.hero-art,.page-hero-art{background:#082f3b;overflow:hidden}
.hero-art img,.page-hero-art img{width:100%;height:100%;object-fit:cover;object-position:center;display:block}
@media(max-width:760px){.hero-art img,.page-hero-art img{object-position:66% center}}

/* Optional per-section illustration inside a story card. A section may carry a
   third element, { src, alt, note }; two-element sections stay text-only,
   which is deliberate. A section with no honest image should not get a faked
   one. The image bleeds to the card edges and the caption aligns with copy. */
.story-media {
  margin: -55px -55px 30px;
}

.story-media img {
  width: 100%;
  /* height:auto is load bearing. The generator emits width and height
     attributes for layout stability, and those become presentational hints, so
     without this the used height is the attribute value and CSS aspect-ratio is
     ignored entirely. That rendered the same artwork 332px tall in some cards
     and 800px tall and hard cropped in others. */
  height: auto;
  aspect-ratio: 3 / 2;
  object-fit: cover;
}

.story-media figcaption {
  padding: .75rem 55px 0;
  color: #5f7075;
  font-size: .74rem;
  line-height: 1.45;
}

.story-card.has-media .story-copy h2 {
  margin-top: 24px;
}

/* Wide story sections occupy a complete row. Illustrated ones split that row
   between image and copy, so a tall image cannot create a blank neighbouring
   card. */
.story-card.is-wide {
  grid-column: 1 / -1;
}

.story-card.is-wide:not(.has-media) .story-copy {
  max-width: 900px;
  margin: 0 auto;
}

.story-card.has-media.is-wide {
  display: grid;
  grid-template-columns: minmax(0, 1.15fr) minmax(20rem, .85fr);
  padding: 0;
  min-height: 0;
}

.story-card.has-media.is-wide .story-media {
  margin: 0;
  min-width: 0;
  min-height: 520px;
  display: grid;
  grid-template-rows: minmax(0, 1fr) auto;
  overflow: hidden;
}

.story-card.has-media.is-wide .story-media img {
  width: 100%;
  height: 100%;
  min-height: 0;
  aspect-ratio: auto;
  object-fit: cover;
}

.story-card.has-media.is-wide .story-media figcaption {
  padding: .75rem 32px 1rem;
}

.story-card.has-media.is-wide .story-copy {
  align-self: center;
  padding: 55px;
}

.story-card.has-media.is-wide .story-copy h2 {
  margin-top: 0;
}

/* Grid rows stretch to the tallest card, so an illustrated card leaves its
   text-only neighbour with a few hundred pixels of dead white. Centre the copy
   in cards without an image so the leftover reads as deliberate spacing. */
.story-card {
  display: flex;
  flex-direction: column;
}

.story-card:not(.has-media) .story-copy {
  margin: auto 0;
}

/* An odd number of sections leaves one empty grid cell, which shows through as
   a grey block because the grid uses its background as the card borders. */
.story-grid > .story-card:last-child:nth-child(odd) {
  grid-column: 1 / -1;
}

/* The heading's top margin exists to clear the sequence number. Pages that opt
   out of numbering do not need the gap. */
.story-copy > h2:first-child {
  margin-top: 0;
}

@media (max-width: 760px) {
  .story-media {
    margin: -38px -28px 24px;
  }

  .story-media figcaption {
    padding: .75rem 28px 0;
  }

  .story-card.has-media.is-wide {
    grid-template-columns: 1fr;
  }

  .story-card.has-media.is-wide .story-media img {
    height: auto;
    aspect-ratio: 3 / 2;
  }

  .story-card.has-media.is-wide .story-media {
    min-height: 0;
  }

  .story-card.has-media.is-wide .story-copy {
    padding: 38px 28px;
  }
}

/* Inset mode for small documentary images. A licensed archive photograph is
   often only a few hundred pixels wide; stretching it to fill a card makes it
   soft and quietly misrepresents it as a produced asset. Inset renders it at
   its own size, left aligned, inside the card padding rather than bleeding. */
.story-media.is-inset {
  margin: 0 0 26px;
  max-width: 20.5rem;
}

.story-media.is-inset img {
  width: 100%;
  height: auto;
  aspect-ratio: auto;
  object-fit: contain;
}

.story-media.is-inset figcaption {
  padding: .6rem 0 0;
}

/* Live weather panel on weather.html. Every element below has readable static
   content in the served HTML; script replaces it only on a successful fetch. */
.weather-panel {
  max-width: 1320px;
  margin: 0 auto;
  padding: 60px 32px 0;
}

.weather-panel h2 {
  font: 2rem/1.1 var(--serif);
  margin: 34px 0 14px;
}

.weather-panel h2:first-child {
  margin-top: 0;
}

.weather-status {
  color: #5f7075;
  font-size: .84rem;
  margin: 0 0 18px;
  max-width: 62ch;
}

.weather-grid {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 1px;
  background: var(--line);
  border: 1px solid var(--line);
  margin: 0;
}

.weather-grid > div {
  background: var(--paper);
  padding: 18px 20px;
}

.weather-grid dt {
  text-transform: uppercase;
  letter-spacing: .14em;
  font-size: .62rem;
  font-weight: 700;
  color: var(--coral);
}

.weather-grid dd {
  margin: 6px 0 0;
  font: 1.5rem/1.1 var(--serif);
}

.weather-read {
  margin: 18px 0 0;
  max-width: 70ch;
}

.forecast-strip {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 1px;
  background: var(--line);
  border: 1px solid var(--line);
}

.forecast-strip > p {
  grid-column: 1 / -1;
  background: var(--paper);
  margin: 0;
  padding: 20px;
  max-width: 70ch;
}

.forecast-day {
  background: var(--paper);
  padding: 16px 12px;
  display: grid;
  gap: 4px;
  text-align: center;
}

.forecast-day span {
  text-transform: uppercase;
  letter-spacing: .12em;
  font-size: .62rem;
  font-weight: 700;
  color: var(--coral);
}

.forecast-day strong {
  font: 1.15rem/1.1 var(--serif);
}

.forecast-day small {
  font-size: .68rem;
  color: #5f7075;
}

.weather-source {
  color: #5f7075;
  font-size: .78rem;
  margin: 20px 0 0;
  max-width: 70ch;
}

@media (max-width: 900px) {
  .weather-grid { grid-template-columns: repeat(2, 1fr); }
  .forecast-strip { grid-template-columns: repeat(3, 1fr); }
}

@media (max-width: 760px) {
  .weather-panel { padding: 45px 20px 0; }
  .weather-grid { grid-template-columns: repeat(2, 1fr); }
  .forecast-strip { grid-template-columns: repeat(2, 1fr); }
}

/* Live fuel panel on gas.html. Static-readable in the served HTML. */
.gas-panel {
  max-width: 1320px;
  margin: 0 auto;
  padding: 60px 32px 0;
}

.gas-panel h2 {
  font: 2rem/1.1 var(--serif);
  margin: 0 0 14px;
}

.gas-status {
  color: #5f7075;
  font-size: .84rem;
  margin: 0 0 18px;
  max-width: 70ch;
}

.gas-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 1px;
  background: var(--line);
  border: 1px solid var(--line);
  margin: 0;
}

