/* Uncanny Valley — a contemporary take on a newspaper river.
   Aesthetic: warm newsprint paper, ink-black serif headlines, a single
   electric accent (valley dusk violet), generous rules between items. */

:root {
  --paper: #f4f1ea;
  --paper-2: #fbf9f4;
  --ink: #16140f;
  --ink-soft: #514c41;
  --rule: #d8d2c4;
  --accent: #6a4cff;      /* dusk violet */
  --accent-ink: #3a2bb8;
  --warm: #c2452d;        /* breaking/high-priority brick */
  --weather: #1f6f8b;
  --event: #146b54;
  --max: 760px;
}

/* Dark mode: warm near-black "newsprint at night". The whole design is built on
   these tokens, so flipping them re-themes everything; accents are brightened
   for contrast on dark. */
@media (prefers-color-scheme: dark) {
  :root {
    --paper: #15130e;
    --paper-2: #211e17;
    --ink: #ece6d8;
    --ink-soft: #a99f8b;
    --rule: #38332a;
    --accent: #8f76ff;
    --accent-ink: #b9a9ff;
    --warm: #ef6e54;
    --event: #2aa07c;
  }
}

* { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: "Iowan Old Style", "Palatino Linotype", Palatino, "Book Antiqua", Georgia, serif;
  font-size: 18px;
  line-height: 1.5;
}

/* ---------- Masthead ---------- */
/* Rotating CC-BY Pioneer Valley vistas cross-fade behind the masthead. Two
   stacked photo layers (JS swaps + fades them), a scrim weighted toward the
   bottom (where the text sits) for legibility, and the text on top. Same in
   light + dark mode — the masthead is its own dark photographic band. */
/* The whole masthead is sticky with a negative top of --mh-stick (= its height
   minus the chip band, set in JS). It scrolls up with the page until only the
   bottom band — the town/topic chips, still on the same photo — stays pinned at
   the top. One photographic background covers both the title and the chips. */
.masthead {
  /* --filt-band-pad is the photo band shown both above and below the chips when
     the masthead is pinned, so the stuck chips sit centered (equal top/bottom).
     It's also the masthead's bottom padding, so the two stay locked together. */
  --filt-band-pad: 14px;
  position: sticky;
  top: calc(var(--filt-band-pad) - var(--mh-stick, 0px));
  z-index: 20;
  overflow: hidden;
  isolation: isolate;
  background-color: #18241a;
}
@media (prefers-color-scheme: dark) {
  /* Keep the original dark, moody masthead: no photo brightening, heavier scrim. */
  .masthead .mh-photo { filter: none; }
  .masthead::after {
    background: linear-gradient(to bottom, rgba(16,24,16,0.34) 0%, rgba(12,18,12,0.68) 70%, rgba(12,18,12,0.84) 100%);
  }
}
.masthead .mh-photo {
  position: absolute;
  inset: 0;
  z-index: 0;
  background-size: cover;
  background-position: center 58%;
  opacity: 0;
  transition: opacity 1.4s ease;
  /* Light mode: brighten the vista so the masthead reads as daylight rather than
     a dark moody band. Reset to none in dark mode below. */
  filter: brightness(1.24) saturate(1.05);
}
.masthead .mh-photo.show { opacity: 1; }
.masthead::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  /* Light mode: a lighter scrim — just enough to keep the white title/chips
     legible over the brightened photo. Dark mode restores the heavier scrim. */
  background: linear-gradient(to bottom, rgba(16,24,16,0.18) 0%, rgba(12,18,12,0.42) 70%, rgba(12,18,12,0.54) 100%);
}
.masthead-inner {
  position: relative;
  z-index: 2;
  max-width: var(--max);
  margin: 0 auto;
  /* A tight clean band below the chips, then a hard edge into the body (both modes). */
  padding: 34px 20px var(--filt-band-pad);
}
.wordmark {
  margin: 0;
  /* Scales from phones (≈32px) up to 64px; min keeps it readable while the
     vw term lets it shrink enough to never overflow narrow viewports. */
  font-size: clamp(32px, 11vw, 64px);
  font-weight: 800;
  letter-spacing: -0.02em;
  line-height: 0.92;
  text-transform: uppercase;
  font-family: "Iowan Old Style", Georgia, serif;
  overflow-wrap: break-word;   /* allow wrap on very narrow screens */
  hyphens: none;
  color: #f6f2ea;              /* light over the photo, both modes */
  text-shadow: 0 2px 12px rgba(0, 0, 0, 0.55), 0 1px 2px rgba(0, 0, 0, 0.45);
}
.tagline {
  margin: 8px 0 0;
  font-style: italic;
  color: rgba(246, 242, 234, 0.92);
  font-size: 16px;
  text-shadow: 0 1px 5px rgba(0, 0, 0, 0.55);
}
.meta {
  margin-top: 12px;
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
  font-size: 12px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ink-soft);
}

