/* ============================================================
   TEMPLATE STYLES.CSS
   Sunny Web Shops — starter template for new client builds
   Mobile-first, ADA compliant, no frameworks
 
   FONT LOADING — paste in every HTML <head>:
   <link rel="preconnect" href="https://fonts.googleapis.com">
   <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
   <link href="https://fonts.googleapis.com/css2?family=Lora:ital,wght@0,400;0,500;1,400;1,500&family=DM+Sans:ital,wght@0,400;0,500;0,700;1,400&family=Roboto+Mono:wght@400;500&display=swap" rel="stylesheet">
 
   ARCHITECTURE
   Typographic styling lives inside named section contexts —
   not on bare HTML elements globally. The .content block owns
   all prose styling (headings, paragraphs, lists, links, tables,
   code, figures, hr, mark, abbr, etc.) via cascade from the
   container class. New contexts (.content--blog, .content--landing,
   etc.) inherit from .content and override only what changes.
 
   Chrome elements (header, footer, nav, buttons, forms) are
   styled entirely through their own BEM selectors and do not
   depend on global element rules.
 
   Only the absolute minimum lives globally: the reset, body/html
   base, inline semantics (strong/em/small), a link baseline for
   chrome, and the focus ring.
 
   TABLE OF CONTENTS
   1.  Project Variables      ← Edit these per project
   2.  System Variables       ← Do not edit
   3.  Reset & Base           ← Minimal — chrome-level only
   4.  Chrome: Navigation
   5.  Chrome: Footer
   6.  Chrome: Buttons
   7.  Chrome: Forms
   8.  Chrome: Accessibility & Utilities
   9.  Layout & Grid          ← .container · .section--flush · three-col
   10. Spacing Utilities
   11. Color Utilities
   12. Animation
   13. Print
   14. Content Block          ← All prose typography lives here
   15. Content Block Variants ← .content--card + stub for new ones
   16. Cards                  ← Grid layouts for card components
   17. Hero Image Components  ← .img-hero · .hero-text
   18. Slideshow              ← .slideshow · arrows · play/pause
   19. Lightbox               ← .lightbox-grid · .lightbox overlay
   20. Cookie Notice          ← .cookie-notice · fixed bottom bar
   21. FAQ Accordion          ← .faq · .faq__item · .faq__answer
   22. Full-Bleed Image       ← .img-bleed · no container · natural height
   23. CTA Block              ← .cta · centered · cascades h2 + p
   24. Testimonials           ← .testimonials · .testimonial-item · 3-up
   25. Contact Form Section   ← .contact-form · column-constrained
   26. Cards: 1-up            ← .cards__grid--one · column-constrained
   27. TOC Overrides          ← .toc · .toc__nav · .toc__link · .toc__top
   28. Homepage Hero          ← .hero-home · full-bleed, no header
   29. Archive Card Grid      ← .archive-grid/.archive-card · Events & Slideshows landing pages
 
   THE THREE HTML FILES
   long-form.html      — the master page template. Every client
                          page starts here: header, footer, hero,
                          .section.content > .container > .three-col
                          > .three-col__mid > .main-content (prose).
                          .three-col__left/.content-left and
                          .three-col__right/.content-right are empty
                          by default.
 
   long-form-toc.html  — same as long-form.html, with a <aside class
                          ="toc"> populated in .content-left. Use
                          only when a page needs an in-page table of
                          contents in the left column; otherwise use
                          long-form.html.
 
   components.html     — library of additional section-level
                          components (§1–§14 above), each a
                          self-contained <section>. To build a page,
                          pull whichever sections a wireframe calls
                          for and insert them as siblings of
                          .section.content in long-form.html (or
                          long-form-toc.html).
   ============================================================ */
 
 
/* ============================================================
   1. PROJECT VARIABLES
   These are the only values that change from project to project.
   ============================================================ */
 
:root {
 
  /* Accent — saturated blue for links, CTAs, active states.
     Distinct from --color-heading so links are unmistakably links. */
  --accent:               #1A6FAD;
  --accent-hover:         #135585;
 
  /* Fonts                                                     */
  --font-heading:         'Lora', Georgia, serif;
  --font-body:            'DM Sans', Helvetica Neue, Arial, sans-serif;
 
  /* Backgrounds & Surfaces                                    */
  --color-page:           #FFFFFF;
  --color-surface:        #F7F5F2;
  --color-surface-mid:    #EDEBE8;
 
  /* Borders & Dividers                                        */
  --color-border:         #EDEBE8;
  --color-border-strong:  #C8C4BF;
 
  /* Text
     --color-heading is desaturated blue-gray — headings only.
     Distinct from --accent so headings and links never confuse. */
  --color-heading:        #39566C;
  --color-text:           #1A1A1A;
  --color-text-secondary: #4A4A4A;
  --color-text-muted:     #8A8A8A;
}
 
 
/* ============================================================
   2. SYSTEM VARIABLES
   Architecture. Do not edit between projects.
   ============================================================ */
 
:root {
 
  /* --- Spacing Scale (base unit: 8px) ---                   */
  --space-half:   4px;
  --space-1:      8px;
  --space-2:     16px;
  --space-3:     24px;
  --space-4:     32px;
  --space-5:     48px;
  --space-6:     64px;
  --space-7:     96px;
  --space-8:    128px;
 
  /* --- Typography Scale ---
     Reference values used by chrome BEM components.
     Prose typography uses --ct- variables (Section 14).      */
  --text-caption:      14px;
  --text-body:         16px;
  --text-lead:         18px;
  --text-h3:           22px;
  --text-h2:           28px;
  --text-h1-desktop:   56px;
 
  /* --- Line Heights ---                                      */
  --leading-body:      1.6;
  --leading-heading:   1.1;
  --leading-caption:   1.4;
 
  /* --- Font Weights ---                                      */
  --weight-regular:    400;
  --weight-medium:     500;
  --weight-bold:       700;
 
  /* --- Column & Layout ---                                   */
  --column-width:      720px;
  --column-width-wide: 800px;
  --container-max:    1200px;
  --container-wide:   1440px;
  --page-margin:       16px;
  --page-margin-tablet:32px;
 
  /* --- Breakpoints (reference only)
     Mobile:  0–859px  |  Desktop: 860–1199px
     Wide:    1200–1439px  |  Full: 1440px+               */
 
  /* --- Border Radius ---                                     */
  --radius-sm:    3px;
  --radius:       6px;
  --radius-lg:   12px;
 
  /* --- Transitions ---                                       */
  --transition-fast:   150ms ease;
  --transition-base:   250ms ease;
  --transition-slow:   400ms ease;
 
  /* --- Functional Colors ---                                 */
  --color-error:       #C0392B;
  --color-success:     #27AE60;
  --color-warning:     #E67E22;
  --color-focus:       #0066CC;
 
  /* --- Shadows ---                                           */
  --shadow-sm:   0 1px 3px rgba(0,0,0,0.08);
  --shadow:      0 2px 8px rgba(0,0,0,0.10);
  --shadow-lg:   0 8px 24px rgba(0,0,0,0.12);
  --shadow-xl:   0 16px 48px rgba(0,0,0,0.14);
}
 
 
/* ============================================================
   3. RESET & BASE
   Minimal. Only what chrome elements genuinely need globally.
   Typographic element styling (h1–h3, p, ul, ol, blockquote,
   figure, a full treatment, hr, code, table, mark, abbr) is
   NOT set here — it lives inside named section contexts (§14+).
   ============================================================ */
 
*,
*::before,
*::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}
 
html {
  font-size: 100%;
  -webkit-text-size-adjust: 100%;
}
 
body {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  /* overflow-x lives here, not on html — overflow-x: hidden on the
     root element forces html to become its own scroll container,
     which reliably breaks position: sticky on descendants. That's why
     .site-header wasn't staying stuck on real, tall event pages,
     especially once the mega-panel's own scroll-lock also touched
     body's overflow. Same horizontal-overflow protection, applied one
     level down, doesn't have that side effect. */
  overflow-x: hidden;
  background-color: var(--color-page);
  color: var(--color-text);
  font-family: var(--font-body);
  font-size: var(--text-body);
  font-weight: var(--weight-regular);
  line-height: var(--leading-body);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}
 
main { flex: 1; }
 
/* Images never overflow containers                           */
img, video, iframe {
  display: block;
  max-width: 100%;
  height: auto;
}
 
/* Inline semantics — needed everywhere                       */
strong { font-weight: var(--weight-bold); }
em     { font-style: italic; }
small  { font-size: var(--text-caption); }
 
/* Link baseline — chrome links (footer, nav) need this.
   Full typographic treatment is defined per content context. */
a {
  color: var(--accent);
  text-decoration: underline;
  transition: color var(--transition-fast);
}
 
a:hover   { color: var(--accent-hover); }
a:visited { color: var(--accent); }
 
/* Nav links — always strip underline regardless of context   */
nav a { text-decoration: none; }
 
/* HR baseline — just enough for chrome use (form dividers).
   Spacing, color, and margin are set inside content contexts. */
hr {
  border: none;
  border-top: 1px solid var(--color-border);
}
 
/* Focus ring — global, applies to all interactive elements   */
:focus-visible {
  outline: 2px solid var(--color-focus);
  outline-offset: 3px;
}
 
a:focus-visible { border-radius: var(--radius-sm); }
 
 
/* ============================================================
   4. CHROME: NAVIGATION
   ============================================================ */
 
.site-header {
  position: sticky;
  top: 0;
  z-index: 100;
  background-color: var(--color-surface);
  border-bottom: 1px solid var(--color-border);
  box-shadow: var(--shadow-sm);
  transition:
    border-color var(--transition-base),
    box-shadow var(--transition-base);
}

/* Opt-out for pages where sticky nav costs more viewport than it's
   worth — currently the slideshow-hero pages, where there's very
   little to scroll and the header would otherwise permanently eat
   into the space available to the image. */
.site-header--static {
  position: static;
}
 
.site-header.is-scrolled {
  border-color: var(--color-border-strong);
  box-shadow: var(--shadow);
}
 
.site-header__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--space-half) var(--page-margin);
  max-width: var(--container-max);
  margin: 0 auto;
  min-height: 48px;
}
 
@media (min-width: 860px) {
  .site-header__inner {
    padding-left: var(--page-margin-tablet);
    padding-right: var(--page-margin-tablet);
  }
}
 
.site-logo {
  display: block;
  text-decoration: none;
  flex-shrink: 0;
}
 
.site-logo img {
  height: 40px;
  width: auto;
}
 
.site-nav {
  display: none;
  list-style: none;
  padding: 0;
  margin: 0;
}
 
@media (min-width: 860px) {
  .site-header__inner > nav {
    align-self: stretch;
  }

  .site-nav {
    height: 100%;
    display: flex;
    align-items: center;
    gap: var(--space-1);
  }
 
  .site-nav a {
    font-size: var(--text-caption);
    font-weight: var(--weight-medium);
    color: var(--color-text);
    letter-spacing: 0.04em;
    text-transform: uppercase;
    padding: 4px 6px;
    border-radius: var(--radius-sm);
    border-bottom: 2px solid transparent;
    transition:
      color var(--transition-fast),
      background-color var(--transition-fast),
      border-color var(--transition-fast);
  }
 
  .site-nav a:hover {
    color: var(--accent);
    background-color: var(--color-surface);
  }
 
  .site-nav a.is-active,
  .site-nav a[aria-current="page"] {
    color: var(--color-text);
    border-bottom: 1px solid var(--color-border-strong);
  }
 
  .site-nav a.nav-special {
    color: var(--accent);
    font-weight: var(--weight-bold);
    border: 1.5px solid var(--accent);
    border-radius: var(--radius-sm);
    padding: 3px 8px;
  }
 
  .site-nav a.nav-special:hover {
    background-color: var(--accent);
    color: #fff;
  }
 
  .site-nav a.nav-special.is-active,
  .site-nav a.nav-special[aria-current="page"] {
    background-color: var(--accent);
    color: #fff;
    border-color: var(--accent);
  }
}
 