.gas-grid > div {
  background: var(--paper);
  padding: 18px 20px;
}

.gas-grid dt {
  text-transform: uppercase;
  letter-spacing: .14em;
  font-size: .62rem;
  font-weight: 700;
  color: var(--coral);
}

.gas-grid dd {
  margin: 6px 0 0;
  font: 1.5rem/1.1 var(--serif);
}

.gas-trend,
.gas-source {
  color: #5f7075;
  font-size: .78rem;
  margin: 16px 0 0;
  max-width: 74ch;
}

@media (max-width: 760px) {
  .gas-panel { padding: 45px 20px 0; }
  .gas-grid { grid-template-columns: repeat(2, 1fr); }
}

/* Advertising slots. The unsold state is server-rendered and already styled by
   .sponsor-strip; these cover the two states partners.js can swap in. */
.sponsor-strip.is-house {
  align-items: center;
  gap: 22px;
}

.sponsor-strip .house-banner {
  flex: 0 0 auto;
  width: min(280px, 40vw);
  line-height: 0;
}

.sponsor-strip .house-banner img {
  width: 100%;
  height: auto;
  aspect-ratio: 16 / 5;
  object-fit: cover;
}

.sponsor-strip.is-house > div {
  flex: 1 1 auto;
}

.sponsor-strip.is-sold strong {
  color: var(--navy);
}