/* ---------- Filters ---------- */
/* The chips live inside the masthead, directly on its photo — no background of
   their own. They're the band that stays pinned once the masthead scrolls up. */
.filters {
  /* ≥ --filt-band-pad so the photo band above the pinned chips is clean (never
     clips the tagline). */
  margin-top: 16px;
}
.filter-row {
  padding: 4px 0;
  display: flex;
  align-items: center;
  gap: 10px;
}
.filter-label {
  flex: 0 0 auto;
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: rgba(246, 242, 234, 0.72);
  text-shadow: 0 1px 4px rgba(0, 0, 0, 0.6);
  width: 68px;
}
.chip-scroll {
  display: flex;
  gap: 6px;
  overflow-x: auto;
  scrollbar-width: none;        /* Firefox: hide scrollbar */
  -ms-overflow-style: none;     /* IE/old Edge: hide scrollbar */
  padding-bottom: 2px;
  /* Soft-fade an end only when there's more to scroll that way (widths set in
     JS): no left fade at the start, no right fade at the end. */
  --fade-l: 0px;
  --fade-r: 0px;
  -webkit-mask-image: linear-gradient(to right, transparent 0, #000 var(--fade-l), #000 calc(100% - var(--fade-r)), transparent 100%);
          mask-image: linear-gradient(to right, transparent 0, #000 var(--fade-l), #000 calc(100% - var(--fade-r)), transparent 100%);
}
.chip-scroll::-webkit-scrollbar { display: none; }  /* Chrome/Safari/Edge */
.chip {
  flex: 0 0 auto;
  border: 1px solid rgba(246, 242, 234, 0.34);
  background: rgba(20, 24, 18, 0.42);
  color: rgba(246, 242, 234, 0.92);
  border-radius: 999px;
  padding: 4px 12px;
  font-size: 13px;
  font-family: -apple-system, system-ui, sans-serif;
  cursor: pointer;
  white-space: nowrap;
  transition: all 0.12s ease;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.5);
}
.chip:hover { border-color: #fff; color: #fff; }
/* A dead-end chip (no stories under the other dimension's filter) dims out and
   stops responding, so the user can't select their way into an empty river. */
.chip.is-empty { opacity: 0.32; pointer-events: none; }
.chip.active {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
  text-shadow: none;
}

/* ---------- River ---------- */
.river {
  max-width: var(--max);
  margin: 0 auto;
  padding: 8px 20px 60px;
}
.loading {
  color: var(--ink-soft);
  font-style: italic;
  margin: 0;
  min-height: 70vh;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
}
/* While the loading message is up, keep the footer out of view so it doesn't
   bunch under the masthead before the river fills in. */
body:has(.loading) .footer { display: none; }

/* Story item */
.item { padding: 22px 0; border-bottom: 1px solid var(--rule); }
.item:first-child { padding-top: 24px; }

.story { display: grid; grid-template-columns: 1fr; gap: 6px; }
.story.has-img { grid-template-columns: 1fr 120px; gap: 18px; }
.story-body { min-width: 0; }
.kicker {
  font-family: -apple-system, system-ui, sans-serif;
  font-size: 12px;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color: var(--ink-soft);
  margin-bottom: 5px;
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: center;
}
.kicker .town {
  color: var(--accent-ink);
  font-weight: 700;
}
.kicker .topic { color: var(--ink-soft); }
.headline {
  margin: 0 0 6px;
  font-size: 24px;
  line-height: 1.18;
  font-weight: 700;
  letter-spacing: -0.01em;
}
.headline a { color: var(--ink); text-decoration: none; }
.headline a:hover { color: var(--accent-ink); }
.summary { margin: 0; color: var(--ink-soft); font-size: 16.5px; }
.byline {
  margin-top: 8px;
  font-family: -apple-system, system-ui, sans-serif;
  font-size: 12.5px;
  color: var(--ink-soft);
}
.byline .src { font-weight: 600; color: var(--ink); }

/* Topic rollup: same-event coverage tucked under the primary story as a tight
   list of links, set off by a hairline rule. Spans the full item width even when
   the story has a thumbnail (it lives in .story-body, which is the text column). */
.related {
  margin-top: 12px;
  padding: 10px 14px 11px;
  background: var(--paper-2);
  border: 1px solid var(--rule);
  border-radius: 10px;
}
.related-label {
  display: block;
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
  font-size: 9.5px;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--ink-soft);
  margin-bottom: 6px;
}
.related ul { margin: 0; padding: 0 0 0 16px; list-style: disc; }
.related li { margin: 3px 0; line-height: 1.25; }
.related li::marker { color: var(--ink-soft); font-size: 0.85em; }
.related li a {
  font-family: "Iowan Old Style", Georgia, serif;
  font-size: 13px;
  color: var(--ink);
  text-decoration: none;
}
.related li a:hover { color: var(--accent-ink); }
.related-meta {
  margin-left: 7px;
  font-family: -apple-system, system-ui, sans-serif;
  font-size: 10.5px;
  color: var(--ink-soft);
  white-space: nowrap;
}
.thumb {
  width: 120px; height: 120px;
  border-radius: 3px; background: var(--rule);
  overflow: hidden;   /* clip the hover zoom, like the hero photo cards */
}
.thumb img {
  width: 100%; height: 100%; object-fit: cover; display: block;
  transition: transform 0.4s ease;
}
.story:hover .thumb img { transform: scale(1.03); }

/* Lead story gets bigger type */
.item.lead .headline { font-size: clamp(30px, 6vw, 40px); }
.item.lead .summary { font-size: 18px; }

/* ---------- Top story photo card (hero treatment) ---------- */
.topstory { padding: 26px 0; border-bottom: 1px solid var(--rule); }
.topstory-card { display: block; text-decoration: none; color: inherit; }
.topstory-media {
  width: 100%;
  aspect-ratio: 16 / 9;
  border-radius: 6px;
  overflow: hidden;
  background: var(--rule);
  margin-bottom: 14px;
}
.topstory-media img {
  width: 100%; height: 100%; object-fit: cover; display: block;
  transition: transform 0.4s ease;
}
.topstory-card:hover .topstory-media img { transform: scale(1.03); }
/* If the art fails to load, fall back to a normal text-only treatment. */
.topstory.no-art .topstory-media { display: none; }
.topstory .eyebrow {
  color: var(--warm);
  font-weight: 800;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}
.topstory .headline { font-size: clamp(26px, 4.5vw, 34px); margin-top: 2px; }
.topstory-card:hover .headline { color: var(--accent-ink); }
/* The lead hero is larger and gets a touch more presence. */
.topstory.lead .headline { font-size: clamp(30px, 6vw, 44px); }
.topstory.lead .summary { font-size: 18px; }

/* ---------- Weather card ---------- */
.weather-card {
  /* A tinted public-domain photo of the current condition (set via --wx-bg in
     JS), over a teal fallback color if the image is missing. The tint keeps the
     white text legible across any photo. */
  background-color: #24506b;
  background-image: linear-gradient(135deg, rgba(20,70,95,0.72) 0%, rgba(28,42,78,0.86) 100%), var(--wx-bg, none);
  background-size: cover;
  background-position: center;
  color: #fff; border-radius: 8px; padding: 20px 22px; margin: 8px 0;
  border-bottom: none !important;
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.45);
  overflow: hidden;
}
.weather-top { display: flex; align-items: center; gap: 16px; }
.weather-emoji { font-size: 52px; line-height: 1; }
.weather-now .temp { font-size: 40px; font-weight: 800; }
.weather-now .cond { font-size: 15px; opacity: 0.9; }
.weather-loc {
  font-family: -apple-system, system-ui, sans-serif;
  font-size: 12px; text-transform: uppercase; letter-spacing: 0.06em;
  opacity: 0.85; margin-bottom: 10px;
}
.weather-detail { font-size: 13px; opacity: 0.85; font-family: -apple-system, system-ui, sans-serif; }
.forecast { display: flex; gap: 14px; margin-top: 14px; flex-wrap: wrap; }
.fc-day {
  font-family: -apple-system, system-ui, sans-serif; font-size: 12px; text-align: center;
}
.fc-day .d { opacity: 0.8; }
.fc-day .e { font-size: 22px; }
.fc-day .t { font-weight: 600; }
.fc-day .t .lo { opacity: 0.6; }