.hamburger {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 5px;
  width: 32px;
  height: 32px;
  background: none;
  border: none;
  cursor: pointer;
  padding: 4px;
  border-radius: var(--radius-sm);
}
 
.hamburger:focus-visible {
  outline: 2px solid var(--color-focus);
  outline-offset: 3px;
}
 
.hamburger__line {
  display: block;
  width: 100%;
  height: 2px;
  background-color: var(--color-text);
  transition:
    transform var(--transition-base),
    opacity var(--transition-base);
  transform-origin: center;
}
 
.hamburger.is-open .hamburger__line:nth-child(1) { transform: translateY(7px) rotate(45deg); }
.hamburger.is-open .hamburger__line:nth-child(2) { opacity: 0; }
.hamburger.is-open .hamburger__line:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }
 
@media (min-width: 860px) { .hamburger { display: none; } }
 
.mobile-nav {
  display: none;
  position: fixed;
  inset: 0;
  top: 64px;
  z-index: 200;
  background-color: var(--color-surface);
  padding: var(--space-4) var(--page-margin);
  overflow-y: auto;
}
 
.mobile-nav.is-open {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}
 
.mobile-nav > a {
  font-family: var(--font-heading);
  font-size: var(--text-h3);
  color: var(--color-text);
  padding-bottom: var(--space-3);
  border-bottom: 1px solid var(--color-border);
  display: block;
}
 
.mobile-nav > a:hover       { color: var(--accent); }
.mobile-nav > a.nav-special { color: var(--accent); font-weight: var(--weight-medium); }
 
@media (min-width: 860px) { .mobile-nav { display: none !important; } }
 
 
/* ============================================================
   5. CHROME: FOOTER
   ============================================================ */
 
.site-footer {
  background-color: var(--color-surface);
  border-top: 1px solid var(--color-border);
  box-shadow: 0 -3px 10px rgba(0,0,0,0.05);
  padding: var(--space-4) var(--page-margin) var(--space-3);
  margin-top: auto;
  text-align: center;
}

.site-footer__top { margin-bottom: var(--space-1); }

.site-footer__brand {
  font-family: var(--font-heading);
  font-size: var(--text-h3);
  font-weight: var(--weight-regular);
  color: var(--color-heading);
  letter-spacing: -0.015em;
  margin-bottom: 4px;
}

.site-footer__tagline {
  font-size: var(--text-body);
  color: var(--color-text-secondary);
  margin: 0;
}

.site-footer__legal {
  margin-top: var(--space-2);
  padding-top: var(--space-1);
  border-top: 1px solid var(--color-border);
  font-size: var(--text-caption);
  color: var(--color-text-muted);
  /* Single centered line now — text-align: center already comes
     from .site-footer, so no flex/stacking machinery needed here
     anymore now that the nav row is gone. */
}

.site-footer__legal a {
  color: var(--color-text-muted);
  text-decoration: underline;
  text-decoration-color: var(--color-border-strong);
  text-underline-offset: 2px;
  transition: color var(--transition-fast), text-decoration-color var(--transition-fast);
}

.site-footer__legal a:hover {
  color: var(--accent);
  text-decoration-color: var(--accent);
}
 
 
/* ============================================================
   6. CHROME: BUTTONS
   ============================================================ */
 
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-1);
  font-family: var(--font-body);
  font-size: var(--text-body);
  font-weight: var(--weight-medium);
  line-height: 1;
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius);
  border: 2px solid transparent;
  cursor: pointer;
  text-decoration: none;
  transition:
    background-color var(--transition-fast),
    border-color var(--transition-fast),
    color var(--transition-fast),
    box-shadow var(--transition-fast);
}
 
.btn:focus-visible {
  outline: 2px solid var(--color-focus);
  outline-offset: 3px;
}
 
.btn:visited            { opacity: 1; }
.btn--primary:visited   { color: #FFFFFF; }
.btn--secondary:visited { color: var(--accent); }
.btn--ghost:visited     { color: var(--accent); }
.btn--text:visited      { color: var(--accent); }
 
.btn--primary {
  background-color: var(--accent);
  border-color: var(--accent);
  color: #FFFFFF;
}
 
.btn--primary:hover {
  background-color: #FFFFFF;
  border-color: var(--accent);
  color: var(--accent);
  box-shadow: 0 4px 12px rgba(26, 111, 173, 0.25);
}
 
.btn--secondary {
  background-color: transparent;
  border-color: var(--accent);
  color: var(--accent);
}
 
.btn--secondary:hover {
  background-color: var(--accent);
  color: #FFFFFF;
}
 
.btn--ghost {
  background-color: transparent;
  border-color: var(--accent);
  color: var(--accent);
}
 
.btn--ghost:hover {
  background-color: var(--accent);
  color: #FFFFFF;
}
 
.btn--text {
  background-color: transparent;
  border-color: transparent;
  color: var(--accent);
  padding-left: 0;
  padding-right: 0;
}
 
.btn--text:hover {
  color: var(--accent-hover);
  text-decoration: underline;
}
 
.btn--sm {
  font-size: var(--text-caption);
  padding: var(--space-1) var(--space-2);
}
 
.btn-group {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  justify-content: center;
  margin-top: var(--space-3);
}
 
 
/* ============================================================
   7. CHROME: FORMS (Formspree-ready)
   Required structure:
   <form class="form"
     action="https://formspree.io/f/YOUR_FORM_ID" method="POST">
     <input type="hidden" name="_subject" value="...">
   </form>
   ============================================================ */
 
.form { width: 100%; }
 
.form-group {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  margin-bottom: var(--space-3);
}
 
label {
  font-size: var(--text-caption);
  font-weight: var(--weight-medium);
  color: var(--color-text);
  letter-spacing: 0.03em;
}
 
label .required {
  color: var(--color-error);
  margin-left: 2px;
}
 
input[type="text"],
input[type="email"],
input[type="tel"],
input[type="search"],
input[type="url"],
input[type="password"],
textarea,
select {
  width: 100%;
  font-family: var(--font-body);
  font-size: var(--text-body);
  color: var(--color-text);
  background-color: var(--color-page);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-sm);
  padding: var(--space-2);
  transition:
    border-color var(--transition-fast),
    box-shadow var(--transition-fast);
  appearance: none;
  -webkit-appearance: none;
}
 
input[type="text"],
input[type="email"],
input[type="tel"],
textarea { max-width: 480px; }
 
input::placeholder,
textarea::placeholder { color: var(--color-text-muted); }
 
input:focus,
textarea:focus,
select:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(26, 111, 173, 0.15);
}
 
textarea {
  min-height: 140px;
  resize: vertical;
  line-height: var(--leading-body);
}
 
.form-group--error input,
.form-group--error textarea,
.form-group--error select { border-color: var(--color-error); }
 
.form-group--error input:focus,
.form-group--error textarea:focus,
.form-group--error select:focus {
  box-shadow: 0 0 0 3px rgba(192, 57, 43, 0.15);
}
 
.form-error-message {
  font-size: var(--text-caption);
  color: var(--color-error);
}
 
.form-success {
  background-color: #EBF7F0;
  border: 1px solid var(--color-success);
  border-radius: var(--radius);
  padding: var(--space-3);
  color: #1A5C35;
  font-size: var(--text-body);
  display: none;
}
 
.form-success.is-visible { display: block; }
 
input:disabled,
textarea:disabled,
select:disabled {
  background-color: var(--color-surface);
  color: var(--color-text-muted);
  cursor: not-allowed;
  opacity: 0.7;
}
 
 
/* ============================================================
   8. CHROME: ACCESSIBILITY & UTILITIES
   ============================================================ */
 
.skip-link {
  position: absolute;
  top: -100%;
  left: var(--space-2);
  background-color: var(--accent);
  color: #FFFFFF;
  padding: var(--space-1) var(--space-2);
  border-radius: var(--radius-sm);
  font-weight: var(--weight-medium);
  text-decoration: none;
  z-index: 600;
  transition: top var(--transition-fast);
}
 
.skip-link:focus { top: var(--space-2); }
 
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}
 
.back-to-top {
  position: fixed;
  bottom: var(--space-4);
  right: var(--space-4);
  z-index: 50;
  width: 40px;
  height: 40px;
  background-color: var(--accent);
  color: #FFFFFF;
  border: none;
  border-radius: 50%;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 18px;
  opacity: 0;
  pointer-events: none;
  transition:
    opacity var(--transition-base),
    box-shadow var(--transition-fast);
  box-shadow: var(--shadow);
}
 
.back-to-top.is-visible    { opacity: 1; pointer-events: auto; }
.back-to-top:hover         { box-shadow: var(--shadow-lg); }
.back-to-top:focus-visible {
  outline: 2px solid var(--color-focus);
  outline-offset: 3px;
}
 
/* Text utilities — globally available, applied by hand      */
.text-lead {
  font-size: var(--text-lead);
  line-height: 1.5;
  color: var(--color-text-secondary);
  margin-bottom: var(--space-4);
  max-width: 66ch;
}
 
.text-caption {
  font-size: var(--text-caption);
  line-height: var(--leading-caption);
  color: var(--color-text-secondary);
}
 
.text-byline {
  font-size: var(--text-caption);
  color: var(--color-text-muted);
  font-weight: var(--weight-medium);
  letter-spacing: 0.04em;
  text-transform: uppercase;
}
 
@media (forced-colors: active) {
  .btn             { border: 2px solid ButtonText; }
  .hamburger__line { background-color: ButtonText; }
}
 
 
/* ============================================================
   9. LAYOUT & GRID
   Three-tier width hierarchy:
   1. Column-constrained — 720px centered (.content, 2-card)
   2. Container-width    — full container with margins (most blocks)
   3. Full-bleed         — edge to edge (.section--flush)
   ============================================================ */
 
.container {
  width: 100%;
  max-width: var(--container-max);
  margin-left: auto;
  margin-right: auto;
  padding-left: var(--page-margin);
  padding-right: var(--page-margin);
}
 
@media (min-width: 860px) {
  .container {
    padding-left: var(--page-margin-tablet);
    padding-right: var(--page-margin-tablet);
  }
}
 
@media (min-width: 1200px) {
  .container {
    padding-left: 0;
    padding-right: 0;
  }
}
 
.section {
  padding-bottom: var(--space-3);
}
 
@media (min-width: 1200px) {
  .section {
    padding-bottom: var(--space-4);
  }
}
 
.section--surface { background-color: var(--color-surface); }
 
/* .section--flush — zero padding and margin. Use in place of
   .section for components that must sit edge-to-edge or
   directly against an adjacent image (full-width hero,
   full-bleed image). Replaces ad-hoc inline styles. */
.section--flush { padding: 0; margin: 0; }
 
.grid-2 {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-4);
}
 
@media (min-width: 860px) { .grid-2 { grid-template-columns: repeat(2, 1fr); } }
 
.grid-3 {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-4);
}
 
@media (min-width: 860px) { .grid-3 { grid-template-columns: repeat(3, 1fr); } }
 
.clearfix::after {
  content: '';
  display: table;
  clear: both;
}
 