@media (max-width: 760px) {
  .sponsor-strip.is-house { align-items: flex-start; }
  .sponsor-strip .house-banner { width: 100%; }
}

/* Regional news feed, matching the network standard. The served HTML already
   carries a usable card; script replaces it when the newsroom responds. */
.region-news {
  max-width: 1320px;
  margin: 0 auto;
  padding: 70px 32px 0;
}

.region-news-head {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 6vw;
  align-items: end;
  margin-bottom: 30px;
}

.region-news-head h2 {
  font: clamp(2.2rem, 4vw, 3.4rem)/1 var(--serif);
  margin: 8px 0 0;
}

.region-news-head > p {
  margin: 0;
  color: #5f7075;
  font-size: .86rem;
  line-height: 1.7;
}

.region-news-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1px;
  background: var(--line);
  border: 1px solid var(--line);
}

/* A quiet news day may return one regional card. Let it fill the feed instead
   of exposing the grid background as a large grey phantom card. */
.region-news-grid > .region-news-card:only-child {
  grid-column: 1 / -1;
}

.region-news-card {
  background: var(--paper);
  padding: 26px;
}

.region-news-card.priority {
  border-top: 4px solid var(--coral);
}

.region-news-card > div {
  display: flex;
  justify-content: space-between;
  gap: 16px;
  font-size: .62rem;
  font-weight: 800;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--coral);
}

.region-news-card small {
  color: #5f7075;
  letter-spacing: 0;
  text-transform: none;
  font-weight: 400;
}

.region-news-card h2 {
  font: 1.5rem/1.1 var(--serif);
  margin: 20px 0 10px;
}

.region-news-card p {
  font-size: .88rem;
  color: #4a5b63;
  margin: 0 0 14px;
}

.region-news-card a {
  font-size: .74rem;
  font-weight: 800;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--navy);
}

.network-news-cta {
  background: var(--navy);
  color: #fff;
  padding: 70px max(7vw, 32px);
  margin-top: 70px;
}

.network-news-cta h2 {
  font: clamp(2.2rem, 4vw, 3.4rem)/1 var(--serif);
  margin: 10px 0 18px;
  max-width: 900px;
}

.network-news-cta p:not(.eyebrow) {
  max-width: 760px;
  color: #cdd9dc;
}

.network-news-cta a {
  display: inline-block;
  margin-top: 16px;
  padding: 14px 18px;
  background: var(--coral);
  color: #fff;
  font: 700 .75rem var(--sans);
  letter-spacing: .08em;
  text-transform: uppercase;
  text-decoration: none;
}

@media (max-width: 900px) {
  .region-news-head { grid-template-columns: 1fr; gap: 18px; }
  .region-news-grid { grid-template-columns: 1fr; }
}

@media (max-width: 760px) {
  .region-news { padding: 50px 20px 0; }
  .network-news-cta { padding: 50px 20px; margin-top: 50px; }
}

/* Mobile tap targets. Footer link lists rendered at 19-22px tall, which is
   tight for a thumb; guidance is 44px and 32px is the lenient floor. Padding
   only under 760px, so the desktop footer is unchanged. */
@media (max-width: 760px) {
  .footer-grid a,
  .legal a,
  .source-note a,
  .sponsor-strip a,
  .network-band a {
    display: inline-block;
    padding-top: 11px;
    padding-bottom: 11px;
  }

  .footer-grid > div {
    gap: 0;
  }

  .text-link,
  .hero-actions a {
    display: inline-block;
    padding-top: 11px;
    padding-bottom: 11px;
  }
}

/* Trip fuel calculator. The form is real HTML so the tool is readable without
   JavaScript; only the result block is hidden, because it is output. */
.fuel-calc {
  max-width: 1320px;
  margin: 0 auto;
  padding: 60px 32px 0;
}

.fuel-calc h2 {
  font: clamp(2rem, 3.6vw, 3rem)/1 var(--serif);
  margin: 8px 0 12px;
}

.fuel-calc > p {
  color: #5f7075;
  max-width: 68ch;
  margin: 0 0 22px;
}

