/* ===================================================================
   Hopkinton Historical Society — Shared Stylesheet
   Design system: warm "archive parchment" palette, accessible defaults
   =================================================================== */

:root {
  /* Palette */
  --color-bg: #faf6ee;
  --color-bg-alt: #ffffff;
  --color-bg-deep: #f1e8d8;
  --color-text: #2a2520;
  --color-text-muted: #5b5248;
  --color-primary: #1f4d3a;       /* deep New England green */
  --color-primary-dark: #143329;
  --color-primary-light: #cfe0d6;
  --color-accent: #ab5836;        /* brick / terracotta */
  --color-accent-dark: #8a4528;
  --color-gold: #b8923f;          /* aged-brass accent */
  --color-border: #e2d6c0;
  --color-focus: #1d6fd6;

  /* Type */
  --font-heading: "Source Serif 4", Georgia, "Times New Roman", serif;
  --font-body: "Source Sans 3", -apple-system, Segoe UI, Helvetica, Arial, sans-serif;

  /* Layout */
  --max-width: 1180px;
  --radius: 6px;
  --shadow: 0 4px 18px rgba(40, 30, 15, 0.08);
  --transition: 0.2s ease;
}

/* ----------------------------- Reset ----------------------------- */
*, *::before, *::after { box-sizing: border-box; }
html { scroll-behavior: smooth; }
body {
  margin: 0;
  font-family: var(--font-body);
  color: var(--color-text);
  background: var(--color-bg);
  line-height: 1.65;
  font-size: 1.0625rem;
}
img { max-width: 100%; display: block; }
h1, h2, h3, h4 { font-family: var(--font-heading); line-height: 1.2; color: var(--color-primary-dark); }
h1 { font-size: clamp(2.1rem, 5vw, 3.4rem); }
h2 { font-size: clamp(1.6rem, 3.2vw, 2.4rem); margin-top: 0; }
h3 { font-size: clamp(1.2rem, 2.4vw, 1.5rem); }
p { margin: 0 0 1rem; }
a { color: var(--color-accent-dark); text-decoration-thickness: 1.5px; }
a:hover { color: var(--color-accent); }
ul { padding-left: 1.25rem; }

/* Visible, high-contrast focus ring for keyboard users (WCAG 2.4.7) */
a:focus-visible, button:focus-visible, input:focus-visible,
select:focus-visible, textarea:focus-visible, [tabindex]:focus-visible {
  outline: 3px solid var(--color-focus);
  outline-offset: 2px;
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  * { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; }
}

/* --------------------------- Skip link ---------------------------- */
.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  background: var(--color-primary-dark);
  color: #fff;
  padding: 0.75rem 1.25rem;
  z-index: 1000;
  border-radius: 0 0 var(--radius) 0;
  font-weight: 600;
}
.skip-link:focus {
  left: 0;
}

/* ------------------------- Top utility bar ------------------------- */
.utility-bar {
  background: var(--color-primary-dark);
  color: #f3ede0;
  font-size: 0.875rem;
}
.utility-bar .wrap {
  max-width: var(--max-width);
  margin: 0 auto;
  padding: 0.4rem 1.5rem;
  display: flex;
  flex-wrap: wrap;
  gap: 1.25rem;
  justify-content: space-between;
  align-items: center;
}
.utility-bar a { color: #f3ede0; }
.utility-bar a:hover { color: var(--color-gold); }
.utility-bar__links { display: flex; gap: 1.25rem; flex-wrap: wrap; }

/* ------------------------------ Header ------------------------------ */
header.site-header {
  background: var(--color-bg-alt);
  border-bottom: 1px solid var(--color-border);
  position: sticky;
  top: 0;
  z-index: 100;
  box-shadow: var(--shadow);
}
.nav-wrap {
  max-width: var(--max-width);
  margin: 0 auto;
  padding: 0.9rem 1.5rem;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
}
.brand {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  text-decoration: none;
  color: var(--color-primary-dark);
}
.brand__mark {
  width: 200px; height: 200px;
  display: flex; align-items: center; justify-content: center;
  flex-shrink: 0;
}
.brand__mark img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  display: block;
}
.brand__text { line-height: 1.15; }
.brand__text strong { display: block; font-family: var(--font-heading); font-size: 1.2rem; }
.brand__text span { display: block; font-size: 0.78rem; letter-spacing: 0.06em; text-transform: uppercase; color: var(--color-text-muted); }