/* ── Three-column layout ─────────────────────────────────────
   Purely structural. No padding, no color, no typography.
   Content blocks (.content-left, .main-content, .content-right)
   sit inside each column and own all their own styling.
 
   Mobile stacking order: source order — left, mid, right.
   A TOC in .content-left appears above the main content with
   no order override needed.
   Desktop 1200px+: left | mid | right as a flex row.
 
   Usage:
   <section class="section content">
     <div class="container">
       <div class="three-col">
         <div class="three-col__left">
           <div class="content-left"> ... </div>
         </div>
         <div class="three-col__mid">
           <div class="main-content"> ... </div>
         </div>
         <div class="three-col__right">
           <div class="content-right"> ... </div>
         </div>
       </div>
     </div>
   </section>
   ──────────────────────────────────────────────────────────── */
 
.three-col {
  display: flex;
  flex-direction: column;
}
 
.three-col__left,
.three-col__mid,
.three-col__right {
  width: 100%;
}
 
/* Mobile stacking: source order is left, mid, right — TOC
   appears above the main content with no override needed.   */
 
@media (min-width: 1200px) {
  .three-col {
    flex-direction: row;
    align-items: flex-start;
  }
 
  .three-col__left  { width: 240px; flex-shrink: 0; order: 0; }
  .three-col__mid   { width: 720px; flex-shrink: 0; order: 0; }
  .three-col__right { width: 240px; flex-shrink: 0; order: 0; }
}
 
/* ── Content blocks ──────────────────────────────────────────
   Generic structural wrappers inside each column.
   Width 100% by default — fill the column.
   All styling (padding, background, typography) is applied
   by the specific block or modifier class placed inside.    */
 
.content-left,
.main-content,
.content-right {
  width: 100%;
  max-width: var(--column-width);
  margin-left: auto;
  margin-right: auto;
}
 
/* Sticky sidebar — applied to the column element itself.
   padding-top aligns the TOC with the H1 in the mid column. */
@media (min-width: 1200px) {
  .three-col__left {
    position: sticky;
    top: calc(64px + var(--space-4));
    max-height: calc(100vh - 96px);
    overflow-y: auto;
    overflow-x: hidden;
    scrollbar-width: none;
    align-self: flex-start;
    padding-top: calc(var(--space-5) + var(--space-4));
  }
 
  .three-col__left::-webkit-scrollbar { display: none; }
}
 
/* All TOC rules use .content .toc descendant selectors to beat
   the .content a cascade (border-bottom, padding-bottom, hover
   background). Everything is zeroed and flush left.           */
 
.toc {
  width: 100%;
  font-size: 14px;
  font-family: var(--font-body);
  padding: 0;
  margin: 0;
}
 
.toc__label {
  font-size: 11px;
  font-weight: var(--weight-medium);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--color-text-secondary);
  display: flex;
  align-items: baseline;
  gap: var(--space-2);
  padding: 0;
  margin: 0 0 var(--space-1) 0;
}
 
.toc__toggle {
  background: none;
  border: none;
  cursor: pointer;
  font-size: 11px;
  font-weight: var(--weight-regular);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--accent);
  text-decoration: none;
  padding: 0;
  font-family: var(--font-body);
}
 
@media (min-width: 1200px) { .toc__toggle { display: none; } }
 
/* Beat .content ul padding-left and list-style with high specificity */
.toc__nav {
  list-style: none;
  padding: 0;
  margin: 0;
  display: none;
}
.toc__nav.is-open { display: block; }
@media (min-width: 1200px) { .toc__nav { display: block; } }
 
.content .toc__item,
.toc__item { margin: 0; padding: 0; list-style: none; }
 
/* Beat .content a border-bottom, padding-bottom, and hover bg  */
.toc__link,
.content .toc__link,
.content a.toc__link {
  display: block;
  padding: 3px 0 3px 0;
  color: var(--accent);
  text-decoration: none;
  border-bottom: none !important;
  line-height: 1.3;
  transition: color var(--transition-fast);
}
 
.toc__link:hover,
.content .toc__link:hover,
.content a.toc__link:hover {
  color: var(--accent-hover);
  background-color: transparent;
  border-bottom: none !important;
}
 
.toc__link.is-active,
.content .toc__link.is-active {
  color: var(--accent);
  font-weight: var(--weight-medium);
}
 
.toc__top,
.content a.toc__top {
  display: block;
  font-size: 11px;
  color: var(--color-text-muted);
  text-decoration: none;
  border-bottom: none !important;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}
 
.toc__top:hover,
.content a.toc__top:hover {
  color: var(--accent);
  background-color: transparent;
}
 
/* Context links sidebar                                      */
.context-links {
  background-color: var(--color-surface);
  border-left: 3px solid var(--accent);
  padding: var(--space-2);
  margin: 0 0 var(--space-3) 0;
}
 
.context-links__label {
  font-size: var(--text-caption);
  font-weight: var(--weight-medium);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--color-text-muted);
  margin-bottom: var(--space-1);
}
 
.context-links__list {
  list-style: circle;
  padding-left: var(--space-2);
  margin: 0;
  line-height: 1.3;
}
 
.context-links__list li { margin-bottom: var(--space-half); }
 
.context-links__list a {
  font-size: var(--text-caption);
  color: var(--accent);
  text-decoration: underline;
  text-underline-offset: 2px;
  text-decoration-thickness: 1px;
  padding: 2px 4px;
  margin-left: -4px;
  border-radius: var(--radius-sm);
  transition: color var(--transition-fast), background-color var(--transition-fast);
}
 
.context-links__list a:hover {
  color: #FFFFFF;
  background-color: var(--accent);
  text-decoration: none;
}
 
@media (min-width: 1200px) {
  .context-links {
    float: right;
    width: 200px;
    margin-left: var(--space-4);
    margin-right: calc((100vw - var(--column-width)) / -4);
    margin-bottom: var(--space-3);
    margin-top: var(--space-half);
  }
}
 
.section-body::after { content: ''; display: table; clear: both; }
 
 
/* ============================================================
   10. SPACING UTILITIES
   ============================================================ */
 
.mt-1 { margin-top:    var(--space-1); }  .mb-1 { margin-bottom: var(--space-1); }
.mt-2 { margin-top:    var(--space-2); }  .mb-2 { margin-bottom: var(--space-2); }
.mt-3 { margin-top:    var(--space-3); }  .mb-3 { margin-bottom: var(--space-3); }
.mt-4 { margin-top:    var(--space-4); }  .mb-4 { margin-bottom: var(--space-4); }
.mt-5 { margin-top:    var(--space-5); }  .mb-5 { margin-bottom: var(--space-5); }
.mt-6 { margin-top:    var(--space-6); }  .mb-6 { margin-bottom: var(--space-6); }
 
.pt-1 { padding-top:    var(--space-1); }  .pb-1 { padding-bottom: var(--space-1); }
.pt-2 { padding-top:    var(--space-2); }  .pb-2 { padding-bottom: var(--space-2); }
.pt-3 { padding-top:    var(--space-3); }  .pb-3 { padding-bottom: var(--space-3); }
.pt-4 { padding-top:    var(--space-4); }  .pb-4 { padding-bottom: var(--space-4); }
.pt-5 { padding-top:    var(--space-5); }  .pb-5 { padding-bottom: var(--space-5); }
.pt-6 { padding-top:    var(--space-6); }  .pb-6 { padding-bottom: var(--space-6); }
 
 
/* ============================================================
   11. COLOR UTILITIES
   ============================================================ */
 
.bg-page    { background-color: var(--color-page); }
.bg-surface { background-color: var(--color-surface); }
.bg-mid     { background-color: var(--color-surface-mid); }
.bg-accent  { background-color: var(--accent); color: #FFFFFF; }
 
.text-primary   { color: var(--color-text); }
.text-secondary { color: var(--color-text-secondary); }
.text-muted     { color: var(--color-text-muted); }
.text-accent    { color: var(--accent); }
 
 
/* ============================================================
   12. ANIMATION
   ============================================================ */
 
@keyframes slideDown {
  from { opacity: 0; transform: translateY(-16px); }
  to   { opacity: 1; transform: translateY(0); }
}
 
.toast { animation: slideDown var(--transition-base) ease both; }
 
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}
 
 
/* ============================================================
   13. PRINT
   ============================================================ */
 
@media print {
 
  *, *::before, *::after {
    background: transparent !important;
    color: #000000 !important;
    box-shadow: none !important;
  }
 
  body { font-size: 12pt; line-height: 1.5; display: block; }
  main { flex: none; }
 
  .site-header, .site-footer, .hamburger, .mobile-nav,
  .btn, .skip-link, .back-to-top { display: none !important; }
 
  h1, h2, h3        { page-break-after: avoid; }
  p, blockquote, li { orphans: 3; widows: 3; }
  img               { max-width: 100% !important; page-break-inside: avoid; }
 
  a[href]::after {
    content: " (" attr(href) ")";
    font-size: 10pt;
    color: #555 !important;
  }
 
  a[href^="#"]::after,
  a[href^="javascript"]::after { content: ""; }
 
  .main-content,
  .content-left,
  .content-right { max-width: 100%; }
 
  .content .figure--left,
  .content .figure--right { float: none; width: 100%; margin: 0 0 24px 0; }
}
 
 
/* ============================================================
   14. CONTENT BLOCK
   The primary typographic environment for page content.
   All element styling cascades from .content — no classes
   on child elements. This is the canonical definition of every
   typographic element: headings, paragraphs, lists, links,
   blockquotes, figures, hr, tables, code, mark, and abbr.
   Variants (Section 15) inherit everything and override
   only what changes.
 
   Usage:
     <section class="section content">
       <div class="container">
         <div class="three-col">
           <div class="three-col__mid">
             <div class="main-content">
               [pure HTML — no classes on children]
             </div>
           </div>
         </div>
       </div>
     </section>
 
   The .content class lives on the outer <section> — the
   typographic cascade below (.content h1, .content p, etc.)
   reaches .main-content's children regardless of the
   .three-col / .three-col__mid wrappers in between, since
   descendant selectors match at any depth. .main-content
   itself owns the 720px constraint (see §9).
 
   Image patterns (class on <figure>, not on <img>):
     Full width:  no class
     Centered:    class="figure--centered"  → 70% of column
     Float left:  class="figure--left"      → 45%, text wraps right
     Float right: class="figure--right"     → 45%, text wraps left
   ============================================================ */
 
/* --- Custom properties ---
   Every typographic decision is a --ct- variable.
   Variants override only the tokens that differ.            */
.content {
  --ct-font-heading:        'Lora', Georgia, serif;
  --ct-font-body:           'DM Sans', Helvetica Neue, Arial, sans-serif;
  --ct-font-mono:           'Roboto Mono', 'Courier New', monospace;
  --ct-weight-heading:      400;
  --ct-weight-body:         400;
  --ct-size-body:           16px;
  --ct-size-lead:           18px;
  --ct-size-h1:             clamp(32px, 7vw, 56px);
  --ct-size-h2:             28px;
  --ct-size-h3:             22px;
  --ct-size-caption:        14px;
  --ct-leading-body:        1.6;
  --ct-leading-heading:     1.1;
  --ct-tracking-h1:         -0.01em;
  --ct-tracking-h2:         0;
  --ct-tracking-h3:         0;
  --ct-color-heading:       var(--color-heading);
  --ct-color-text:          var(--color-text);
  --ct-color-text-sec:      var(--color-text-secondary);
  --ct-color-text-muted:    var(--color-text-muted);
  --ct-color-link:          var(--accent);
  --ct-color-link-hover:    var(--accent-hover);
  --ct-color-link-visited:  var(--accent);
  --ct-color-link-bg-hover: rgba(26, 111, 173, 0.08);  /* muted tint on hover */
  --ct-color-rule:          #AAAAAA;  /* darker than border-strong for visible HR */
  --ct-color-code-bg:       var(--color-surface);
  --ct-color-code-text:     var(--color-heading);
  --ct-color-mark:          #FFF3CD;
  --ct-ul-style:            disc;
  --ct-ol-style:            decimal;
  --ct-list-indent:         32px;
  --ct-list-item-gap:       6px;
  --ct-blockquote-border:   var(--accent);
  --ct-table-border:        var(--color-border-strong);
  --ct-table-stripe:        var(--color-surface);
}
 