.fuel-calc form {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 1px;
  background: var(--line);
  border: 1px solid var(--line);
}

.fuel-calc label {
  background: var(--paper);
  padding: 18px 20px;
  display: grid;
  gap: 8px;
  font-size: .68rem;
  font-weight: 700;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--coral);
}

.fuel-calc input {
  font: 1.25rem var(--serif);
  padding: 10px 12px;
  border: 1px solid var(--line);
  background: #fffdf8;
  color: var(--ink);
  width: 100%;
}

.fuel-calc button {
  grid-column: 1 / -1;
  background: var(--coral);
  color: #fff;
  border: 0;
  padding: 18px 20px;
  font: 700 .78rem var(--sans);
  letter-spacing: .1em;
  text-transform: uppercase;
  text-align: left;
  cursor: pointer;
}

.fuel-calc button:hover { filter: brightness(1.06); }

.fuel-hint {
  color: #5f7075;
  font-size: .76rem;
  margin: 12px 0 0;
}

.fuel-result {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 1px;
  background: var(--line);
  border: 1px solid var(--line);
  border-top: 0;
}

.fuel-result > div {
  background: var(--paper);
  padding: 18px 20px;
}

.fuel-result span {
  display: block;
  font-size: .62rem;
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--coral);
}

.fuel-result b {
  font: 1.5rem/1.1 var(--serif);
  font-weight: 400;
}

.fuel-result .fuel-total {
  background: var(--navy);
}

.fuel-result .fuel-total span { color: var(--sun); }
.fuel-result .fuel-total b { color: #fff; }

@media (max-width: 900px) {
  .fuel-calc form, .fuel-result { grid-template-columns: repeat(2, 1fr); }
}

@media (max-width: 760px) {
  .fuel-calc { padding: 45px 20px 0; }
  .fuel-calc form, .fuel-result { grid-template-columns: 1fr; }
}

/* ---- Section emphasis and grid shading ---------------------------------
   The live console is the most valuable module on the homepage and was
   reading as a continuation of the dark hero above it. The information grids
   were transparent, so they dissolved into the page. Each block now sits on
   its own shade and the console is separated by a hard accent rule. */

/* The console: deepest tone on the page, with an accent rule top and bottom so
   it reads as an instrument panel rather than more hero. */
.live-console {
  background: var(--deep);
  border-top: 5px solid var(--coral);
  border-bottom: 5px solid var(--coral);
  position: relative;
}

.live-console .live-cell strong {
  color: #fff;
}

.live-console .live-cell span {
  color: var(--sun);
}

/* Quick facts: a warmer field so the tiles read as data, with each tile on
   paper. Previously the section and its cells were both transparent. */
.quick-facts {
  background: linear-gradient(180deg, rgba(0, 0, 0, .035), rgba(0, 0, 0, .015));
}

.quick-facts .fact-grid {
  background: var(--line);
  border: 1px solid var(--line);
  gap: 1px;
}

.quick-facts .fact-grid .live-cell {
  background: var(--paper);
  border: 0;
}

.quick-facts .fact-grid .live-cell span {
  color: var(--coral);
}

/* Interior data grids get the same treatment so a reader recognises "this is
   a set of facts" anywhere on the site. */
.weather-grid,
.gas-grid,
.fuel-result {
  background: var(--line);
  border: 1px solid var(--line);
}

.weather-grid > div,
.gas-grid > div,
.fuel-result > div {
  background: var(--paper);
}

/* Pathways sits between two shaded blocks, so it stays on the page tone and
   gets a rule instead. Without this the homepage becomes striped. */
.pathways {
  border-top: 1px solid var(--line);
}

/* ---- The sponsor strip under the live console --------------------------
   Two faults. The strip used space-between across three children, so the
   banner, the copy and the call to action were flung to opposite ends with the
   copy stranded in the middle. And the console carried 90px of padding below
   its status line, so the ad floated away from the block it belongs to.
   Group banner and copy together, push only the CTA right, and close the gap
   so the ad reads as attached to the console rather than orphaned under it. */
.live-console + .sponsor-strip,
.live-console + * > .sponsor-strip {
  margin-top: 0;
  border-top: 0;
}

.live-console {
  padding-bottom: 34px;
}

.sponsor-strip {
  max-width: 1320px;
  margin-inline: auto;
  align-items: center;
  gap: 20px;
}

.sponsor-strip.is-house > div {
  flex: 1 1 auto;
  margin-right: auto;
}

.sponsor-strip.is-house > a:last-child {
  flex: 0 0 auto;
  white-space: nowrap;
}

.sponsor-strip .house-banner {
  flex: 0 0 auto;
}

@media (max-width: 760px) {
  .sponsor-strip.is-house {
    flex-direction: column;
    align-items: flex-start;
    gap: 14px;
  }
  .sponsor-strip.is-house > a:last-child { white-space: normal; }
}

/* Quick-fact tiles are real links, not divs with a click handler, so a crawler
   follows them and middle-click works. Styled to look identical to a plain
   tile, with a clear hover and a visible focus ring for keyboard users. */
a.live-cell {
  text-decoration: none;
  color: inherit;
  transition: background .15s ease, transform .15s ease;
  position: relative;
}

a.live-cell:hover {
  background: var(--cream);
  transform: translateY(-2px);
}

a.live-cell:focus-visible {
  outline: 3px solid var(--coral);
  outline-offset: -3px;
}

a.live-cell::after {
  content: "\2192";
  position: absolute;
  right: 20px;
  bottom: 18px;
  font-size: .9rem;
  color: var(--coral);
  opacity: 0;
  transition: opacity .15s ease, transform .15s ease;
}

a.live-cell:hover::after,
a.live-cell:focus-visible::after {
  opacity: 1;
  transform: translateX(3px);
}

/* ---- History band: photograph behind the wording ------------------------
   The band was a flat gradient, which wasted the single most evocative image
   each site owns. The hero now sits behind the copy as a real <img>, so it
   carries alt text and gets indexed, with a scrim heavy on the left where the
   type sits and light on the right so the dune still reads. */
.history-tease {
  position: relative;
  overflow: hidden;
}

.history-tease > img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center 42%;
}