nav.primary-nav { display: flex; align-items: center; gap: 0.25rem; }
nav.primary-nav ul {
  display: flex;
  list-style: none;
  margin: 0;
  padding: 0;
  gap: 0.25rem;
  flex-wrap: wrap;
}
nav.primary-nav a {
  display: inline-block;
  padding: 0.6rem 0.85rem;
  border-radius: var(--radius);
  text-decoration: none;
  font-weight: 600;
  color: var(--color-text);
  font-size: 0.95rem;
  transition: background var(--transition), color var(--transition);
}
nav.primary-nav a:hover { background: var(--color-primary-light); color: var(--color-primary-dark); }
nav.primary-nav a[aria-current="page"] {
  color: var(--color-primary-dark);
  background: var(--color-primary-light);
}
.nav-cta {
  background: var(--color-accent) !important;
  color: #fff !important;
  margin-left: 0.25rem;
}
.nav-cta:hover { background: var(--color-accent-dark) !important; color: #fff !important; }

.nav-toggle {
  display: none;
  background: var(--color-primary);
  color: #fff;
  border: none;
  border-radius: var(--radius);
  padding: 0.55rem 0.8rem;
  font-size: 1rem;
  font-weight: 600;
  cursor: pointer;
}

/* Digital Archive submenu: Historical Records and Virtual Exhibits live here
   instead of as their own top-level nav items, to keep the main bar short.
   Opens on hover or keyboard focus (no JS required for that much); the
   caret button is a click/tap target for touch screens, where hover never
   fires -- see js/main.js. */
.has-submenu { position: relative; display: flex; align-items: center; }
.submenu-toggle {
  background: none;
  border: none;
  padding: 0.4rem 0.4rem;
  color: var(--color-text);
  font-size: 0.65rem;
  line-height: 1;
  cursor: pointer;
  border-radius: var(--radius);
}
.submenu-toggle:hover,
.submenu-toggle:focus-visible { background: var(--color-primary-light); }
/* Specificity note: the existing "nav.primary-nav ul" rule above (which sets
   display: flex on every <ul>, including this nested one) outranks a plain
   ".submenu" selector, so this has to match "nav.primary-nav" too or the
   submenu would stay visible at all times regardless of hover/focus/open. */
nav.primary-nav .submenu {
  list-style: none;
  margin: 0;
  padding: 0.4rem;
  position: absolute;
  top: 100%;
  left: 0;
  min-width: 200px;
  background: #fff;
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  display: none;
  flex-direction: column;
  gap: 0;
  z-index: 200;
}
.has-submenu:hover .submenu,
.has-submenu:focus-within .submenu,
.has-submenu.is-open .submenu { display: block; }
.submenu a {
  display: block;
  padding: 0.55rem 0.7rem;
  border-radius: var(--radius);
  font-size: 0.9rem;
  font-weight: 600;
  color: var(--color-text);
  text-decoration: none;
  white-space: nowrap;
}
.submenu a:hover { background: var(--color-primary-light); color: var(--color-primary-dark); }
.submenu a[aria-current="page"] { color: var(--color-primary-dark); background: var(--color-primary-light); }

@media (max-width: 880px) {
  .nav-toggle { display: inline-block; }
  nav.primary-nav {
    display: none;
    width: 100%;
    order: 3;
  }
  nav.primary-nav.is-open { display: block; }
  nav.primary-nav ul { flex-direction: column; gap: 0; padding: 0.5rem 0; }
  nav.primary-nav a { display: block; padding: 0.75rem 0.5rem; }
  .nav-wrap { flex-wrap: wrap; }

  /* On the collapsed mobile menu there's no hover, and the whole list is
     already tucked behind the hamburger, so just show Historical Records
     and Virtual Exhibits permanently indented under Digital Archive rather
     than requiring a second tap to expand them. */
  .has-submenu { flex-wrap: wrap; }
  .submenu-toggle { display: none; }
  /* Same specificity note as above: has to match "nav.primary-nav .submenu"
     to actually win and show the submenu here. */
  nav.primary-nav .submenu {
    position: static;
    display: block;
    width: 100%;
    margin-top: 0.15rem;
    padding: 0 0 0.35rem 1rem;
    background: transparent;
    border: none;
    box-shadow: none;
  }
  .submenu a { padding: 0.6rem 0.5rem; font-size: 0.9rem; }
}

/* ------------------------------ Hero ------------------------------ */
.hero {
  color: #fff;
  padding: clamp(3rem, 8vw, 6rem) 1.5rem;
  position: relative;
  overflow: hidden;
  min-height: 420px;
  display: flex;
  align-items: center;
  background-image: url('../archive_images/Central%20House%201915.jpg');
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
  background-attachment: fixed;
}
.hero::before {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(160deg, rgba(15, 30, 22, 0.82) 0%, rgba(15, 30, 22, 0.6) 60%);
}
.hero::after {
  content: "";
  position: absolute;
  inset: 0;
  background-image: repeating-linear-gradient(135deg, rgba(255,255,255,0.04) 0 2px, transparent 2px 40px);
  pointer-events: none;
}
.hero .wrap { max-width: var(--max-width); margin: 0 auto; position: relative; z-index: 1; }
.hero h1 { color: #fff; max-width: 38rem; }
.hero p.lede { font-size: 1.2rem; max-width: 38rem; color: #eef5ef; }
.hero-actions { display: flex; gap: 0.85rem; flex-wrap: wrap; margin-top: 1.5rem; }

/* iOS Safari and most mobile browsers don't support fixed backgrounds well,
   so fall back to a normal scrolling background on small/touch screens. */
@media (max-width: 768px), (hover: none) {
  .hero { background-attachment: scroll; }
}

/* Every page.page-hero across the site is just a breadcrumb + h1 + a
   sentence or two of orientation copy -- not a real intro -- so it stays
   small everywhere rather than eating a big chunk of the viewport. Kept
   (not removed) for accessibility/orientation, just compact. */
.page-hero {
  background: linear-gradient(160deg, var(--color-primary-dark) 0%, var(--color-primary) 70%);
  color: #fff;
  padding: 0.85rem 1.5rem;
}
.page-hero .wrap { max-width: var(--max-width); margin: 0 auto; }
.page-hero h1 { color: #fff; font-size: clamp(1.4rem, 3vw, 1.8rem); margin-bottom: 0.25rem; }
.page-hero p { color: #eef5ef; font-size: 0.95rem; max-width: 46rem; margin-bottom: 0; }
.breadcrumb { font-size: 0.85rem; color: #d9e8df; margin-bottom: 0.35rem; }
.breadcrumb a { color: #d9e8df; }

/* ------------------------------ Buttons ------------------------------ */
.btn {
  display: inline-block;
  padding: 0.75rem 1.5rem;
  border-radius: var(--radius);
  font-weight: 700;
  text-decoration: none;
  border: 2px solid transparent;
  cursor: pointer;
  font-size: 1rem;
  font-family: var(--font-body);
  transition: transform var(--transition), background var(--transition), color var(--transition), border-color var(--transition);
}
.btn:hover { transform: translateY(-1px); }
.btn-primary { background: var(--color-accent); color: #fff; }
.btn-primary:hover { background: var(--color-accent-dark); color: #fff; }
.btn-secondary { background: transparent; border-color: #fff; color: #fff; }
.btn-secondary:hover { background: rgba(255,255,255,0.12); color: #fff; }
.btn-outline { background: transparent; border-color: var(--color-primary); color: var(--color-primary-dark); }
.btn-outline:hover { background: var(--color-primary-light); }
.btn-block { display: block; width: 100%; text-align: center; }

/* ------------------------------ Layout ------------------------------ */
.section { padding: clamp(2.5rem, 6vw, 4.5rem) 1.5rem; }
.section .wrap { max-width: var(--max-width); margin: 0 auto; }
.section--alt { background: var(--color-bg-alt); border-top: 1px solid var(--color-border); border-bottom: 1px solid var(--color-border); }
.section--deep { background: var(--color-bg-deep); }

/* Historic 1830s Sumner survey map, faded behind a parchment wash so the
   card text on top stays fully readable while the map's texture and
   handwriting show through around and behind it. */
.section--map {
  position: relative;
  background-image: url('../images/hopkinton-boundary-survey-map.jpg');
  background-size: cover;
  background-position: center;
  isolation: isolate;
}
.section--map::before {
  content: "";
  position: absolute;
  inset: 0;
  background: rgba(250, 246, 238, 0.87);
  z-index: 0;
}
.section--map > .wrap { position: relative; z-index: 1; }
.section-head { max-width: 46rem; margin-bottom: 2rem; }
.section-head p { color: var(--color-text-muted); font-size: 1.1rem; }
.eyebrow {
  display: inline-block;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  font-size: 0.78rem;
  font-weight: 700;
  color: var(--color-accent-dark);
  margin-bottom: 0.5rem;
}

.grid { display: grid; gap: 1.5rem; align-items: start; }
.grid-2 { grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); }
.grid-3 { grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); }
.grid-4 { grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); }

/* ------------------------------ Cards ------------------------------ */
.card {
  background: var(--color-bg-alt);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  padding: 1.5rem;
  box-shadow: var(--shadow);
}
.card h3 { margin-top: 0; font-size: 1.15rem; overflow-wrap: break-word; word-break: break-word; }
.card h4 { margin-top: 0; font-size: 1rem; overflow-wrap: break-word; word-break: break-word; }
.card--link { display: block; text-decoration: none; color: var(--color-text); transition: transform var(--transition), box-shadow var(--transition); }
.card--link:hover { transform: translateY(-3px); box-shadow: 0 10px 24px rgba(40,30,15,0.12); }
.card .tag { display: inline-block; background: var(--color-primary-light); color: var(--color-primary-dark); font-size: 0.75rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.06em; padding: 0.2rem 0.55rem; border-radius: 999px; margin-bottom: 0.5rem; }
.card__image {
  display: block;
  width: calc(100% + 3rem);
  margin: -1.5rem -1.5rem 1rem -1.5rem;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  border-radius: var(--radius) var(--radius) 0 0;
}

.media-frame {
  background: var(--color-bg-deep);
  border: 1px dashed var(--color-gold);
  border-radius: var(--radius);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--color-text-muted);
  font-size: 0.9rem;
  text-align: center;
  padding: 1rem;
  min-height: 160px;
}
.media-frame--tall { min-height: 280px; }
.media-frame--hero { min-height: 320px; }
.media-frame--photo { padding: 0; border-style: solid; background: none; overflow: hidden; }
.media-frame--photo img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* ------------------------------ Then & Now click-to-reveal compare ------------------------------ */
/* Modeled on a reference "now & then" widget: the frame starts showing only
   the archival ("then") photo, occupying the right half of the frame, with
   the left half held empty/reserved. Pressing the reveal button slides the
   archival photo into the left half while the present-day ("now") photo
   fades in on the right, so the end state shows both photos side by side at
   once. Pressing it again reverses the animation. This is deliberately
   button/click-triggered (not hover-triggered) to match that reference. */
.tn-item__title {
  margin: 0 0 0.6rem;
  font-size: 1.3rem;
  color: var(--color-primary-dark);
}
.tn-compare {
  width: 100%;
  overflow: hidden;
  border-radius: 4px;
  /* A picture-frame border in the site's "aged brass" accent, with a subtle
     inset bevel (light top/left, dark bottom/right) so it reads as a raised
     molding rather than a flat colored line, plus a soft drop shadow so the
     whole frame lifts off the page a little, like it's hanging on a wall.
     Deliberately just the frame chrome -- see .tn-compare__frame below for
     why the aspect-ratio and photo positioning don't also live here. */
  border: 10px solid var(--color-gold);
  box-shadow:
    inset 2px 2px 0 rgba(255, 255, 255, 0.35),
    inset -2px -2px 0 rgba(0, 0, 0, 0.35),
    0 10px 26px rgba(40, 30, 15, 0.3);
  background: var(--color-bg-deep);
}
.tn-compare__frame {
  position: relative;
  width: 100%;
  /* aspect-ratio is set inline per item (see then-and-now.php): the "then"
     photo's own pixel width DOUBLED, over its height. Each photo shows in
     full inside its own half of the frame, so the frame as a whole is
     shaped like two side-by-side copies of one photo's proportions -- no
     taller than that, so the frame always hugs the photo with no empty
     letterboxing above/below it. If a write-up's text runs taller than
     that, .tn-compare__intro's own overflow-y: auto lets it scroll rather
     than stretching the frame (see below).
     This aspect-ratio math assumes the box it's applied to has no border or
     padding of its own -- any fixed-pixel border thrown into that ratio's
     box would throw off the fraction just enough to letterbox the photo
     with a visible gap, which is why the border lives one level up on
     .tn-compare (a plain frame with no ratio math) instead of here. */
  background: var(--color-bg-deep);
}
/* Each pane is a half-width box that holds one full photo. The "then" pane
   starts pinned to the right edge and slides over to the left edge on
   reveal; the "now" pane stays put on the right and just fades in. Neither
   photo is ever cropped -- object-fit: contain (below) always shows the
   whole image, letterboxed if its proportions don't perfectly match its
   half of the frame. */
.tn-compare__then-pane,
.tn-compare__now-pane {
  position: absolute;
  top: 0;
  left: 50%;
  width: 50%;
  height: 100%;
}
.tn-compare__then-pane {
  z-index: 2;
  transition: left 0.6s ease;
}
.tn-compare.is-revealed .tn-compare__then-pane { left: 0; }
.tn-compare__now-pane {
  z-index: 1;
  opacity: 0;
  transition: opacity 0.6s ease;
}
.tn-compare.is-revealed .tn-compare__now-pane { opacity: 1; }
/* Optional write-up, from data/then-now-captions.json (see then-and-now.php
   for the format). Sits in the left half, underneath the "then" pane's
   resting position (z-index 2 vs 0 here) -- so when that pane slides over
   on reveal, its own opaque background (see .tn-compare__photo above)
   wipes the text away/covers it up, exactly like the photo swap itself. */
.tn-compare__intro {
  position: absolute;
  top: 0;
  left: 0;
  width: 50%;
  height: 100%;
  z-index: 0;
  display: flex;
  /* Top-aligned, not centered: a flex item taller than its container can't
     be scrolled up to reach the part hidden above the container's top edge
     (scrollTop can't go negative), so a long caption with align-items:
     center gets its opening line clipped and unreachable. Starting at the
     top keeps the whole caption reachable (via overflow-y: auto below) no
     matter how long it runs. */
  align-items: flex-start;
  justify-content: center;
  padding: 1.75rem;
  overflow-y: auto;
  background: var(--color-bg-deep);
  color: var(--color-text);
}
.tn-compare__intro p {
  margin: 0;
  max-width: 40ch;
  text-align: justify;
  text-align-last: left;
  -webkit-hyphens: auto;
  hyphens: auto;
  font-family: var(--font-heading);
  font-size: clamp(0.85rem, 0.3vw + 0.7rem, 1rem);
  line-height: 1.5;
}
.tn-compare__photo,
.tn-compare__placeholder {
  width: 100%;
  height: 100%;
  display: block;
  /* contain -- never crops. Shows the entire photo, letterboxed (against
     the frame's own background color) rather than cropped if needed. */
  object-fit: contain;
  background: var(--color-bg-deep);
  user-select: none;
  -webkit-user-drag: none;
}
/* Every photo opens the shared #tn-lightbox at full size on click (see
   js/then-and-now.js) -- cursor + a slight brighten on hover/focus signal
   that, same idea as the archive page's own zoomable photos. */
.tn-compare__photo { cursor: zoom-in; transition: filter 0.15s ease; }
.tn-compare__photo:hover,
.tn-compare__photo:focus-visible { filter: brightness(1.06); }
.tn-compare__photo:focus-visible { outline: 3px solid var(--color-primary); outline-offset: -3px; }
.tn-compare__placeholder {
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: 1rem;
  border-left: 1px dashed var(--color-gold);
  color: var(--color-text-muted);
  font-size: 0.8rem;
}
/* Badges live inside their own pane, so they travel with it automatically
   as the "then" pane slides from right to left. */
.tn-compare__badge {
  position: absolute;
  bottom: 0.75rem;
  padding: 0.3rem 0.7rem;
  background: rgba(15, 30, 22, 0.78);
  color: #fff;
  font-size: 0.75rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  border-radius: 4px;
  z-index: 3;
  pointer-events: none;
}
.tn-compare__then-pane .tn-compare__badge { left: 0.75rem; }
.tn-compare__now-pane .tn-compare__badge { right: 0.75rem; }
.tn-compare__nav {
  position: absolute;
  bottom: 0.75rem;
  right: 0.75rem;
  z-index: 4;
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.4rem 0.75rem;
  background: rgba(15, 30, 22, 0.78);
  color: #fff;
  border: none;
  border-radius: 999px;
  font: inherit;
  font-size: 0.72rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  cursor: pointer;
  transition: background 0.2s ease, right 0.6s ease, left 0.6s ease;
}
.tn-compare.is-revealed .tn-compare__nav {
  right: auto;
  left: 0.75rem;
}
.tn-compare__nav:hover,
.tn-compare__nav:focus-visible { background: rgba(15, 30, 22, 0.92); }
.tn-compare__nav:focus-visible { outline: 3px solid var(--color-primary); outline-offset: 2px; }
.tn-compare__nav-arrow { font-size: 0.85rem; line-height: 1; }

/* Then & Now page layout: just a stacked column of photo-frame comparisons,
   no sidebar or surrounding text. */
.tn-layout__main { display: flex; flex-direction: column; gap: 2.5rem; margin-top: 2rem; }
.tn-item { scroll-margin-top: 1.5rem; }

/* Shared full-size viewer (native <dialog>) that any .tn-compare__photo
   opens, at its own natural resolution rather than squeezed into a
   comparison pane -- see js/then-and-now.js. One dialog, reused for every
   photo on the page; its image src is swapped in on open. Deliberately no
   card/body chrome like .archive-modal has -- just the photo, as large as
   the viewport allows, on a dim backdrop. */
.tn-lightbox {
  border: none;
  padding: 0;
  background: transparent;
  max-width: 94vw;
  max-height: 94vh;
}
.tn-lightbox[open] { display: flex; }
.tn-lightbox::backdrop { background: rgba(15, 30, 22, 0.88); }
.tn-lightbox__img {
  display: block;
  max-width: 94vw;
  max-height: 94vh;
  width: auto;
  height: auto;
  object-fit: contain;
  border-radius: 4px;
  box-shadow: 0 20px 60px rgba(20, 15, 5, 0.45);
}
.tn-lightbox__close {
  position: fixed;
  top: 1rem;
  right: 1rem;
  z-index: 2;
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  background: rgba(15, 30, 22, 0.78);
  color: #fff;
  border: none;
  border-radius: 999px;
  padding: 0.5rem 1.1rem 0.5rem 0.9rem;
  font-family: var(--font-body);
  font-size: 1rem;
  font-weight: 600;
  line-height: 1;
  cursor: pointer;
}
/* The × glyph alone, sized up a bit relative to the "Close" label next to
   it -- aria-hidden since the button's aria-label already says "Close
   full-size photo", so screen readers get one clean announcement rather
   than "times Close" or the glyph read twice. */
.tn-lightbox__close span { font-size: 1.4rem; }
.tn-lightbox__close:hover { background: var(--color-primary-dark); }
.tn-lightbox__close:focus-visible { outline: 3px solid var(--color-primary-light); outline-offset: 2px; }

/* On a phone, the side-by-side layout above falls apart: the frame's
   aspect-ratio is shaped for two photo-width halves sitting next to each
   other, so at a narrow column width that same ratio produces a very
   short box, and each half within it is only a sliver wide. Squeezing a
   whole photo and a paragraph of type into a couple of inches of width
   doesn't work at any font size.
   Below this breakpoint the layout switches from side-by-side panes to a
   stacked column instead: the write-up (if any), full width; the archival
   photo below it, full width, at its own natural height; and -- once
   revealed -- the present-day photo full width underneath that, with the
   Reveal/Back button becoming an ordinary full-width button rather than a
   corner overlay. Nothing crops (object-fit: contain is unaffected) and
   nothing needs to scroll to be reached; it's just stacked instead of
   side-by-side, per the standing "no crop, but mobile can lay out
   differently" rule for this page.
   880px, not 640px, to match the breakpoint the site's own nav already
   switches to its mobile menu at -- otherwise a mid-size phone or a
   tablet would fall in the gap between the two: past 640px so still
   getting the cramped side-by-side squeeze here, but under 880px so
   already seeing the mobile nav everywhere else. */
@media (max-width: 880px) {
  .tn-compare__frame {
    aspect-ratio: auto !important;
    display: block;
  }
  .tn-compare__intro,
  .tn-compare__then-pane,
  .tn-compare__now-pane {
    position: relative;
    top: auto;
    left: 0 !important;
    width: 100%;
    height: auto;
    opacity: 1 !important;
    transition: none;
  }
  .tn-compare__intro {
    padding: 1rem;
    max-height: 40vh;
  }
  .tn-compare__intro p { font-size: 0.85rem; line-height: 1.45; max-width: 100%; }
  /* Before reveal: write-up (if any) + the archival photo. After reveal:
     the write-up is done its job (there's no slide-and-cover animation to
     do that here), so it steps aside and the present-day photo appears
     below the archival one -- both still visible at once, just stacked
     instead of side-by-side. */
  .tn-compare__now-pane { display: none; }
  .tn-compare.is-revealed .tn-compare__intro { display: none; }
  .tn-compare.is-revealed .tn-compare__now-pane { display: block; }
  .tn-compare__photo,
  .tn-compare__placeholder { height: auto; }
  .tn-compare__nav {
    position: relative;
    inset: auto;
    width: 100%;
    margin-top: 0.6rem;
    justify-content: center;
    border-radius: var(--radius);
    transition: background 0.2s ease;
  }
  .tn-compare.is-revealed .tn-compare__nav { left: auto; right: auto; }
}

/* ------------------------------ Timeline ------------------------------ */
.timeline { position: relative; margin: 2rem 0; }
.timeline__track {
  display: flex;
  gap: 0.5rem;
  overflow-x: auto;
  padding: 1rem 0.25rem 1.5rem;
  scrollbar-width: thin;
  border-bottom: 2px solid var(--color-border);
}
.timeline__item {
  flex: 0 0 auto;
  width: 150px;
  background: var(--color-bg-alt);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  padding: 0.75rem 0.85rem;
  cursor: pointer;
  text-align: left;
  font-family: var(--font-body);
}
.timeline__item:hover { border-color: var(--color-accent); }
.timeline__item[aria-selected="true"] {
  border-color: var(--color-accent);
  background: var(--color-primary-light);
}
.timeline__year { font-family: var(--font-heading); font-weight: 700; font-size: 1.15rem; color: var(--color-accent-dark); display: block; }
.timeline__label { font-size: 0.85rem; color: var(--color-text-muted); }
.timeline__detail {
  margin-top: 1.5rem;
  background: var(--color-bg-alt);
  border: 1px solid var(--color-border);
  border-left: 6px solid var(--color-accent);
  border-radius: var(--radius);
  padding: 1.5rem;
}
.timeline__detail h3 { margin-top: 0; }
.timeline__detail .timeline__meta { color: var(--color-text-muted); font-size: 0.9rem; margin-bottom: 0.75rem; }

/* ------------------------------ Chapters / story list ------------------------------ */
.chapter {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 1.25rem;
  padding: 2rem 0;
  border-bottom: 1px solid var(--color-border);
}
.chapter:last-child { border-bottom: none; }
@media (min-width: 760px) {
  .chapter { grid-template-columns: 1fr 1.6fr; align-items: start; }
}
.chapter__num { font-family: var(--font-heading); color: var(--color-gold); font-size: 0.95rem; letter-spacing: 0.1em; text-transform: uppercase; margin-bottom: 0.25rem; }
.chapter__title { margin-top: 0; }

/* ------------------------------ Stats ------------------------------ */
.stat { text-align: center; }
.stat__num { font-family: var(--font-heading); font-size: clamp(1.8rem, 4vw, 2.6rem); color: var(--color-accent-dark); font-weight: 700; }
.stat__label { color: var(--color-text-muted); font-size: 0.95rem; }

/* ------------------------------ Forms ------------------------------ */
.form-grid { display: grid; gap: 1rem; }
label { font-weight: 700; display: block; margin-bottom: 0.3rem; }
input, select, textarea {
  width: 100%;
  font-family: inherit;
  font-size: 1rem;
  padding: 0.65rem 0.75rem;
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  background: #fff;
  color: var(--color-text);
}
fieldset { border: 1px solid var(--color-border); border-radius: var(--radius); padding: 1rem 1.25rem; }
legend { font-family: var(--font-heading); font-weight: 700; padding: 0 0.4rem; }
.required-note { font-size: 0.85rem; color: var(--color-text-muted); }
.field-hint { font-size: 0.85rem; color: var(--color-text-muted); margin-top: 0.25rem; }

/* ------------------------------ Filters (Collections) ------------------------------ */
.filters { display: grid; gap: 1rem; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); align-items: end; }
.results-count { margin: 1rem 0; font-weight: 700; color: var(--color-text-muted); }
.archive-item { display: flex; flex-direction: column; gap: 0.5rem; }
.archive-item .media-frame { aspect-ratio: 4/3; }
.archive-item__photo { aspect-ratio: 4/3; overflow: hidden; border-radius: var(--radius); border: 1px solid var(--color-border); }
.archive-item__photo img { width: 100%; height: 100%; object-fit: cover; display: block; }
.archive-item__meta { display: flex; flex-wrap: wrap; gap: 0.4rem; }
.pill { background: var(--color-bg-deep); border: 1px solid var(--color-border); border-radius: 999px; padding: 0.15rem 0.6rem; font-size: 0.75rem; font-weight: 700; color: var(--color-text-muted); text-transform: uppercase; letter-spacing: 0.04em; }
.empty-state { text-align: center; padding: 3rem 1rem; color: var(--color-text-muted); }

/* ------------------------------ Audio / transcript demo ------------------------------ */
.audio-card audio { width: 100%; margin: 0.75rem 0; }
details.transcript { margin-top: 0.5rem; }
details.transcript summary { cursor: pointer; font-weight: 700; color: var(--color-primary-dark); }
details.transcript .transcript-body { margin-top: 0.75rem; max-height: 220px; overflow-y: auto; padding-right: 0.5rem; border-top: 1px solid var(--color-border); padding-top: 0.75rem; }
details.transcript .transcript-body p { font-size: 0.95rem; }

/* ------------------------------ Banner / callout ------------------------------ */
.callout {
  background: var(--color-bg-deep);
  border-left: 6px solid var(--color-gold);
  border-radius: var(--radius);
  padding: 1.25rem 1.5rem;
}
.callout--accent { border-left-color: var(--color-accent); }
.banner-cta {
  background: var(--color-accent);
  color: #fff;
  text-align: center;
  padding: clamp(2rem, 5vw, 3rem) 1.5rem;
}
.banner-cta h2 { color: #fff; }
.banner-cta .wrap { max-width: 46rem; margin: 0 auto; }

/* ------------------------------ Pricing / membership ------------------------------ */
.tier { display: flex; flex-direction: column; height: 100%; }
.tier__price { font-family: var(--font-heading); font-size: 2rem; color: var(--color-primary-dark); margin: 0.5rem 0; }
.tier ul { padding-left: 1.1rem; flex-grow: 1; }
.tier--featured { border: 2px solid var(--color-accent); position: relative; }
.tier--featured::before {
  content: "Most Popular";
  position: absolute;
  top: -0.75rem; right: 1rem;
  background: var(--color-accent);
  color: #fff;
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  padding: 0.25rem 0.6rem;
  border-radius: 999px;
  font-weight: 700;
}

/* ------------------------------ Accessibility info blocks ------------------------------ */
.a11y-list { list-style: none; padding: 0; display: grid; gap: 0.75rem; }
.a11y-list li { display: flex; gap: 0.75rem; align-items: flex-start; background: var(--color-bg-alt); border: 1px solid var(--color-border); border-radius: var(--radius); padding: 0.85rem 1rem; }
.a11y-list .icon { font-size: 1.3rem; flex-shrink: 0; }

/* ------------------------------ Info table ------------------------------ */
.info-table { width: 100%; border-collapse: collapse; background: var(--color-bg-alt); border: 1px solid var(--color-border); border-radius: var(--radius); overflow: hidden; }
.info-table th, .info-table td { text-align: left; padding: 0.7rem 1rem; border-bottom: 1px solid var(--color-border); }
.info-table th { width: 40%; background: var(--color-bg-deep); font-family: var(--font-heading); }
.info-table tr:last-child th, .info-table tr:last-child td { border-bottom: none; }

/* Keep info-table rows label-left/content-right on narrow screens too —
   tables don't stack by default here, but tighten column width, padding,
   and font size so the row stays comfortably horizontal instead of wrapping
   awkwardly. */
@media (max-width: 600px) {
  .info-table th { width: 34%; font-size: 0.92rem; }
  .info-table th, .info-table td { padding: 0.6rem 0.65rem; font-size: 0.92rem; }
}

/* ------------------------------ Footer ------------------------------ */
footer.site-footer {
  background: var(--color-primary-dark);
  color: #e7eee9;
  padding: 3rem 1.5rem 1.5rem;
}
footer.site-footer .wrap { max-width: var(--max-width); margin: 0 auto; }
footer.site-footer h2 { color: #fff; font-size: 1.1rem; }
footer.site-footer a { color: #cfe0d6; }
footer.site-footer a:hover { color: #fff; }
.footer-grid { display: grid; gap: 2rem; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); margin-bottom: 2rem; }
.footer-grid ul { list-style: none; padding: 0; margin: 0; display: grid; gap: 0.5rem; }
.footer-bottom { border-top: 1px solid rgba(255,255,255,0.15); padding-top: 1.25rem; font-size: 0.85rem; color: #b7c7bd; display: flex; flex-wrap: wrap; gap: 1rem; justify-content: space-between; }
.footer-bottom a { color: #b7c7bd; }

/* ------------------------------ Digital Archive: filters, cards, modal ------------------------------ */
/* Needed because .filters (display:grid) and .btn (display:inline-block)
   both set an explicit `display`, which otherwise beats the browser's
   default [hidden] rule. Progressive-enhancement elements (the filter bar,
   results count, reset button, empty state) start hidden in the markup and
   are revealed by JS once they're actually wired up. */
[hidden] { display: none !important; }

#archive-filters > div:first-child { grid-column: 1 / -1; }

.archive-item__photo { position: relative; }
.archive-item__photo img { transition: transform var(--transition); }
.archive-item__photo[role="button"] { cursor: zoom-in; }
.archive-item__photo[role="button"]:hover img,
.archive-item__photo[role="button"]:focus-visible img { transform: scale(1.045); }

.archive-item__details { margin-top: auto; padding-top: 0.35rem; }
.archive-item__details > summary {
  cursor: pointer;
  font-weight: 700;
  color: var(--color-primary-dark);
  list-style: none;
}
.archive-item__details > summary::-webkit-details-marker { display: none; }
.archive-item__details > summary::before { content: "+ "; color: var(--color-accent-dark); }
.archive-item__details[open] > summary::before { content: "\2212 "; }
.archive-item__details-body { margin-top: 0.75rem; font-size: 0.95rem; }

/* Modal (native <dialog>) showing one archive item's full detail. */
.archive-modal {
  /* No `position` override here on purpose: <dialog> needs its UA-default
     `position: fixed` (plus `inset:0; margin:auto`) to stay centered in the
     top layer. `position: fixed` still works fine as a containing block for
     the absolutely-positioned close button below. */
  border: none;
  padding: 0;
  border-radius: var(--radius);
  width: min(900px, 92vw);
  max-height: min(88vh, 900px);
  background: var(--color-bg-alt);
  box-shadow: 0 20px 60px rgba(20, 15, 5, 0.35);
  overflow: hidden;
}
.archive-modal[open] { display: flex; flex-direction: column; }
.archive-modal::backdrop { background: rgba(15, 30, 22, 0.72); }
.archive-modal__close {
  position: absolute;
  top: 0.75rem;
  right: 0.9rem;
  z-index: 2;
  background: rgba(15, 30, 22, 0.72);
  color: #fff;
  border: none;
  border-radius: 999px;
  width: 2.25rem;
  height: 2.25rem;
  font-size: 1.4rem;
  line-height: 1;
  cursor: pointer;
}
.archive-modal__close:hover { background: var(--color-primary-dark); }
.archive-modal__media {
  background: var(--color-bg-deep);
  display: flex;
  align-items: center;
  justify-content: center;
  max-height: 55vh;
  overflow: hidden;
  flex-shrink: 0;
}
.archive-modal__media img { width: 100%; height: 100%; max-height: 55vh; object-fit: contain; }
.archive-modal__media .media-frame { width: 100%; min-height: 220px; border-radius: 0; border-width: 0; }
.archive-modal__body { padding: 1.5rem; overflow-y: auto; }
.archive-modal__body h2 { margin: 0.5rem 0 0.25rem; }
.archive-modal__body .archive-item__meta { margin-bottom: 0.25rem; }

@media (max-width: 640px) {
  .archive-modal { width: 100vw; max-height: 100vh; height: 100vh; border-radius: 0; }
  .archive-modal__media { max-height: 40vh; }
  .archive-modal__media img { max-height: 40vh; }
}

/* Every "Donate" link on the site (utility bar, nav CTA, footer, and the
   "Donate or Become a Member" buttons) opens this shared dialog instead of
   navigating away, with Zeffy's donation form loaded in an iframe -- keeps
   the visitor on our site. One dialog, reused sitewide; built and inserted
   by js/main.js only on pages that actually have a Donate link. */
.donate-modal {
  border: none;
  padding: 0;
  border-radius: var(--radius);
  width: min(560px, 92vw);
  height: min(760px, 88vh);
  background: var(--color-bg-alt);
  box-shadow: 0 20px 60px rgba(20, 15, 5, 0.35);
  overflow: hidden;
}
.donate-modal[open] { display: flex; flex-direction: column; }
.donate-modal::backdrop { background: rgba(15, 30, 22, 0.72); }
.donate-modal__close {
  position: absolute;
  bottom: 0.75rem;
  right: 0.9rem;
  z-index: 2;
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  background: rgba(15, 30, 22, 0.78);
  color: #fff;
  border: none;
  border-radius: 999px;
  padding: 0.5rem 1.1rem 0.5rem 0.9rem;
  font-family: var(--font-body);
  font-size: 1rem;
  font-weight: 600;
  line-height: 1;
  cursor: pointer;
}
.donate-modal__close span { font-size: 1.4rem; }
.donate-modal__close:hover { background: var(--color-primary-dark); }
.donate-modal__close:focus-visible { outline: 3px solid var(--color-primary-light); outline-offset: 2px; }
.donate-modal__frame {
  flex: 1;
  width: 100%;
  height: 100%;
  border: none;
  display: block;
  background: var(--color-bg-alt);
}

@media (max-width: 640px) {
  .donate-modal { width: 100vw; height: 100vh; max-height: 100vh; border-radius: 0; }
}

/* ------------------------------ Misc helpers ------------------------------ */
.text-muted { color: var(--color-text-muted); }
.mt-0 { margin-top: 0; }
.center { text-align: center; }
.visually-hidden {
  position: absolute !important;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0,0,0,0);
  white-space: nowrap; border: 0;
}