/* --- Headings --- */
 
.content h1,
.content h2,
.content h3 {
  font-family:       var(--ct-font-heading);
  font-weight:       var(--ct-weight-heading);
  line-height:       var(--ct-leading-heading);
  color:             var(--ct-color-heading);
  scroll-margin-top: 88px;
}
 
.content h1 {
  font-size:      var(--ct-size-h1);
  letter-spacing: var(--ct-tracking-h1);
  margin-bottom:  24px;
}
 
.content h2 {
  font-size:      var(--ct-size-h2);
  letter-spacing: var(--ct-tracking-h2);
  margin-top:     32px;
  margin-bottom:  24px;
}
 
.content h3 {
  font-size:         var(--ct-size-h3);
  letter-spacing:    var(--ct-tracking-h3);
  margin-top:        32px;
  margin-bottom:     16px;
  scroll-margin-top: 76px;
}
 
/* If a heading is the first element in .main-content, it
   shouldn't carry the top margin meant to separate it from
   preceding prose. (h1 needs no reset — it has no margin-top
   to begin with.) */
.content .main-content > h2:first-child,
.content .main-content > h3:first-child { margin-top: 0; }
 
/* --- Paragraphs --- */
.content p {
  font-family:   var(--ct-font-body);
  font-weight:   var(--ct-weight-body);
  font-size:     var(--ct-size-body);
  line-height:   var(--ct-leading-body);
  color:         var(--ct-color-text);
  margin-bottom: 24px;
  max-width:     68ch;
}
 
/* --- Links ---
   Dotted border-bottom instead of text-decoration underline.
   Hover adds a very muted background tint — no color change.
   The global baseline (§3) handles chrome only.             */
.content a {
  color:           var(--ct-color-link);
  text-decoration: none;
  border-bottom:   1px dotted var(--ct-color-link);
  padding-bottom:  1px;
  transition:
    background-color var(--transition-fast),
    color var(--transition-fast);
}
 
.content a:hover {
  color:            var(--ct-color-link);
  background-color: var(--ct-color-link-bg-hover);
  border-radius:    2px;
}
 
.content a:visited { color: var(--ct-color-link-visited); }
 
/* --- Lists --- */
.content ul,
.content ol {
  font-family:   var(--ct-font-body);
  font-size:     var(--ct-size-body);
  line-height:   var(--ct-leading-body);
  color:         var(--ct-color-text);
  padding-left:  var(--ct-list-indent);
  margin-bottom: 24px;
}
 
.content ul { list-style-type: var(--ct-ul-style); }
.content ol { list-style-type: var(--ct-ol-style); }
.content li { margin-bottom: var(--ct-list-item-gap); }
 
/* --- Blockquote --- */
.content blockquote {
  font-family:  var(--ct-font-heading);
  font-size:    var(--ct-size-h3);
  font-weight:  var(--ct-weight-heading);
  font-style:   italic;
  line-height:  1.4;
  color:        var(--ct-color-text-sec);
  border-left:  3px solid var(--ct-blockquote-border);
  padding-left: 24px;
  margin:       24px 0;
}
 
@media (min-width: 860px) { .content blockquote { margin-left: 32px; } }
 
/* --- HR ---
   Full treatment — spacing, color, weight.
   The global baseline (§3) provides only a bare border-top.  */
.content hr {
  border: none;
  border-top: 1px solid var(--ct-color-rule);
  margin: 40px 0;
}
 
/* --- Inline code & pre blocks --- */
.content code {
  font-family:      var(--ct-font-mono);
  font-size:        0.875em;
  font-weight:      500;
  background-color: var(--ct-color-code-bg);
  color:            var(--ct-color-code-text);
  padding:          2px 5px;
  border-radius:    var(--radius-sm);
}
 
.content pre {
  font-family:      var(--ct-font-mono);
  font-size:        0.875em;
  font-weight:      500;
  background-color: var(--ct-color-code-bg);
  color:            var(--ct-color-code-text);
  padding:          var(--space-3);
  border-radius:    var(--radius);
  overflow-x:       auto;
  margin-bottom:    24px;
  line-height:      1.6;
}
 
.content pre code { background: none; padding: 0; font-size: inherit; font-weight: inherit; }
 
/* --- Tables --- */
.content table {
  width: 100%;
  border-collapse: collapse;
  font-family:     var(--ct-font-body);
  font-size:       var(--ct-size-body);
  margin-bottom:   24px;
}
 
.content th {
  font-family:     var(--ct-font-body);
  font-weight:     var(--weight-medium);
  font-size:       var(--ct-size-caption);
  text-transform:  uppercase;
  letter-spacing:  0.05em;
  color:           var(--ct-color-text-muted);
  padding:         8px 12px;
  border-bottom:   2px solid var(--ct-table-border);
  text-align:      left;
}
 
.content td {
  padding:         10px 12px;
  border-bottom:   1px solid var(--ct-color-rule);
  color:           var(--ct-color-text);
  vertical-align:  top;
}
 
.content tr:nth-child(even) td { background-color: var(--ct-table-stripe); }
 
/* --- Mark (highlight) --- */
.content mark {
  background-color: var(--ct-color-mark);
  color:            inherit;
  padding:          1px 3px;
  border-radius:    2px;
}
 
/* --- Abbr --- */
.content abbr[title] {
  text-decoration:       underline dotted;
  text-underline-offset: 2px;
  cursor:                help;
}
 
/* --- Figures & images --- */
.content img {
  width:   100%;
  height:  auto;
  display: block;
}
 
.content figure { margin: 32px 0; }
 
.content figcaption {
  font-family: var(--ct-font-body);
  font-size:   var(--ct-size-caption);
  font-style:  italic;
  line-height: 1.4;
  color:       var(--ct-color-text-sec);
  margin-top:  8px;
}
 
/* Centered — 70% of column width                            */
.content .figure--centered {
  width:        70%;
  margin-left:  auto;
  margin-right: auto;
}
 
/* Float patterns — full width mobile, float desktop.
   Text wraps naturally under the float.
   margin-bottom gives clearance when text wraps beneath.     */
.content .figure--left,
.content .figure--right { width: 100%; margin-bottom: 16px; }
 
@media (min-width: 860px) {
  .content .figure--left {
    float: left;
    width: 45%;
    margin-top: 0;
    margin-right: 24px;
    margin-bottom: 8px;
    margin-left: 0;
  }
 
  .content .figure--right {
    float: right;
    width: 45%;
    margin-top: 0;
    margin-left: 24px;
    margin-bottom: 8px;
    margin-right: 0;
  }
}
 
/* Clear floats after the prose column so the next section
   starts clean below any active float.                      */
.content .main-content::after {
  content: '';
  display: table;
  clear: both;
}
 
/* --- Desktop scaling --- */
@media (min-width: 860px) {
  .content p,
  .content ul,
  .content ol { font-size: var(--ct-size-lead); }
}
 
 
/* ============================================================
   15. CONTENT BLOCK VARIANTS
 
   Each variant inherits everything from .content and overrides
   only what changes — via --ct- tokens where possible, or
   direct element rules where layout changes are needed.
 
   ── BUILT-IN: .content--card ────────────────────────────────
   Inverts the base font pairing: DM Sans headings, Lora body.
   Used inside .card shells. Image sits flush at top.
   Padding applied per element (h3, p) rather than container.
 
   ── STUB ────────────────────────────────────────────────────
   Copy the commented block below, rename [name], delete
   lines you don't need. Override only what differs.
   ============================================================ */
 
/* --- .content--card --- */
 
.content--card {
  --ct-font-heading:    'DM Sans', Helvetica Neue, Arial, sans-serif;
  --ct-font-body:       'Lora', Georgia, serif;
  --ct-weight-heading:  500;
  --ct-size-body:       15px;
  --ct-size-h3:         17px;
  --ct-leading-body:    1.6;
  --ct-leading-heading: 1.2;
  --ct-tracking-h3:     0;
  --ct-list-indent:     18px;
  --ct-list-item-gap:   4px;
  padding:              0;
}
 
.content--card h3 {
  font-family:    var(--ct-font-heading);
  font-weight:    var(--ct-weight-heading);
  font-size:      var(--ct-size-h3);
  letter-spacing: var(--ct-tracking-h3);
  line-height:    var(--ct-leading-heading);
  color:          var(--ct-color-heading);
  margin:         16px 24px 8px 24px;
}
 
.content--card p {
  font-family:  var(--ct-font-body);
  font-size:    var(--ct-size-body);
  line-height:  1.5;
  color:        var(--ct-color-text);
  margin:       0 24px 16px 24px;
  overflow:     hidden;
}
 
.content--card p:last-child { margin-bottom: 12px; }
 
.content--card ul,
.content--card ol {
  font-family:  var(--ct-font-body);
  font-size:    var(--ct-size-body);
  line-height:  var(--ct-leading-body);
  color:        var(--ct-color-text);
  padding-left: var(--ct-list-indent);
  margin:       0 24px 16px 24px;
}
 
.content--card ul { list-style-type: var(--ct-ul-style, disc); }
.content--card ol { list-style-type: var(--ct-ol-style, decimal); }
.content--card li { margin-bottom: var(--ct-list-item-gap); }
 
.content--card figure { margin: 0; }
 
.content--card img { width: 100%; height: auto; display: block; }
 
@media (min-width: 860px) {
  .content--card img { height: 220px; object-fit: cover; }
}
 
.content--card figcaption {
  font-family:   var(--ct-font-heading);
  font-size:     12px;
  font-style:    italic;
  line-height:   1.4;
  color:         var(--ct-color-text-sec);
  padding:       8px 0 0 24px;
  margin-bottom: 0;
}
 
 
/* ============================================================
   NEW CONTEXT VARIANT STUB
   Copy this entire commented block, rename [name], fill in
   only what differs from the .content base. Delete any lines
   you don't need — the base values remain in effect.
 
   Common use cases:
     .content--blog      larger body, looser leading, drop caps
     .content--landing   centered headings, no p max-width
     .content--sidebar   smaller type, tighter spacing
     .content--minimal   no blockquote border, plain hr, no stripe
 
   .content--[name] {
 
     -- Custom properties: override only what changes --------
     --ct-font-heading:        ;
     --ct-font-body:           ;
     --ct-font-mono:           ;
     --ct-weight-heading:      ;
     --ct-weight-body:         ;
     --ct-size-body:           ;
     --ct-size-lead:           ;
     --ct-size-h1:             ;
     --ct-size-h2:             ;
     --ct-size-h3:             ;
     --ct-size-caption:        ;
     --ct-leading-body:        ;
     --ct-leading-heading:     ;
     --ct-tracking-h1:         ;
     --ct-tracking-h2:         ;
     --ct-tracking-h3:         ;
     --ct-color-heading:       ;
     --ct-color-text:          ;
     --ct-color-text-sec:      ;
     --ct-color-text-muted:    ;
     --ct-color-link:          ;
     --ct-color-link-hover:    ;
     --ct-color-link-visited:  ;
     --ct-color-link-bg-hover: ;   hover background tint
     --ct-color-rule:          ;
     --ct-color-code-bg:       ;
     --ct-color-code-text:     ;
     --ct-color-mark:          ;
     --ct-ul-style:            ;
     --ct-ol-style:            ;
     --ct-list-indent:         ;
     --ct-list-item-gap:       ;
     --ct-blockquote-border:   ;
     --ct-table-border:        ;
     --ct-table-stripe:        ;
   }
 
   -- Element overrides: only when layout changes -------
   .content--[name] h1         { text-align: center; }
   .content--[name] p          { max-width: none; }
   .content--[name] a          { text-decoration: none; border-bottom: 1px solid; }
   .content--[name] blockquote { border-left: none; padding-left: 0; }
   .content--[name] hr         { margin: 24px 0; }
   .content--[name] figure     { margin: 48px 0; }
   .content--[name] figcaption { text-align: center; }
   .content--[name] pre        { border-radius: 0; }
   .content--[name] table      { font-size: var(--ct-size-caption); }
   ============================================================ */
 
 