/* ---------- Event card ---------- */
.event-card {
  display: flex; gap: 16px; align-items: flex-start;
  background: var(--paper-2);
  border-left: 4px solid var(--event);
  border-radius: 4px; padding: 16px 18px; margin: 6px 0;
  border-bottom: none !important;
}
.event-date {
  flex: 0 0 auto; text-align: center; line-height: 1;
  font-family: -apple-system, system-ui, sans-serif; color: var(--event);
}
.event-date .mo { font-size: 12px; text-transform: uppercase; letter-spacing: 0.05em; font-weight: 700; }
.event-date .dy { font-size: 30px; font-weight: 800; }
.event-info .label {
  font-family: -apple-system, system-ui, sans-serif; font-size: 11px;
  text-transform: uppercase; letter-spacing: 0.06em; color: var(--event); font-weight: 700;
}
.event-info h3 { margin: 2px 0 4px; font-size: 19px; }
.event-info h3 a { color: var(--ink); text-decoration: none; }
.event-info h3 a:hover { color: var(--accent-ink); }  /* unified link-hover color */
.event-info .where {
  font-family: -apple-system, system-ui, sans-serif; font-size: 13px; color: var(--ink-soft);
}

.empty { padding: 50px 0; text-align: center; color: var(--ink-soft); font-style: italic; }