.history-tease::before {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(90deg, rgba(3, 29, 42, .95) 0%, rgba(3, 29, 42, .82) 38%, rgba(3, 29, 42, .28) 78%, rgba(3, 29, 42, .45) 100%);
}

.history-tease > div {
  position: relative;
  z-index: 1;
}

/* Narrow screens have no room for the copy to sit beside the image, so the
   scrim goes vertical and covers the whole frame. */
@media (max-width: 860px) {
  .history-tease::before {
    background: linear-gradient(180deg, rgba(3, 29, 42, .84), rgba(3, 29, 42, .93));
  }
}

/* Two specificity corrections to the blocks above.
   1. The staggered footed-image margin is written with four selector parts and
      would otherwise beat `.story-media.is-inset`, flinging a small archive
      photograph to the bottom of the card and bleeding it off the edge.
   2. `.quick-facts .fact-grid .live-cell` sets the tile background with three
      classes, so the linked-tile hover written as `a.live-cell:hover` never
      applied. Matched here at equal weight. */
.quick-facts .fact-grid a.live-cell:hover {
  background: var(--cream);
}

/* A named source under a section, so "Apple's own instructions" is a link
   rather than a phrase somebody has to go and search for. */
.story-link {
  display: inline-block;
  margin-top: 16px;
  font-weight: 700;
  font-size: .8rem;
  text-transform: uppercase;
  letter-spacing: .08em;
  color: var(--coral);
  text-underline-offset: 6px;
}

/* Illustrated planning sections must read as one image-and-copy unit. The
   former two-column card grid visually paired each image with its neighbour's
   heading, especially on Camping, Riding, and Rules. */