/* ============================================================
   16. CARDS
   Three grid layouts sharing the same .card shell and
   .content--card typographic variant.
 
   Width hierarchy:
     .cards__grid        column-constrained — self-constrains to 720px
     .cards__grid--three container width
     .cards__grid--four  container width
 
   All grids are full-width of their wrapper. .cards__grid
   self-constrains to 720px; --three and --four fill the container.
 
   Usage:
     <section class="section">
       <div class="container">
         <div class="cards__grid">
           <div class="card">
             <div class="content--card">
               [pure HTML — no classes on children]
             </div>
           </div>
         </div>
       </div>
     </section>
   ============================================================ */
 
.cards__grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 24px;
  max-width: var(--column-width);
  margin-left: auto;
  margin-right: auto;
}
 
@media (min-width: 860px) {
  .cards__grid { grid-template-columns: repeat(2, 1fr); }
}
 
.cards__grid--three {
  display: grid;
  grid-template-columns: 1fr;
  gap: 24px;
}
 
@media (min-width: 860px) {
  .cards__grid--three {
    grid-template-columns: repeat(3, 1fr);
  }
}
 
.cards__grid--four {
  display: grid;
  grid-template-columns: 1fr;
  gap: 24px;
}
 
@media (min-width: 600px) {
  .cards__grid--four { grid-template-columns: repeat(2, 1fr); }
}
 
@media (min-width: 860px) {
  .cards__grid--four {
    grid-template-columns: repeat(4, 1fr);
    gap: 20px;
  }
}
 
/* Card shell — flex column so .card__link pins to bottom     */
.card {
  background-color: #F7F7F7;
  border:           1px solid #CCCCCC;
  border-radius:    0;
  box-shadow:       0 2px 8px rgba(0,0,0,0.07);
  overflow:         hidden;
  display:          flex;
  flex-direction:   column;
}
 
/* .content--card fills available space, pushing link down   */
.card .content--card {
  flex: 1;
}
 
/* Pinned card link — always at the bottom of the card.
   Lives outside .content--card in the HTML — it's chrome,
   not prose. One empty-line gap above (via p:last-child
   margin of 24px), 8px below to card edge.
   Usage: <a href="#" class="card__link">Learn more</a>       */
.card__link {
  display:         block;
  font-family:     var(--font-body);
  font-size:       var(--text-caption);
  font-weight:     var(--weight-medium);
  color:           var(--accent);
  text-decoration: none;
  padding:         0 24px 8px 24px;
  transition:      color var(--transition-fast);
}
 
.card__link:hover   { color: var(--accent-hover); text-decoration: underline; text-underline-offset: 3px; }
.card__link:visited { color: var(--accent); }
 
.card__link:focus-visible {
  outline:        2px solid var(--color-focus);
  outline-offset: 2px;
  border-radius:  var(--radius-sm);
}
 
.card__link::after { content: " →"; }
 
 
/* ============================================================
   17. HERO IMAGE COMPONENTS
   img-hero    — full-width image, max-height 80vh
   hero-text   — image with text block overlaid top-left
 
   Usage (.hero-text):
   <section class="hero-text">
     <img src="..." alt="...">
     <div class="hero-text__block">
       <h2>...</h2>
       <p class="text-lead">...</p>
     </div>
   </section>
 
   NOTE — heading level: the long-form page template owns the
   page's single <h1> in .main-content. The hero overlay heading
   is an <h2>, even when it reads visually as the page title.
 
   NOTE — per-project styling: .hero-text__block's background
   color and position (top/left, max-width) are placeholders.
   Surface tint and placement are design decisions made per
   project once colors and layout are settled.
   ============================================================ */
 
.img-hero {
  width:         100%;
  max-height:    80vh;
  object-fit:    cover;
  display:       block;
  margin-bottom: var(--space-5);
}
 
.hero-text {
  position: relative;
  width:    100%;
}
 
.hero-text img {
  width:      100%;
  display:    block;
  object-fit: cover;
}
 
.hero-text__block {
  position:         absolute;
  top:              var(--space-4);
  left:             0;
  max-width:        560px;
  background-color: rgba(255, 245, 224, 0.82);
  padding:          var(--space-3) var(--space-5);
}
 
.hero-text__block h2 {
  font-family:    var(--font-heading);
  font-weight:    var(--weight-regular);
  font-size:      clamp(1.8rem, 5vw, 3rem);
  line-height:    1.1;
  color:          var(--color-heading);
  margin-bottom:  12px;
}
 
.hero-text__block p {
  font-family: var(--font-body);
  font-size:   var(--text-lead);
  line-height: 1.4;
  color:       var(--color-text-secondary);
  margin:      0;
  max-width:   44ch;
}
 
@media (max-width: 599px) {
  .hero-text__block {
    position:  relative;
    top:       auto;
    left:      auto;
    max-width: 100%;
    padding:   var(--space-3) var(--page-margin);
  }
}
 
 
/* ============================================================
   18. SLIDESHOW
   Arrows + a single centered play/pause button. One slide visible
   at a time. Images fill the slideshow width at a fixed aspect
   ratio. Sits inside .container at container width, or go
   full-bleed by wrapping in a section with no container.

   Deliberately no dot indicators — with categories running up to
   48 photos, dots never worked as real navigation (nobody counts
   to the 23rd dot), and on mobile a single row of them physically
   couldn't fit without pushing other controls off-screen. Removed
   entirely rather than just hidden: emulates the plain, minimal
   feel of a physical digital picture frame — just the photo, with
   the least interface necessary (prev, next, pause) rather than
   the most.
 
   Usage:
   <section class="section--flush slideshow-hero">
     <div class="container">
       <div class="slideshow-hero__inner">
         <div class="slideshow-hero__header">
           <h1>Category Title</h1>
           <p>One-line intro.</p>
         </div>
         <div class="slideshow" aria-label="..." aria-roledescription="carousel">
           <button class="slideshow__btn slideshow__btn--prev" aria-label="Previous slide">&lt;</button>
           <div class="slideshow__track" id="ss-track">
             <!-- single <img> swapped by JS, opacity crossfade -->
           </div>
           <button class="slideshow__btn slideshow__btn--next" aria-label="Next slide">&gt;</button>
           <div class="slideshow__footer">
             <button class="slideshow__playpause" aria-label="Pause slideshow"><svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><rect x="6" y="4" width="3" height="16"></rect><rect x="15" y="4" width="3" height="16"></rect></svg></button>
           </div>
         </div>
         <p class="event-gallery__hint">Instructions text.</p>
       </div>
     </div>
   </section>

   .slideshow-hero is the full-bleed dark backdrop (#2b2b2b, not a
   --color-* token — a deliberate one-off theater treatment) that
   contains the title/intro, the slideshow, AND the hint text — the
   whole component is one continuous dark field, no seams. Everything
   inside shares one width via .slideshow-hero__inner (max-width:
   1200px, centered) so the header text, the slide, and the hint all
   share the same left/right edges instead of each picking their own.

   .slideshow is a 3-column CSS grid — left gutter (1fr), center
   column (auto, sized to the photo), right gutter (1fr) — the same
   "section > left/center/right column" pattern used elsewhere in
   this stylesheet, applied here with the center column's width
   determined by the photo's own 3:2-ratio box rather than a fixed
   prose measure. The arrows are direct grid children living in the
   gutter columns, vertically centered for free via align-items on
   the grid (no absolute positioning, no JS measurement, no negative
   offsets — that approach proved fragile and was replaced with this).
   They're pushed toward the photo edge via justify-self, with a
   fixed 30px padding as the gap — same rule on mobile and desktop,
   no breakpoint-specific values needed. Mobile gets its own override
   (see the @media block on .slideshow and .slideshow__track img)
   since there the photo should fill available WIDTH rather than
   being height-bound. The footer bar spans all three columns on its
   own row (grid-column: 1 / -1) and holds just the play/pause button,
   centered.
   ============================================================ */
 
.slideshow-hero {
  background: #2b2b2b;
  padding: var(--space-3) 0 var(--space-5);
}

.slideshow-hero__inner {
  max-width:   1200px;
  margin-right: auto;
}

.slideshow-hero__header {
  display:     flex;
  align-items: baseline;
  flex-wrap:   wrap;
  gap:         var(--space-3);
  margin-bottom: var(--space-2);
}

.slideshow-hero__header h1 {
  font-family: var(--font-heading);
  font-weight: var(--weight-regular);
  font-size:   var(--text-h2);
  color:       var(--color-page);
  line-height: var(--leading-heading);
  margin:      0;
}

.slideshow-hero__header p {
  font-family: var(--font-body);
  font-size:   var(--text-body);
  color:       rgba(255,255,255,0.75);
  margin:      0;
  max-width:   60ch;
}

.slideshow-hero .event-gallery__hint {
  color: rgba(255,255,255,0.55);
  margin-top: var(--space-half);
  margin-bottom: 0;
}

.slideshow {
  display:               grid;
  grid-template-columns: 1fr auto 1fr;
  align-items:           center;
  user-select:           none;
}
 
.slideshow__track {
  grid-column: 2;
  position:    relative;
}
 
.slideshow__track img {
  display:      block;
  width:        auto;
  height:       auto;
  max-width:    100%;
  max-height:   85dvh;
  aspect-ratio: 3 / 2;
  object-fit:   cover;
  opacity:      0;
  transition:   opacity 400ms ease;
}
 
.slideshow__track img.is-active { opacity: 1; }
 
.slideshow__caption {
  font-family:  var(--font-body);
  font-size:    var(--text-caption);
  font-style:   italic;
  line-height:  var(--leading-caption);
  color:        var(--color-text-secondary);
  padding:      var(--space-1) var(--space-2);
  background:   var(--color-surface);
  margin:       0;
}
 
/* Prev / next arrow buttons — plain grid children of .slideshow,
   living in the left/right gutter columns (see .slideshow above).
   Vertical centering comes free from the grid's align-items:center;
   horizontal placement is just "pushed toward the photo, then a
   fixed padding" — no absolute positioning, no measurement, no
   negative offsets. This is what actually keeps it reliable across
   both mobile (narrow gutters) and desktop (wide gutters). */
.slideshow__btn {
  background:       none;
  border:           none;
  box-shadow:       none;
  color:            rgba(255,255,255,0.6);
  text-shadow:      0 1px 5px rgba(0,0,0,0.7);
  font-family:      var(--font-body);
  font-size:        32px;
  font-weight:      var(--weight-medium);
  line-height:      1;
  cursor:           pointer;
  display:          flex;
  align-items:      center;
  justify-content:  center;
  transition:       color var(--transition-fast);
}

.slideshow__btn--prev {
  grid-column:   1;
  justify-self:  end;
  padding-right: 30px;
}

.slideshow__btn--next {
  grid-column:  3;
  justify-self: start;
  padding-left: 30px;
}

.slideshow__btn:hover {
  color: var(--color-page);
}