/* ---------- Valley map ---------- */
/* A geographic view of where the news is, sitting in the river between the top
   stories and the rest. The map itself is a Leaflet slippy map (CARTO
   light/dark tiles, chosen in JS to match the page theme); these styles frame
   it as a river item and theme its tooltips to the river's tokens. */
.valleymap-canvas {
  height: 380px;
  width: 100%;
  border-radius: 10px;
  overflow: hidden;
  background: var(--rule);
  /* Contain Leaflet's internal z-indexes (panes/controls/tooltips run up to
     ~1000) in their own stacking context at z-index 0, so the whole map scrolls
     UNDER the sticky masthead (z-index 20) instead of over it. */
  position: relative;
  z-index: 0;
}
/* Markers are clickable (they filter the river); show a pointer cursor. */
.valleymap-canvas .leaflet-interactive { cursor: pointer; }
/* Hover tooltip themed to the river tokens — borderless, so it doesn't flash a
   bright bordered box on the dark theme. */
.leaflet-tooltip.leaflet-tooltip {
  background: var(--paper-2);
  color: var(--ink);
  border: none;
  border-radius: 6px;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.28);
  font-family: -apple-system, system-ui, sans-serif;
  font-size: 12.5px;
  font-weight: 600;
}
.leaflet-tooltip-top::before { border-top-color: var(--paper-2); }
.leaflet-tooltip-bottom::before { border-bottom-color: var(--paper-2); }
.leaflet-tooltip-left::before { border-left-color: var(--paper-2); }
.leaflet-tooltip-right::before { border-right-color: var(--paper-2); }

/* ---------- Footer ---------- */
.footer {
  background: var(--paper-2);
}
.footer p {
  max-width: var(--max); margin: 0 auto; padding: 22px 20px;
  font-family: -apple-system, system-ui, sans-serif;
  font-size: 12.5px; color: var(--ink-soft);
  text-align: center;
}
.footer .credit { text-align: center; padding-top: 0; }
.footer a { color: var(--accent-ink); text-decoration: none; }
.footer a:hover { color: var(--accent); }

@media (max-width: 560px) {
  .story.has-img { grid-template-columns: 1fr; }
  .thumb { width: 100%; height: 200px; order: -1; }
}

/* View Transition API: smooth cross-fade when filters change the river. */
@media (prefers-reduced-motion: no-preference) {
  ::view-transition-old(root),
  ::view-transition-new(root) {
    animation-duration: 220ms;
    animation-timing-function: ease;
  }
}

/* Digest link in the footer */
.footer .digest-link { font-size: 14px; }
.footer .digest-link a { color: var(--accent-ink); font-weight: 600; text-decoration: none; }
.footer .digest-link a:hover { color: var(--accent); }