@media (min-width: 761px) {
  body:is([data-page="camping"], [data-page="riding"], [data-page="permits"], [data-page="safety"], [data-page="history"]) .story-grid {
    grid-template-columns: 1fr;
  }

  body:is([data-page="camping"], [data-page="riding"], [data-page="permits"], [data-page="safety"], [data-page="history"]) .story-card.has-media {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    min-height: 0;
    padding: 0;
  }

  body:is([data-page="camping"], [data-page="riding"], [data-page="permits"], [data-page="safety"], [data-page="history"]) .story-card.has-media .story-media,
  body:is([data-page="camping"], [data-page="riding"], [data-page="permits"], [data-page="safety"], [data-page="history"]) .story-card:nth-child(even).has-media .story-media {
    margin: 0;
  }

  body:is([data-page="camping"], [data-page="riding"], [data-page="permits"], [data-page="safety"], [data-page="history"]) .story-card.has-media .story-media img {
    width: 100%;
    height: 100%;
    min-height: 430px;
    aspect-ratio: auto;
    object-fit: cover;
  }

  body:is([data-page="camping"], [data-page="riding"], [data-page="permits"], [data-page="safety"], [data-page="history"]) .story-card.has-media .story-copy {
    align-self: center;
    padding: 55px;
  }

  body:is([data-page="camping"], [data-page="riding"], [data-page="permits"], [data-page="safety"], [data-page="history"]) .story-card:nth-child(even).has-media .story-media {
    order: 2;
  }

  body:is([data-page="camping"], [data-page="riding"], [data-page="permits"], [data-page="safety"], [data-page="history"]) .story-card:nth-child(even).has-media .story-copy {
    order: 1;
  }

  body:is([data-page="camping"], [data-page="riding"], [data-page="permits"], [data-page="safety"], [data-page="history"]) .story-media figcaption {
    padding: .75rem 55px 0;
  }
}

/* ---- Illustrated cards run full width, image beside their own copy -------
   Replaces the earlier stagger. Staggering stopped two pictures sharing an
   edge but left each image level with the neighbouring card's heading, so the
   page read as though the wrong words sat next to the wrong picture. Giving an
   illustrated card the whole row, with its image beside its own copy, removes
   both problems at once: no two images touch, and nothing is level with
   another card's words. History pages already do this and are left alone. */
@media (min-width: 761px) {
  body:not([data-page="history"]) .story-grid > .story-card.has-media {
    grid-column: 1 / -1;
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    padding: 0;
    min-height: 0;
  }

  body:not([data-page="history"]) .story-card.has-media .story-media {
    margin: 0;
  }

  body:not([data-page="history"]) .story-card.has-media .story-media img {
    width: 100%;
    height: 100%;
    min-height: 420px;
    aspect-ratio: auto;
    object-fit: cover;
  }

  body:not([data-page="history"]) .story-card.has-media .story-copy {
    align-self: center;
    padding: 55px;
  }

  body:not([data-page="history"]) .story-card.has-media .story-copy h2 {
    margin-top: 0;
  }

  /* Alternate which side the picture sits on, so a run of illustrated cards
     does not read as a column of identical slabs. */
  body:not([data-page="history"]) .story-card.has-media:nth-of-type(even) .story-media {
    order: 2;
  }

  body:not([data-page="history"]) .story-card.has-media:nth-of-type(even) .story-copy {
    order: 1;
  }

  body:not([data-page="history"]) .story-card.has-media .story-media figcaption {
    padding: .75rem 55px 0;
  }

  /* An inset archive photograph keeps its true size rather than being cropped
     to fill half a row. */
  body:not([data-page="history"]) .story-card.has-media .story-media.is-inset {
    max-width: none;
    padding: 55px;
    align-self: center;
  }

  body:not([data-page="history"]) .story-card.has-media .story-media.is-inset img {
    min-height: 0;
    height: auto;
    object-fit: contain;
  }

  body:not([data-page="history"]) .story-card.has-media .story-media.is-inset figcaption {
    padding: .75rem 0 0;
  }
}

/* A hairline grid paints its own background and lets the gap show through, so
   any leftover cell renders as a solid grey block. The regional news feed
   carries one card in the served HTML and gains more only when the newsroom
   responds, so the count is variable by design. A trailing odd card spans the
   row, which covers one card, three, five. */
.region-news-grid > .region-news-card:last-child:nth-child(odd) {
  grid-column: 1 / -1;
}

/* Same hairline-grid trap as the news feed. The seven-day strip is a seven
   column grid, and the served HTML carries a single explanatory paragraph
   until the forecast arrives, so six empty cells render as a grey band. Let a
   lone child span the row; once seven day cells exist the rule stops applying. */
.forecast-strip > :only-child {
  grid-column: 1 / -1;
}