.slideshow__btn:focus-visible {
  outline:        2px solid var(--color-focus);
  outline-offset: 2px;
}

.slideshow__btn:disabled {
  opacity:        0.3;
  cursor:         default;
}

/* Mobile-only override — desktop rules above are untouched.
   On mobile there's no "fill the viewport height" goal (that's a
   desktop-chrome concern); instead the photo should fill all
   available WIDTH between two arrow-sized gutters. Reverses which
   columns get 1fr, and lets the photo's width (not JS-computed
   height) drive its size.

   The !important on max-height is a deliberate, narrow exception to
   the project's no-!important rule — it's the only way to override
   the inline max-height that JS sets on the image (for the desktop
   viewport-fit behavior) without touching the JS itself. */
@media (max-width: 859px) {
  .slideshow {
    grid-template-columns: auto 1fr auto;
  }

  .slideshow__track img {
    width:      100%;
    max-width:  100%;
    height:     auto;
    max-height: none !important;
  }

  .slideshow__btn--prev { padding-right: 0; }
  .slideshow__btn--next { padding-left:  0; }

  .slideshow-hero__header p {
    font-size: var(--text-caption);
  }
}
 
.slideshow__footer {
  grid-column: 1 / -1;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-3);
  padding: var(--space-2) var(--space-3);
}

.slideshow__playpause {
  background:  none;
  border:      none;
  box-shadow:  none;
  color:       rgba(255,255,255,0.6);
  font-size:   16px;
  line-height: 1;
  padding:     4px 8px;
  cursor:      pointer;
  display:     flex;
  align-items: center;
  justify-content: center;
  transition:  color var(--transition-fast);
  flex-shrink: 0;
}

.slideshow__playpause:hover {
  color: var(--color-page);
}

.slideshow__playpause:focus-visible {
  outline: 2px solid var(--color-focus);
  outline-offset: 2px;
}
 
/* ============================================================
   19. LIGHTBOX
   Fixed-column thumbnail grid (4-up desktop, 2-up mobile).
   Last row is centered via flexbox. Clicking a thumbnail opens
   a full-screen overlay with prev/next navigation.
 
   Usage:
   <div class="lightbox-grid" role="list">
     <button class="lightbox-thumb" role="listitem"
       aria-label="Open image 1 of 5"
       data-src="full-size.jpg" data-caption="Caption text">
       <img src="thumb.jpg" alt="...">
     </button>
     ...
   </div>
 
   The overlay is injected by JavaScript — no markup needed.
   ============================================================ */
 
.lightbox-grid {
  display:         flex;
  flex-wrap:       wrap;
  justify-content: center;
  gap:             var(--space-2);
  padding:         0;
}
 
.lightbox-thumb {
  /* 2-up mobile */
  flex:            0 0 calc(50% - var(--space-1));
  padding:         0;
  border:          none;
  background:      none;
  cursor:          zoom-in;
  overflow:        hidden;
  display:         block;
}
 
@media (min-width: 600px) {
  .lightbox-thumb {
    /* 3-up at mid — graceful step on the way to 5-up */
    flex: 0 0 calc(33.333% - (var(--space-2) * 2 / 3));
  }
}
 
@media (min-width: 860px) {
  .lightbox-thumb {
    /* 5-up desktop: subtract 4 gaps from 20% */
    flex: 0 0 calc(20% - (var(--space-2) * 4 / 5));
  }
}
 
.lightbox-thumb img {
  width:        100%;
  aspect-ratio: 4 / 3;
  object-fit:   cover;
  display:      block;
  transition:   opacity var(--transition-fast), transform var(--transition-base);
}
 
.lightbox-thumb:hover img  { opacity: 0.85; transform: scale(1.03); }
 
.lightbox-thumb:focus-visible {
  outline:        2px solid var(--color-focus);
  outline-offset: 2px;
}
 
/* Overlay — injected by JS. Hidden by default, faded/scaled in
   on .is-open. */
.lightbox-overlay {
  display:          flex;
  visibility:       hidden;
  opacity:          0;
  position:         fixed;
  inset:            0;
  z-index:          500;
  background-color: rgba(0,0,0,0.92);
  flex-direction:   column;
  align-items:      center;
  justify-content:  center;
  padding:          var(--space-5) var(--space-4) var(--space-3);
  transition:       opacity var(--transition-base), visibility var(--transition-base);
}
 
.lightbox-overlay.is-open {
  visibility: visible;
  opacity:    1;
}
 
.lightbox-overlay__img {
  max-width:    100%;
  max-height:   75vh;
  object-fit:   contain;
  display:      block;
  transform:    scale(0.96);
  transition:   opacity var(--transition-fast), transform var(--transition-base);
}
 
.lightbox-overlay.is-open .lightbox-overlay__img {
  transform: scale(1);
}
 
/* Added while swapping the image source during prev/next
   navigation — fades the current image out before the new
   src is set, then fades back in. Toggled by JS. */
.lightbox-overlay__img.is-changing { opacity: 0; }
 
.lightbox-overlay__caption {
  font-family:  var(--font-body);
  font-size:    var(--text-caption);
  font-style:   italic;
  color:        rgba(255,255,255,0.65);
  margin-top:   var(--space-2);
  text-align:   center;
  max-width:    56ch;
}
 
.lightbox-overlay__counter {
  font-family:  var(--font-body);
  font-size:    11px;
  font-weight:  var(--weight-medium);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color:        rgba(255,255,255,0.4);
  margin-top:   var(--space-1);
}
 
.lightbox-overlay__close {
  position:    absolute;
  top:         var(--space-2);
  right:       var(--space-2);
  background:  none;
  border:      none;
  color:       rgba(255,255,255,0.7);
  font-size:   28px;
  line-height: 1;
  cursor:      pointer;
  padding:     var(--space-1);
  border-radius: var(--radius-sm);
  transition:  color var(--transition-fast);
}
 
