/*
 * Millburn Green dashboard components.
 *
 * Every colour and radius here comes from the theme's tokens. The plugin
 * defines no palette of its own -- if the brand changes, it changes in
 * style.css and theme.json and these components follow.
 *
 * Fallback values are supplied on each var() so a component still renders
 * sensibly if it is ever placed on a site without the child theme active.
 */

.mg-component { margin-block: 28px; }
.mg-loading { color: var(--muted, #65716D); font-size: 14px; }
.mg-error {
  color: var(--flood, #B66A55);
  font-size: 14px;
  border-left: 3px solid var(--flood, #B66A55);
  padding-left: 12px;
}

/* Section heading shared by components ------------------------------------ */
.mg-head { display: flex; align-items: baseline; gap: 14px; flex-wrap: wrap; margin-bottom: 14px; }
.mg-head h3 { font-size: 30px; }
.mg-head .mg-meta { margin-left: auto; color: var(--muted, #65716D); font-size: 12px; }

/* Widget anatomy -- §11 --------------------------------------------------
   The parts every widget on the dashboard is built from, so they stay
   consistent as more are added:

     .mg-w-mark      the icon column         always present, may be empty
     .mg-w-icon      the subject badge       optional
     .mg-w-label     the widget name         14px, uppercase
     .mg-w-value     the headline figure     serif, large
     .mg-w-caption   what qualifies it       12px, title case, regular
     .mg-w-detail    supporting figures      12px, muted

   Any part may be omitted. The label sits ABOVE the value -- it names the
   widget before the number, rather than captioning it afterwards. The icon
   sits to the LEFT of all three, its top level with the label.               */
/* 270px, against the 190px this started at: the icon column plus its gap takes
   80px out of the card, and below roughly this width "71° Partly Cloudy" can
   no longer hold one line. */
.mg-metrics {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(270px, 1fr));
  gap: 20px;
}
.mg-w {
  display: flex;
  align-items: flex-start;   /* the icon's top sits level with the label */
  gap: 16px;
  background: var(--white, #fff);
  border: 1px solid var(--border, #DDE3DE);
  border-radius: var(--radius-md, 12px);
  padding: 10px;
}
/* Fixed width whether or not it holds an icon -- see the note in widget(). */
.mg-w-mark { flex: 0 0 64px; height: 64px; }
.mg-w-icon { width: 64px; height: 64px; display: block; }
.mg-w-body { min-width: 0; }

.mg-w-label {
  color: var(--muted, #65716D);
  font: 600 14px/1.2 var(--font-ui, sans-serif);
  letter-spacing: .08em;
  text-transform: uppercase;
}

/* Serif numerals.
   NOTE: this departs from §3, which specifies Montserrat 500 for the dashboard
   number. Deliberate -- worth reflecting in the style guide so the two do not
   disagree.
   Weight is 400, not 500: Newsreader is loaded at 400 only, and asking for 500
   makes the browser synthesise a fake bold, which smears a serif at 48px. */
.mg-w-value {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0 8px;
  margin-top: 6px;
  font: 400 48px/0.95 var(--font-editorial, Georgia, "Times New Roman", serif);
  color: var(--green-deep, #174F48);
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.01em;
}

/* Half the size of the figure it belongs to. A degree or foot mark set at the
   full 48px reads as another digit; at half it reads as a unit.

   The raise is because the glyph scales with the type: at 48px the degree sits
   near the cap height of the numerals on its own, and shrinking it drops it
   with everything else. 0.42em of its OWN size puts the top back level with
   the figures. */
.mg-w-figure { white-space: nowrap; }
.mg-w-unit {
  font-size: 50%;
  vertical-align: 0.62em;   /* of its own size, so the top sits at cap height */
  letter-spacing: 0;
}

/* Rides alongside the value ("71° Partly Cloudy"), so it needs its own font
   shorthand to escape the 48px serif it sits inside. Title case is
   how the source writes it -- no text-transform, which would mangle "NW" and
   "T-storms" into something the forecaster did not say. */
.mg-w-caption {
  font: 400 12px/1.3 var(--font-ui, sans-serif);
  color: var(--muted, #65716D);
  letter-spacing: 0;
}

.mg-w-detail {
  margin-top: 10px;
  color: var(--muted, #65716D);
  font: 400 12px/1.4 var(--font-ui, sans-serif);
}
.mg-w-detail .mg-w-v { color: var(--ink, #1D2B27); font-variant-numeric: tabular-nums; }
.mg-w-detail .mg-w-sep { margin: 0 8px; opacity: .45; }

/* Semantic accents -- §7: green is the brand colour, not every data category */
.mg-w.is-water  .mg-w-value { color: var(--water, #3295B5); }
.mg-w.is-energy .mg-w-value { color: var(--energy, #C69A45); }
.mg-w.is-flood  .mg-w-value { color: var(--flood, #B66A55); }
.mg-w.is-air    .mg-w-value { color: var(--green, #679B58); }

/* Tables ------------------------------------------------------------------ */
.mg-card { background: var(--white, #fff); border: 1px solid var(--border, #DDE3DE); border-radius: var(--radius-md, 12px); overflow: hidden; }
.mg-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.mg-table { border-collapse: collapse; width: 100%; font-variant-numeric: tabular-nums; }
.mg-table th, .mg-table td { padding: 11px 14px; text-align: right; white-space: nowrap; border-bottom: 1px solid var(--border, #DDE3DE); font-size: 14px; }
.mg-table th:first-child, .mg-table td:first-child { text-align: left; position: sticky; left: 0; background: var(--white, #fff); }
.mg-table thead th {
  font: 600 11px/1.2 var(--font-ui, sans-serif);
  letter-spacing: .08em; text-transform: uppercase;
  color: var(--muted, #65716D);
}
.mg-table tbody tr:last-child td { border-bottom: 0; }
.mg-table tbody tr:hover td, .mg-table tbody tr:hover th { background: #F3F7F3; }
/* No rule under a row link. Every name in the first column is a link, so the
   underline marked the whole column rather than distinguishing anything in it.
   Hover carries the affordance instead. */
.mg-table a { color: inherit; text-decoration: none; }
.mg-table a:hover { color: var(--green-deep, #174F48); }
.mg-na { color: #A9B2AD; font-size: 12px; letter-spacing: .02em; }
.mg-stale { color: var(--energy, #C69A45); }

/* Alerts -- §7 puts risk in terracotta ------------------------------------ */
.mg-alert {
  border: 1px solid var(--flood, #B66A55);
  border-left-width: 5px;
  background: #FBF0EC;
  border-radius: var(--radius-md, 12px);
  padding: 16px 18px;
  margin-bottom: 12px;
}
.mg-alert h4 { margin: 0 0 4px; font: 600 16px/1.3 var(--font-ui, sans-serif); color: #7A3B2C; }
.mg-alert .mg-when { font-size: 13px; color: #8A5344; }
.mg-alert details { margin-top: 8px; }
.mg-alert summary { cursor: pointer; font-size: 13px; color: #7A3B2C; }
.mg-alert pre { white-space: pre-wrap; font: inherit; font-size: 13px; margin: 8px 0 0; }

/* Map -- §14: the base map stays quiet ------------------------------------ */

/* Legend column then map, 20/80.
   1fr/4fr rather than literal 20%/80%: percentages are taken from the full
   width and would add the gap on top, overflowing the container. Fractions
   divide what is left AFTER the gap, so the split stays 20/80 whatever the
   gap is. minmax(0,...) lets the map column shrink below the intrinsic width
   of its own contents, which a grid track otherwise refuses to do. */
/* No gap: the legend and the map are one block, the legend reading as the map's
   own surface carried out to the left rather than a card parked beside it. With
   the gap gone, 1fr/4fr is now literally 20/80 of the width. */
.mg-map-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 4fr);
  gap: 0;
}
.mg-map-aside {
  background: var(--white, #fff);
  border: 1px solid var(--border, #DDE3DE);
  /* Outer corners only. The right edge runs straight into the map. */
  border-radius: var(--radius-md, 12px) 0 0 var(--radius-md, 12px);
  /* No border on the seam -- the map's own left border draws it, and two
     adjacent 1px borders would read as a 2px rule down the middle. */
  border-right: 0;
  padding: 28px;
}
.mg-map-title {
  margin: 0;
  font-size: 26px;          /* smaller than a page h2: the column is narrow */
  line-height: 1.2;
  color: var(--green-deep, #174F48);
}
.mg-map-intro {
  margin: 10px 0 0;
  font: 400 14px/1.55 var(--font-ui, sans-serif);
  color: var(--muted, #65716D);
}

.mg-map {
  /* A stacking context of its own. Leaflet gives its panes z-index 400 and its
     controls 1000, and without this those compete directly with the page --
     the zoom buttons drew over the sticky header, which is only z-index 100.
     Contained here, the whole map sits at 0 and nothing inside it can reach
     past the header again, however Leaflet numbers its internals. */
  position: relative;
  z-index: 0;
  min-height: 400px; height: 400px; width: 100%;
  border-radius: 0 var(--radius-md, 12px) var(--radius-md, 12px) 0;
  overflow: hidden;
  border: 1px solid var(--border, #DDE3DE);
  background: #EAEEE9;
}

/* Below this the legend column is too narrow to read, so it stacks above the
   map at full width. 860px is where 20% of the container stops fitting
   "Weather station -- temperature F" on two lines. */
@media (max-width: 860px) {
  .mg-map-layout { grid-template-columns: 1fr; }
  /* Map first, legend under it. Stacked, the aside was a screen of text before
     you reached the thing it describes. The DOM keeps the aside first, so a
     screen reader still meets the heading before the map; only the visual
     order changes. */
  .mg-map { order: 1; border-radius: var(--radius-md, 12px) var(--radius-md, 12px) 0 0; }
  .mg-map-aside {
    order: 2;
    border-radius: 0 0 var(--radius-md, 12px) var(--radius-md, 12px);
    border-right: 1px solid var(--border, #DDE3DE);
    border-top: 0;
  }
}
.mg-pin {
  position: relative; width: 46px; height: 46px;
  display: flex; align-items: center; justify-content: center;
  font: 600 13px/1 var(--font-ui, sans-serif); color: #fff;
  border-radius: 50% 50% 50% 0; transform: rotate(-45deg);
  border: 2px solid rgba(255,255,255,.92);
  box-shadow: 0 2px 7px rgba(0,0,0,.28); cursor: pointer;
}
.mg-pin span { transform: rotate(45deg); white-space: nowrap; }
.mg-pin.is-gauge { border-radius: 8px 8px 8px 0; background: var(--water, #3295B5); font-size: 12px; }
.mg-pin.is-offline { background: #9AA5A0 !important; }
.leaflet-tooltip.mg-tip {
  font: 13px/1.45 var(--font-ui, sans-serif);
  padding: 11px 13px; border-radius: var(--radius-md, 12px);
  border: 1px solid var(--border, #DDE3DE); background: var(--white, #fff);
  color: var(--ink, #26312C); box-shadow: 0 4px 16px rgba(0,0,0,.16);
}
.mg-tip h4 { margin: 0 0 6px; font: 600 13px/1.3 var(--font-ui, sans-serif); }
.mg-tip table { border-collapse: collapse; }
.mg-tip td { border: 0; padding: 1px 0; font-size: 12.5px; }
.mg-tip td.k { color: var(--muted, #65716D); padding-right: 14px; text-align: left; }
.mg-tip td.v { text-align: right; font-variant-numeric: tabular-nums; }

/* Legend ------------------------------------------------------------------
   Swatch colours are classes, not inline styles. Inline cannot carry a media
   query or a dark-mode override, and hardcoded hex duplicates the tokens --
   so a brand change would have to be chased through the JavaScript. */
.mg-legend { display: flex; gap: 18px; flex-wrap: wrap; margin-top: 12px; font-size: 12px; color: var(--muted, #65716D); }
.mg-legend.is-tight { margin: 0 0 6px; }
/* In the map aside the keys read as a list, not a strip. The column is narrow
   enough that a label wraps, so the swatch aligns to the FIRST line rather
   than centring on the block and floating between the two. */
.mg-legend.is-stacked { flex-direction: column; gap: 10px; margin-top: 20px; align-items: flex-start; }
.mg-legend.is-stacked span { align-items: flex-start; }
.mg-legend.is-stacked i { margin-top: 2px; }
@media (max-width: 860px) {
  .mg-legend.is-stacked { flex-direction: row; gap: 10px 18px; }
  /* The ramp takes its own line. As an ordinary flex item it is sized by its
     content, so a key landed beside it and the bar was squeezed to about half
     the column. */
  .mg-legend.is-stacked .mg-key-scale { flex: 0 0 100%; }
}
.mg-legend span { display: inline-flex; align-items: center; gap: 7px; }
.mg-legend i { width: 12px; height: 12px; border-radius: 50%; display: inline-block; flex: 0 0 auto; }
.mg-legend i.sq { border-radius: 3px; }

.mg-legend i.is-weather { background: var(--green, #679B58); }
.mg-legend i.is-offline { background: #9AA5A0; }

/* The temperature scale, as a ramp rather than one swatch. A weather pin takes
   whichever band its reading falls in -- seven of them -- so a single green dot
   said the amber pins were something other than weather stations.
   Band colours come from TEMP_STOPS in the JS; only the frame is here. */
.mg-key-scale { display: block; }
.mg-key-text { display: block; }
.mg-ramp {
  display: flex;
  height: 8px;
  margin-top: 7px;
  border-radius: 3px;
  overflow: hidden;
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .12);
}
.mg-ramp i { display: block; width: auto; height: 100%; border-radius: 0; }
.mg-ramp-ticks {
  display: flex;
  margin-top: 3px;
  font-size: 9.5px;
  font-variant-numeric: tabular-nums;
  opacity: .8;
}
/* Each tick carries its band's flex weight and pushes its number to the right
   edge, which is the boundary the number actually marks. */
.mg-ramp-ticks span { text-align: right; white-space: nowrap; }
.mg-legend i.is-gauge   { background: var(--water, #3295B5); }
.mg-legend i.is-hi      { background: var(--flood, #B66A55); }
.mg-legend i.is-avg     { background: var(--green, #679B58); }
.mg-legend i.is-lo      { background: var(--water, #3295B5); }
.mg-legend i.is-normal  { background: var(--muted, #65716D); }

/* A chart legend shows a LINE, not a dot: these keys stand for strokes on a
   plot, and the swatch carries the dash pattern too -- which is how a reader
   learns that dashed means the right-hand axis without being told in prose.

   The dash is a gradient, not a dashed border. A 2px dashed border is drawn by
   the browser as near-square segments with no way to set their length, so it
   reads as a row of dots rather than a dash. The gradient states 5 on, 4 off --
   the same stroke-dasharray the chart draws with, so the key and the line it
   labels are the same pattern rather than two guesses at one.

   Colour arrives as `color`, inline or from the class below, and currentColor
   carries it into both the solid fill and the gradient. */
.mg-legend i.ln {
  width: 30px;
  height: 2px;
  border-radius: 0;
  background: currentColor;
}
.mg-legend i.ln.is-dashed {
  background: repeating-linear-gradient(90deg,
              currentColor 0 5px, transparent 5px 9px);
}
.mg-legend i.ln.is-hi     { color: var(--flood, #B66A55); }
.mg-legend i.ln.is-avg    { color: var(--green, #679B58); }
.mg-legend i.ln.is-lo     { color: var(--water, #3295B5); }
.mg-legend i.ln.is-normal { color: var(--muted, #65716D); }

/* Basemap fills, not our data: these are the Protomaps "light" flavour's own
   values. Re-check them if that flavour changes or the library is upgraded, or
   the key quietly stops matching the map.
     park_b  #9CD3B4  parks, reservations, playgrounds -- the saturated green
     water   #80DEEA
   NOT wood_a #D0DED0, which is the pale wash over the whole wooded suburb. It
   covers far more of the map than the parks do, so picking the commonest green
   picks that one -- and it reads as grey. Frequency is not the same as
   meaning. The hairline makes a light fill visible at 12px on a white card. */
.mg-legend i.is-park      { background: #9CD3B4; box-shadow: inset 0 0 0 1px rgba(0,0,0,.14); }
.mg-legend i.is-waterbody { background: #80DEEA; box-shadow: inset 0 0 0 1px rgba(0,0,0,.14); }

/* The chart panel's body is tighter than the table panels': the SVG carries
   its own margins, so the usual padding would double up on three sides. */
.mg-panel.is-chart .mg-panel-body { padding: 14px 16px 6px; }
.mg-chart { display: block; width: 100%; }

/* Footnote ---------------------------------------------------------------- */
.mg-note { margin-top: 10px; font-size: 12.5px; color: var(--muted, #65716D); }

/* Dashboard ground -- §12 ------------------------------------------------- */
body.mg-dashboard { background: var(--dashboard-bg, #F2F4F0); }

@media (max-width: 640px) {
  /* The chart runs edge to edge; only the legend keeps the gutter.
     The SVG already carries its own margins -- 42px on the left for the axis
     labels -- so the body's padding was a second inset on top of that, and on
     a phone the two together took a sixth of the width before the plot began. */
  .mg-panel.is-chart .mg-panel-body { padding-left: 0; padding-right: 0; }
  .mg-panel.is-chart .mg-legend { padding-inline: 16px; }

  /* Two up, not one. Four full-width cards is four screens of scrolling before
     the map, and each one is mostly empty to the right of its number. */
  .mg-metrics { grid-template-columns: repeat(2, 1fr); gap: 12px; }

  /* The icon comes down with the card. At 56px it took more than a third of a
     half-width card, and the text had nowhere to go. */
  .mg-w { gap: 10px; }
  .mg-w-mark { flex-basis: 40px; height: 40px; }
  .mg-w-icon { width: 40px; height: 40px; }

  /* Caption under the figure rather than beside it. Half a phone's width has
     no room for "71 degrees" and "Partly Cloudy" on one line, and wrapping
     them left the caption hanging off the numeral's baseline. */
  .mg-w-value {
    font-size: 34px;
    flex-direction: column;
    align-items: flex-start;
    gap: 2px 0;
  }
  .mg-w-label { font-size: 11px; letter-spacing: .06em; }
  .mg-w-detail { margin-top: 8px; }
  .mg-w-detail .mg-w-sep { margin: 0 5px; }

  .mg-head h3 { font-size: 27px; }
}

/* Panels -- the three widgets below the map ------------------------------- */

/* Three across on a wide screen, stacking as the room runs out. 340px is where
   the forecast's five columns stop fitting; the two tables are wider than that
   and scroll inside their card, which is what .mg-scroll is for. */
.mg-panels {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(340px, 1fr));
  gap: 20px;
  margin-block: 28px;
}
/* The shortcodes emit .mg-component wrappers; they are plumbing, not layout,
   so they pass their grid cell straight through to the panel. */
.mg-panels .mg-component { margin-block: 0; display: flex; }
.mg-panels .mg-component > .mg-panel { flex: 1; }

.mg-panel {
  display: flex;
  flex-direction: column;
  background: var(--white, #fff);
  border: 1px solid var(--border, #DDE3DE);
  border-radius: var(--radius-md, 12px);
  overflow: hidden;
}
.mg-panel-head {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 16px 22px;
  border-bottom: 1px solid var(--border, #DDE3DE);
}
.mg-panel-icon { width: 40px; height: 40px; flex: 0 0 40px; display: block; }
.mg-panel-title {
  margin: 0;
  font: 400 21px/1.2 var(--font-editorial, Georgia, serif);
  color: var(--green-deep, #174F48);
}
/* Title and timestamp stack beside the icon, so the stamp reads as belonging
   to the panel it names rather than floating at the far end of the header. */
.mg-panel-heading { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.mg-panel-meta {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  font: 400 11px/1.3 var(--font-ui, sans-serif);
  color: var(--muted, #65716D);
}
/* Nothing to show there leaves no gap behind it. */
.mg-panel-meta:empty { display: none; }
.mg-live {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 3px 9px;
  border-radius: var(--radius-pill, 999px);
  background: #EAF3E8;
  color: #3F6B36;
  font-weight: 600;
}
.mg-live::before {
  content: "";
  width: 6px; height: 6px;
  border-radius: 50%;
  background: currentColor;
}
/* A reading that has stopped arriving is not "Live". Saying so over a stale
   figure is worse than saying nothing at all. */
.mg-live.is-stale { background: #F7EFDC; color: #8A6A22; }

/* 10px at the sides, not 22. The air table wants 312px and a 390px phone left
   it exactly 312 -- equal enough that sub-pixel rounding still produced a
   scrollbar. The narrower gutter gives it 24px of room instead of none. */
.mg-panel-body { padding: 18px 10px; flex: 1; }
.mg-panel-body .mg-note { margin: 12px 0 0; }
/* Tighter than a full-width table: these sit in a third of the page and the
   air panel carries nine columns, so every pixel of padding costs a column. */
.mg-panel-body .mg-table th,
.mg-panel-body .mg-table td { padding: 10px 9px; font-size: 13px; }
.mg-panel-body .mg-table thead th { font-size: 10px; letter-spacing: .05em; }
.mg-panel-body .mg-table th:first-child,
.mg-panel-body .mg-table td:first-child { padding-left: 0; }
.mg-panel-body .mg-table td:last-child,
.mg-panel-body .mg-table th:last-child { padding-right: 0; }

.mg-panel-foot { padding: 4px 10px 16px; }
.mg-panel-foot a, .mg-expand {
  font: 600 14px/1.2 var(--font-ui, sans-serif);
  color: var(--green-deep, #174F48);
  text-decoration: none;
  background: none; border: 0; padding: 0; cursor: pointer;
}
.mg-panel-foot a span { margin-left: 6px; }

/* The expand control points down because it opens the rest of the list in
   place; the forecast's arrow points right because that one leaves the page.
   One chevron, flipped by the expanded state, so the two directions cannot
   drift apart the way two glyphs would. */
.mg-expand { display: inline-flex; align-items: center; gap: 7px; }
.mg-chev {
  width: 14px; height: 14px; flex: 0 0 auto;
  fill: none; stroke: currentColor; stroke-width: 1.9;
  stroke-linecap: round; stroke-linejoin: round;
  transition: transform .18s ease;
}
.mg-panel.is-expanded .mg-chev { transform: rotate(180deg); }
@media (prefers-reduced-motion: reduce) { .mg-chev { transition: none; } }
/* The timestamp, wherever a panel puts it. A panel whose source is too slow
   for "Live" to mean anything moves this to the footer instead of wearing a
   pill; it should not change size on the way down. */
.mg-panel-when {
  font: 400 11px/1.3 var(--font-ui, sans-serif);
  color: var(--muted, #65716D);
}
.mg-panel-foot a:hover, .mg-expand:hover { text-decoration: underline; }

/* Forecast strip --------------------------------------------------------- */
.mg-fc { display: flex; gap: 4px; text-align: center; }
.mg-fc-day { flex: 1 1 0; min-width: 0; padding: 4px 2px; }
.mg-fc-name { font: 600 13px/1.2 var(--font-ui, sans-serif); color: var(--ink, #1D2B27); }
.mg-fc-date { margin-top: 2px; font: 400 11px/1.2 var(--font-ui, sans-serif); color: var(--muted, #65716D); }
.mg-fc-temp { margin-top: 6px; font: 400 17px/1.2 var(--font-editorial, Georgia, serif); font-variant-numeric: tabular-nums; }
.mg-fc-temp .hi { color: var(--ink, #1D2B27); }
.mg-fc-temp .lo { color: var(--muted, #65716D); }
.mg-fc-cond { margin-top: 3px; font: 400 10.5px/1.3 var(--font-ui, sans-serif); color: var(--muted, #65716D); }

/* Drawn, not a sprite sheet -- see wxIcon(). Colour comes from the tokens, so
   a palette change carries into the icons with nothing to re-export. */
.mg-wx { width: 38px; height: 38px; margin: 8px auto 0; display: block; }
.mg-wx circle, .mg-wx .cl { fill: var(--energy, #C69A45); stroke: none; }
.mg-wx .cl { fill: #C9D2CC; }
.mg-wx .sm { fill: var(--energy, #C69A45); }
.mg-wx .ray { stroke: var(--energy, #C69A45); stroke-width: 2.1; stroke-linecap: round; fill: none; }
.mg-wx .drop { stroke: var(--water, #3295B5); stroke-width: 2.1; stroke-linecap: round; fill: none; }
.mg-wx .bolt { fill: var(--energy, #C69A45); }
.mg-wx.is-fog .drop { stroke: #AEB8B2; }

/* Rows beyond the featured three are in the table from the start, just folded
   away -- expanding costs no request and keeps the scroll position. */
.mg-panel .mg-table tr.is-extra { display: none; }
/* A caveat that only applies to the full list travels with it. Three
   hand-picked stations are not what "may briefly go offline" is warning about,
   and a collapsed panel is short enough that the note dominated it. */
.mg-panel .mg-note.is-onexpand { display: none; }
.mg-panel.is-expanded .mg-note.is-onexpand { display: block; }
.mg-panel.is-expanded .mg-table tr.is-extra { display: table-row; }
.mg-expand .on-expanded { display: none; }
.mg-panel.is-expanded .mg-expand .on-collapsed { display: none; }
.mg-panel.is-expanded .mg-expand .on-expanded { display: inline; }

/* Scroll shadows on the panel tables.
   The air panel carries nine columns and needs about 750px; in a third of the
   page it gets under 400. It scrolls, and without this it just looks cut off.
   background-attachment mixes local and scroll so the shadow appears only on
   the side there is more table, and fades out at each end -- no JS, no resize
   listener, and it stays correct if a column is ever added. */
.mg-panel-body .mg-scroll {
  background:
    linear-gradient(to right, var(--white, #fff) 30%, rgba(255,255,255,0)) left center,
    linear-gradient(to left,  var(--white, #fff) 30%, rgba(255,255,255,0)) right center,
    radial-gradient(farthest-side at 0 50%,   rgba(23,79,72,.13), rgba(23,79,72,0)) left center,
    radial-gradient(farthest-side at 100% 50%, rgba(23,79,72,.13), rgba(23,79,72,0)) right center;
  background-repeat: no-repeat;
  background-size: 34px 100%, 34px 100%, 13px 100%, 13px 100%;
  background-attachment: local, local, scroll, scroll;
}