.lightbox-overlay__close:hover { color: #fff; }
 
.lightbox-overlay__close:focus-visible {
  outline:        2px solid var(--color-focus);
  outline-offset: 3px;
}
 
.lightbox-overlay__btn {
  position:         absolute;
  top:              50%;
  transform:        translateY(-50%);
  background-color: rgba(255,255,255,0.12);
  border:           1px solid rgba(255,255,255,0.2);
  color:            #fff;
  width:            44px;
  height:           44px;
  border-radius:    50%;
  cursor:           pointer;
  font-size:        20px;
  display:          flex;
  align-items:      center;
  justify-content:  center;
  transition:       background-color var(--transition-fast);
}
 
.lightbox-overlay__btn:hover { background-color: rgba(255,255,255,0.22); }
 
.lightbox-overlay__btn:focus-visible {
  outline:        2px solid var(--color-focus);
  outline-offset: 3px;
}
 
.lightbox-overlay__btn--prev { left:  var(--space-2); }
.lightbox-overlay__btn--next { right: var(--space-2); }
 
 
/* ============================================================
   20. COOKIE NOTICE
   Fixed bottom bar. Dismisses on button click; stores
   preference in localStorage. Appears only until dismissed.
 
   Usage:
   <div class="cookie-notice" id="cookie-notice" role="region"
     aria-label="Cookie notice" aria-live="polite">
     <p class="cookie-notice__text">We use cookies to...</p>
     <div class="cookie-notice__actions">
       <button class="cookie-notice__btn cookie-notice__btn--accept"
         id="cookie-accept">Accept</button>
       <button class="cookie-notice__btn cookie-notice__btn--decline"
         id="cookie-decline">Decline</button>
     </div>
   </div>
   ============================================================ */
 
.cookie-notice {
  position:         fixed;
  bottom:           0;
  left:             0;
  right:            0;
  z-index:          400;
  background-color: var(--color-heading);
  color:            #fff;
  padding:          var(--space-2) var(--page-margin);
  display:          flex;
  flex-wrap:        wrap;
  align-items:      center;
  justify-content:  center;
  gap:              var(--space-2);
  box-shadow:       0 -2px 12px rgba(0,0,0,0.18);
  transform:        translateY(0);
  transition:       transform var(--transition-base);
}
 
.cookie-notice.is-hidden {
  transform:     translateY(110%);
  pointer-events: none;
}
 
@media (min-width: 860px) {
  .cookie-notice {
    padding-left:  var(--page-margin-tablet);
    padding-right: var(--page-margin-tablet);
    gap:           var(--space-3);
  }
}
 
.cookie-notice__text {
  font-family:  var(--font-body);
  font-size:    var(--text-caption);
  line-height:  1.5;
  color:        rgba(255,255,255,0.9);
  margin:       0;
  max-width:    64ch;
}
 
.cookie-notice__text a {
  color:           rgba(255,255,255,0.9);
  text-decoration: underline;
  text-underline-offset: 2px;
}
 
.cookie-notice__text a:hover { color: #fff; }
 
.cookie-notice__actions {
  display: flex;
  gap:     var(--space-1);
  flex-shrink: 0;
}
 
.cookie-notice__btn {
  font-family:   var(--font-body);
  font-size:     var(--text-caption);
  font-weight:   var(--weight-medium);
  padding:       6px 16px;
  border-radius: var(--radius-sm);
  cursor:        pointer;
  border:        1px solid transparent;
  transition:
    background-color var(--transition-fast),
    color var(--transition-fast),
    border-color var(--transition-fast);
}
 
.cookie-notice__btn--accept {
  background-color: #fff;
  color:            var(--color-heading);
  border-color:     #fff;
}
 
.cookie-notice__btn--accept:hover {
  background-color: rgba(255,255,255,0.88);
}
 
.cookie-notice__btn--decline {
  background-color: transparent;
  color:            rgba(255,255,255,0.8);
  border-color:     rgba(255,255,255,0.35);
}
 
.cookie-notice__btn--decline:hover {
  color:            #fff;
  border-color:     rgba(255,255,255,0.7);
}
 
.cookie-notice__btn:focus-visible {
  outline:        2px solid var(--color-focus);
  outline-offset: 3px;
}
 
 
/* ============================================================
   21. FAQ ACCORDION
   Single-open: opening one item closes others (handled in JS).
   Works inside or outside .content. No icon font needed —
   the toggle indicator is a CSS-drawn chevron.
 
   Usage:
   <div class="faq" role="list">
     <div class="faq__item" role="listitem">
       <button class="faq__question" aria-expanded="false"
         aria-controls="faq-1" id="faq-btn-1">
         Question text
       </button>
       <div class="faq__answer" id="faq-1" role="region"
         aria-labelledby="faq-btn-1" hidden>
         <div class="faq__answer-inner">
           <p>Answer text.</p>
         </div>
       </div>
     </div>
   </div>
   ============================================================ */
 
.faq {
  border-top:   1px solid var(--color-border-strong);
  max-width:    var(--column-width);
  margin-left:  auto;
  margin-right: auto;
}
 
.faq__item {
  border-bottom: 1px solid var(--color-border-strong);
}
 
.faq__question {
  width:           100%;
  display:         flex;
  justify-content: space-between;
  align-items:     center;
  gap:             var(--space-3);
  padding:         var(--space-3) 0;
  background:      none;
  border:          none;
  cursor:          pointer;
  text-align:      left;
  font-family:     var(--font-body);
  font-size:       var(--text-body);
  font-weight:     var(--weight-medium);
  color:           var(--color-heading);
  line-height:     1.4;
  transition:      color var(--transition-fast);
}
 
@media (min-width: 860px) {
  .faq__question { font-size: var(--text-lead); }
}
 
.faq__question:hover { color: var(--accent); }
 
.faq__question:focus-visible {
  outline:        2px solid var(--color-focus);
  outline-offset: 3px;
  border-radius:  var(--radius-sm);
}
 
/* Chevron — pure CSS, rotates on open */
.faq__question::after {
  content:      '';
  display:      block;
  flex-shrink:  0;
  width:        10px;
  height:       10px;
  border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  transform:    rotate(45deg) translateY(-2px);
  transition:   transform var(--transition-base);
}
 
.faq__question[aria-expanded="true"]::after {
  transform: rotate(225deg) translateY(-2px);
}
 
.faq__answer {
  overflow: hidden;
}
 
.faq__answer[hidden] { display: none; }
 
.faq__answer-inner {
  padding-bottom: var(--space-3);
}
 
/* Prose inside FAQ answers cascades from .content when
   .faq lives inside a .content block. When outside, these
   rules provide a reasonable baseline.                    */
.faq__answer-inner p {
  font-family:  var(--font-body);
  font-size:    var(--text-body);
  line-height:  var(--leading-body);
  color:        var(--color-text-secondary);
  margin-bottom: var(--space-2);
  max-width:    68ch;
}
 
.faq__answer-inner p:last-child { margin-bottom: 0; }
 
@media (min-width: 860px) {
  .faq__answer-inner p { font-size: var(--text-lead); }
}
 
 
 
 
/* ============================================================
   22. FULL-BLEED IMAGE
   True edge-to-edge. No container, no margins. Natural height.
   Use landscape images only — portrait images will be very tall.
 
   Usage:
   <section class="section--flush">
     <img class="img-bleed" src="..." alt="...">
   </section>
   ============================================================ */
 
.img-bleed {
  display: block;
  width:   100%;
  height:  auto;
}
 
 
/* ============================================================
   23. CTA BLOCK
   Centered headline, subhead, and button group. Text cascades
   from .cta — no classes on h2 or p.
   Typically sits on .section--surface background.
 
   Usage:
   <section class="section section--surface">
     <div class="container">
       <div class="cta">
         <h2>Headline</h2>
         <p>Subhead text.</p>
         <div class="btn-group">
           <a href="#" class="btn btn--primary">Primary</a>
           <a href="#" class="btn btn--secondary">Secondary</a>
         </div>
       </div>
     </div>
   </section>
   ============================================================ */
 
.cta {
  text-align:  center;
  max-width:   var(--column-width);
  margin-left: auto;
  margin-right: auto;
  padding:     var(--space-5) 0;
}
 
.cta h2 {
  font-family:    var(--font-heading);
  font-weight:    var(--weight-regular);
  font-size:      clamp(28px, 4vw, 40px);
  line-height:    1.15;
  color:          var(--color-heading);
  letter-spacing: -0.01em;
  margin-bottom:  var(--space-2);
}
 
.cta p {
  font-family:   var(--font-body);
  font-size:     var(--text-lead);
  line-height:   1.5;
  color:         var(--color-text-secondary);
  max-width:     52ch;
  margin-left:   auto;
  margin-right:  auto;
  margin-bottom: 0;
}
 
 
/* ============================================================
   24. TESTIMONIALS
   3-up grid of quote + attribution. All type cascades from
   .testimonial-item — no classes on blockquote or p.
   Lora throughout. Attribution italicized.
 
   Usage:
   <section class="section section--surface">
     <div class="container">
       <div class="testimonials">
         <div class="testimonial-item">
           <blockquote>Quote text.</blockquote>
           <p>— Name, Title</p>
         </div>
       </div>
     </div>
   </section>
   ============================================================ */
 
.testimonials {
  display:               grid;
  grid-template-columns: 1fr;
  gap:                   var(--space-4);
  max-width:             var(--container-max);
  margin-left:           auto;
  margin-right:          auto;
}
 
@media (min-width: 860px) {
  .testimonials {
    grid-template-columns: repeat(3, 1fr);
    gap:                   var(--space-4);
  }
}
 
.testimonial-item {
  display:        flex;
  flex-direction: column;
  gap:            var(--space-2);
}
 
.testimonial-item blockquote {
  font-family:  var(--font-heading);
  font-weight:  var(--weight-regular);
  font-style:   normal;
  font-size:    var(--text-lead);
  line-height:  1.55;
  color:        var(--color-text);
  margin:       0;
  padding:      0;
  border:       none;
}
 
.testimonial-item p {
  font-family: var(--font-heading);
  font-weight: var(--weight-regular);
  font-style:  italic;
  font-size:   var(--text-caption);
  line-height: 1.4;
  color:       var(--color-text-muted);
  margin:      0;
}
 
 
/* ============================================================
   25. CONTACT FORM SECTION
   Column-constrained (720px). Heading and intro text cascade
   from .contact-form — no classes on h2 or p.
   Form elements use existing §7 chrome form rules.
 
   Usage:
   <section class="section section--surface">
     <div class="container">
       <div class="contact-form">
         <h2>Get in Touch</h2>
         <p>Intro text.</p>
         [form markup]
       </div>
     </div>
   </section>
   ============================================================ */
 
.contact-form {
  max-width:    var(--column-width);
  margin-left:  auto;
  margin-right: auto;
}
 
.contact-form h2 {
  font-family:    var(--font-heading);
  font-weight:    var(--weight-regular);
  font-size:      var(--text-h2);
  line-height:    var(--leading-heading);
  color:          var(--color-heading);
  letter-spacing: -0.01em;
  margin-bottom:  var(--space-2);
}
 
.contact-form > p {
  font-family:   var(--font-body);
  font-size:     var(--text-lead);
  line-height:   var(--leading-body);
  color:         var(--color-text-secondary);
  margin-bottom: var(--space-4);
  max-width:     56ch;
}
 
 
/* ============================================================
   26. CARDS: 1-UP
   Same .card shell as the grids. Column-constrained (720px).
   Wrap in .container > .cards__grid--one.
 
   Usage:
   <section class="section">
     <div class="container">
       <div class="cards__grid--one">
         <div class="card">
           <div class="content--card">...</div>
           <a href="#" class="card__link">Learn more</a>
         </div>
       </div>
     </div>
   </section>
   ============================================================ */
 
.cards__grid--one {
  max-width:    var(--column-width);
  margin-left:  auto;
  margin-right: auto;
}
 
 
/* ============================================================
   27. TOC OVERRIDES
   These rules live at the end to beat the .content cascade.
   ============================================================ */
 
.toc,
.content .toc {
  font-size: 15px;
  font-family: var(--font-body);
  padding: 0;
  margin: 0;
}
 
/* Force 14px on all TOC children — beats .content desktop scaling */
.toc__nav,
.toc__item,
.content .toc__nav,
.content .toc__item,
.content a.toc__link,
.content a.toc__top {
  font-size: 15px;
}
 
.content .toc__nav,
.toc__nav {
  list-style: none;
  padding: 0;
  margin: 0;
  /* display intentionally not set here — show/hide handled above */
}
 
.content .toc__item,
.toc__item {
  list-style: none;
  margin: 0;
  padding: 0;
}
 
.content a.toc__link,
.toc__link {
  display: block;
  padding: 6px 0;
  color: var(--accent);
  text-decoration: none;
  border-bottom: none;
  line-height: 1.3;
  transition: color var(--transition-fast);
}
 
.content a.toc__link:hover,
.toc__link:hover {
  color: var(--accent-hover);
  background-color: rgba(26, 111, 173, 0.07);
  border-bottom: none;
  border-radius: var(--radius-sm);
  max-width: calc(100% - var(--space-4));
}
 
/* .toc__link.is-active — removed; hover state only */
 
.content a.toc__top,
.toc__top {
  display: block;
  margin-top: var(--space-1);
  font-size: 11px;
  color: var(--color-text-muted);
  text-decoration: none;
  border-bottom: none;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}
 
.content a.toc__top:hover,
.toc__top:hover {
  color: var(--accent);
  background-color: transparent;
}
 
 
/* ============================================================
   28. EVENT GALLERY
   Full-width photo grid + lightbox for event archive pages.
   ============================================================ */

/* ── Page header ──────────────────────────────────────────── */
.event-header {
  padding: var(--space-5) var(--page-margin-tablet) var(--space-4);
  text-align: center;
}

.event-header h1 {
  font-family: var(--font-heading);
  /* Scoped override, not the shared --text-h2 token (also used by
     .slideshow-hero__header h1 and .contact-form h2 — changing the
     token itself would have bumped those too). Verified numerically
     against the longest real event title (58 chars, "Edenton Music &
     Water Festival and Heritage Farm Fest") using the actual Lora font
     metrics: stays on one line at every viewport width from 860px up
     to full desktop; wraps only below 860px, same as the original
     fixed 28px did. A fixed-px jump (this project's usual preference
     over fluid clamp()) can't satisfy that constraint here — the
     43 event titles vary too much in length for one fixed breakpoint
     jump to fit the longest ones without wrapping while still looking
     bigger than 28px on the rest. */
  font-size: clamp(28px, calc(3.4vw - 2px), 44px);
  font-weight: var(--weight-regular);
  color: var(--color-heading);
  line-height: var(--leading-heading);
  margin-bottom: var(--space-1);
}

.event-header p {
  font-family: var(--font-body);
  font-size: var(--text-lead);
  color: var(--color-text-secondary);
  max-width: 680px;
  line-height: var(--leading-body);
  margin: 0 auto;
}

/* ── Hint text ────────────────────────────────────────────── */
.event-gallery__hint {
  text-align: center;
  font-size: var(--text-caption);
  color: var(--color-text-secondary); /* was --color-text-muted (3.45:1 — fails AA at this size); secondary is 8.9:1 */
  margin-bottom: var(--space-3);
  font-style: italic;
}

/* ── Thumbnail grid ───────────────────────────────────────── */
.event-gallery {
  padding: 0 24px var(--space-7);
}

.event-gallery__grid {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 16px;
  max-width: var(--container-wide);
  margin-left: auto;
  margin-right: auto;
}

.event-gallery__item {
  cursor: pointer;
  overflow: hidden;
  background: var(--color-surface-mid);
  aspect-ratio: 3 / 2;
  border: none;
  padding: 0;
  display: block;
  width: calc((100% - 48px) / 4);
}

.event-gallery__item img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* 3-column step — without this, tablet-landscape widths (iPad mini/
   Air/Pro, roughly 1024-1194px) jumped straight from 2 to 4 columns,
   cramming 4 photos into a width only comfortable for 3. Reserves true
   4-up for genuinely wide desktop windows (>=1200px) instead. */
@media (max-width: 1199px) {
  .event-gallery__item { width: calc((100% - 32px) / 3); }
}

@media (max-width: 860px) {
  .event-gallery__item { width: calc((100% - 16px) / 2); }
}

@media (max-width: 480px) {
  .event-gallery {
    padding-left: var(--page-margin);
    padding-right: var(--page-margin);
  }
  .event-gallery__item { width: 100%; }
}

/* ── Lightbox overlay ─────────────────────────────────────── */
.event-lb {
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.92);
  z-index: 1000;
  align-items: center;
  justify-content: center;
}

.event-lb.is-open { display: flex; }

/* The frame is the capped, centered unit holding prev/stage/next as
   true grid children — this is what locks the arrows to the photo's
   own edge (via padding) rather than pinning them to the viewport
   edge, at every width, with no breakpoint jump. .event-lb itself
   stays the full-viewport dark scrim; .event-lb__frame is the
   separate, narrower, capped box centered inside it. */
.event-lb__frame {
  display: grid;
  /* auto columns size exactly to each arrow's own natural width,
     always — they never get squeezed by leftover space. minmax(0, 1fr)
     lets the middle column shrink continuously as the frame narrows,
     with no minimum floor fighting it. */
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  width: 100%;
  max-width: 1500px;
}

.event-lb__stage {
  position: relative;
  /* height, not max-height — the photo's own max-height:100% rule
     below needs a definite parent height to resolve against a
     percentage. max-height alone doesn't count as "definite" per the
     CSS spec, so without this the photo was only ever being
     width-constrained, and could render taller than the viewport
     (worse the less vertical space is available, e.g. heavy browser
     chrome). Harmless for smaller photos — the stage has no visible
     background, so reserving the full 90vh just centers the photo
     within a taller invisible box, same as before. */
  height: 90vh;
  display: flex;
  align-items: center;
  justify-content: center;
  /* Lets this grid child shrink below its content's natural width
     instead of forcing the grid wider — the classic grid/flex
     "won't shrink below content" trap noted elsewhere in this
     project, and easy to hit here since minmax(0, 1fr) alone isn't
     enough if the child itself resists shrinking. */
  min-width: 0;
}

.event-lb__stage img {
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
  opacity: 0;
  transition: opacity 150ms ease;
  user-select: none;
  display: block;
}

.event-lb__stage img.is-active { opacity: 1; }

.event-lb__close {
  position: fixed;
  top: 16px;
  right: 16px;
  background: none;
  border: none;
  color: #fff;
  font-size: 32px;
  cursor: pointer;
  line-height: 1;
  opacity: 0.7;
  transition: opacity 150ms ease;
  z-index: 1010;
}

.event-lb__close:hover { opacity: 1; }

/* Prev/next are now plain grid children of .event-lb__frame — no
   position:fixed, no viewport-relative math, no separate mobile
   strategy. One rule, every width: arrows always locked to the
   photo's edge by a fixed 10px gap. No text-shadow needed — unlike
   the slideshow's arrows, these never sit over a photo, only over
   the flat dark scrim, so a plain flat color is enough contrast on
   its own. */
.event-lb__prev,
.event-lb__next {
  position: static;
  background: transparent;
  border: none;
  color: rgba(255, 255, 255, 0.6);
  font-size: 32px;
  width: 48px;
  height: 80px;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: color 150ms ease;
}

.event-lb__prev:hover,
.event-lb__next:hover { color: #fff; }

.event-lb__prev { grid-column: 1; padding-right: 10px; }
.event-lb__next { grid-column: 3; padding-left: 10px; }

.event-lb__prev:disabled,
.event-lb__next:disabled {
  color: rgba(255, 255, 255, 0.15);
  cursor: default;
  pointer-events: none;
}

/* ── Surprise Me nav pill ─────────────────────────────────── */
.nav-surprise {
  display: inline-block;
  border: 1px solid var(--color-heading);
  color: var(--color-heading);
  border-radius: 20px;
  padding: 4px 14px 5px;
  font-size: 14px;
  text-decoration: none;
  transition: background 150ms ease, color 150ms ease;
  margin-left: var(--space-1);
  line-height: 1.2;
}

.nav-surprise:hover {
  background: var(--color-heading);
  color: #fff;
}

/* ── Mobile lightbox ──────────────────────────────────────── */
/* Only the close button gets a small phone-specific tweak now — the
   arrow/photo/gap relationship above is intentionally the same rule
   at every width, so there's nothing left here for prev/next,
   .event-lb__controls, or .event-lb__stage to override. */
@media (max-width: 480px) {
  .event-lb__close {
    font-size: 22px;
    opacity: 0.5;
  }
}

@media (prefers-reduced-motion: reduce) {
  .event-lb__stage img { transition: none; }
}


/* ============================================================
   28. HOMEPAGE HERO
   Full-viewport single photo, no header, no slideshow — fully
   custom, shares nothing with the long-form/slideshow pattern
   used by every other page. Text overlay only, static per day
   (see index.html's own <script> — day-of-year mod pool size,
   so no photo becomes "Tuesday's photo," per Kip's call).

   --hero-accent is a deliberately different blue from the
   sitewide --accent — darker and more saturated, chosen
   specifically because the nav links sit on a translucent photo
   background rather than --color-page like every other link on
   the site, and needed more weight to stay legible there.
   ============================================================ */

:root {
  --hero-accent: #2f397e;
  --hero-accent-hover: #374394;
}

.hero-home {
  position: relative;
  width: 100%;
  height: 100dvh;
  overflow: hidden;
}

.hero-home__img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* object-position set per-photo by JS — see the rotation array
     in index.html. Different photos need different focal points
     to keep the overlay's corner actually quiet. */
}

.hero-home__overlay {
  position: absolute;
  top: 48px;
  right: 48px;
  max-width: 680px;
  text-align: left;
  padding: 32px;
  background: rgba(247, 245, 242, 0.35);
  /* Approximates --color-surface at 35% opacity — pulled way back
     from an earlier, much heavier version that read as a solid
     card instead of a light touch. */
  backdrop-filter: blur(1px);
  -webkit-backdrop-filter: blur(1px);
  /* Third pass down — 12px, then 4px, then 2px, now 1px. Barely
     perceptible; mostly here to take the hardest edge off busy
     photo detail without visibly softening the photo itself. */
}

.hero-home__brand {
  font-family: 'Lora', Georgia, serif;
  font-size: clamp(30px, 4.5vw, 52px);
  font-weight: 400;
  color: var(--color-heading);
  letter-spacing: -0.01em;
  margin-bottom: 8px;
  /* Not --accent, not a link — a title, not a nav item, even
     though it visually sits above the four that are. */
}

.hero-home__tagline {
  font-family: 'DM Sans', sans-serif;
  font-size: clamp(15px, 1.6vw, 18px);
  font-weight: 400;
  color: var(--color-text-secondary);
  margin: 0 0 28px;
  padding-left: 8px;
  /* Optical alignment, not a real indent — a capital letter at
     52px (the brand) carries more built-in left-bearing in
     absolute pixels than the same letter at 18px does, so the box
     edges line up but the ink doesn't. This nudges the ink back
     into visual alignment. */
}

.hero-home__nav {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 12px;
  padding-left: var(--space-3);
  /* align-items: flex-start stops flexbox's default stretch
     behavior — without it, every link/button silently fills the
     full width of the overlay block (not just its own text),
     which is why the focus ring was drawing a box around empty
     space and why clicking to the right of a short word like
     "About" still triggered it. */
}

.hero-home__nav button,
.hero-home__nav a {
  display: block;
  font-family: 'Lora', Georgia, serif;
  font-size: clamp(20px, 2.6vw, 28px);
  font-weight: 400;
  line-height: 1.1;
  color: var(--hero-accent);
  /* Darker, more saturated than the sitewide --accent — the
     translucent photo background needed more weight than the
     normal link color to stay reliably legible. */
  background: none;
  border: none;
  text-align: left;
  text-decoration: none;
  padding: 0;
  cursor: pointer;
  transition: color var(--transition-fast);
}

.hero-home__nav button:hover,
.hero-home__nav a:hover { color: var(--hero-accent-hover); }
/* Hover lightens rather than darkens — the reverse of the usual
   convention — because the resting state is already the darker
   of the two. Reads as a highlight, not a dimming. */

.hero-home__nav button:focus-visible,
.hero-home__nav a:focus-visible {
  outline: 2px solid var(--color-focus);
  outline-offset: 4px;
}

@media (max-width: 599px) {
  .hero-home__overlay {
    left: 16px;
    right: 16px;
    max-width: none;
    text-align: center;
    background: rgba(247, 245, 242, 0.55);
    /* Bumped up from the desktop 35% — at this width the overlay
       spans nearly the full photo instead of sitting in one
       corner, so it needs to survive a much wider range of what
       might be directly behind it, not just one quiet spot. */
  }
  .hero-home__tagline {
    padding-left: 0;
    font-size: 17px;
    /* Flat value rather than the desktop clamp() — on mobile the
       clamp was already pinned to its 15px floor regardless of
       viewport width, so raising the floor here is the only way
       to actually make it bigger on this breakpoint. */
  }
  .hero-home__nav {
    align-items: center;
    padding-left: 0;
    /* Both the optical-alignment indent and the hierarchy indent
       were built for left-aligned text — centered text doesn't
       need either, and they'd skew a centered block off-center. */
  }
}

/* Short viewports (landscape phones especially) fall outside the
   max-width: 599px query above — e.g. an iPhone in landscape is
   844px wide, well past that cutoff — but has very little vertical
   room. The desktop-style card (48px top offset, full padding, full
   text sizes) was nearly filling the whole height, reading as
   crammed against the bottom rather than actually positioned there.
   Targets height directly since that's the real constraint, not
   width or orientation specifically. Deliberately leaves horizontal
   alignment/position untouched — only the vertical footprint
   shrinks here. */
@media (max-height: 500px) {
  .hero-home__overlay {
    top: 16px;
    padding: 16px 24px;
  }
  .hero-home__brand {
    font-size: clamp(24px, 4vw, 34px);
    margin-bottom: 4px;
  }
  .hero-home__tagline {
    margin-bottom: 12px;
  }
  .hero-home__nav {
    gap: 4px;
  }
  .hero-home__nav button,
  .hero-home__nav a {
    font-size: clamp(16px, 2.2vw, 22px);
  }
}


/* ============================================================
   29. ARCHIVE CARD GRID
   Photo-forward card grid used on the Events and Slideshows
   landing pages (events.html, slideshows.html). A dedicated
   component, not a reuse of .mega-card — that card was purpose-
   built compact and horizontal (108x72px thumb strip) for a
   dropdown overlay with limited vertical room. Now that Events/
   Slideshows are real, primary landing pages instead of a
   dropdown preview, the photo gets real room: a full 3:2 image
   (matching every photo on the site — no cropping ratio was
   invented here), title below, same grid mechanics already
   proven in .cards__grid--four (1 col mobile, 2 col >=600px,
   4 col >=860px).

   Usage:
   <div class="archive-grid">
     <a class="archive-card" href="candlelight-tour-2019.html">
       <img class="archive-card__thumb" src="images-events/standard/20191214-KS2X0658.webp" alt="" loading="lazy">
       <span class="archive-card__title">2019 Candlelight Tour</span>
     </a>
     ...
   </div>

   Title text: year + title as ONE flowing string ("2019
   Candlelight Tour"), no forced <br>. At 42 of 43 events this is
   under 30 characters and sits on one line at normal card widths;
   the one longer title wraps naturally like any other text — no
   per-card exceptions needed. Grid rows stretch to their tallest
   card automatically (default CSS Grid align-items: stretch), so
   a two-line title in one row doesn't misalign its neighbors —
   the extra space lands below the (still top-anchored) title,
   not above it.
   ============================================================ */

.archive-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-3);
}

@media (min-width: 600px) {
  .archive-grid { grid-template-columns: repeat(2, 1fr); }
}

@media (min-width: 860px) {
  .archive-grid {
    grid-template-columns: repeat(3, 1fr);
    gap: var(--space-2);
  }
}

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

.archive-card {
  display: flex;
  flex-direction: column;
  background-color: var(--color-surface);
  border: 1px solid var(--color-border-strong);
  text-decoration: none;
  overflow: hidden;
  transition: border-color var(--transition-fast);
}

.archive-card:hover { border-color: var(--accent); }

.archive-card:focus-visible {
  outline: 2px solid var(--color-focus);
  outline-offset: 2px;
}

.archive-card__thumb {
  display: block;
  width: 100%;
  aspect-ratio: 3 / 2;
  object-fit: cover;
}

.archive-card__title {
  flex: 1;
  padding: var(--space-2);
  font-family: var(--font-heading);
  font-weight: var(--weight-regular);
  font-size: 18px;
  line-height: 1.35;
  color: var(--color-heading);
}


/* ============================================================
   END OF STYLES.CSS
   ============================================================ */
