/* The Calendar tool — /calendar.
   Ported from the 3.0 kit's Tools.dc.html, whose Calendar screen begins at line 441.

   Loaded via yield :page_stylesheets, not on every page — a month grid has nothing to
   say to any other surface.

   Everything here resolves through --zw-* tokens. The category palette is the one piece
   that deviates from the kit on purpose; see the note above --zw-cal-tone below. */

/* The page matches the site header exactly rather than the kit's 1440px tool measure.
   The header is `max-w-7xl` with `px-4 sm:px-6 lg:px-8`, and a tool surface wider than
   the menu above it reads as a broken page rather than a wide one. Mirrored here as
   values rather than shared utilities so the two can be compared at a glance — the
   system test measures both and fails if they drift. */
.zw-cal-page {
  width: 100%;
  max-width: 80rem; /* Tailwind max-w-7xl, the site header's measure */
  margin: 0 auto;
  padding: 28px 1rem 56px; /* px-4 */
}

@media (min-width: 640px) {
  .zw-cal-page { padding-inline: 1.5rem; } /* sm:px-6 */
}

@media (min-width: 1024px) {
  .zw-cal-page { padding-block: 44px 72px; padding-inline: 2rem; } /* lg:px-8 */
}

/* --- masthead -------------------------------------------------------------- */

.zw-cal-title {
  font-family: var(--zw-font-serif);
  font-size: 32px;
  font-weight: 600;
  letter-spacing: -0.015em;
  line-height: 1.15;
  color: var(--zw-ink);
  margin: 0 0 6px;
}

.zw-cal-dek {
  margin: 0 0 26px;
  font-size: 15px;
  line-height: 1.6;
  color: var(--zw-muted);
  max-width: 620px;
}

/* --- toolbar --------------------------------------------------------------- */

.zw-cal-toolbar {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 320px;
  gap: 44px;
  align-items: center;
  margin-bottom: 18px;
}

.zw-cal-toolbar__bar {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
}

.zw-cal-monthname {
  font-size: 22px;
  font-weight: 600;
  letter-spacing: -0.015em;
  color: var(--zw-ink);
  margin: 0;
}

.zw-cal-nav { display: flex; gap: 1px; }

.zw-cal-nav__button {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  font-size: 16px;
  line-height: 1;
  border-radius: var(--zw-radius-xs);
  text-decoration: none;
  color: var(--zw-quiet);
  transition: background var(--dur-2) var(--zw-ease-out), color var(--dur-2) var(--zw-ease-out);
}

.zw-cal-nav__button:hover {
  background: var(--zw-border-warm-grid);
  color: var(--zw-ink);
}

.zw-cal-viewtoggle { margin-left: auto; }

/* --- shell ----------------------------------------------------------------- */

.zw-cal-shell {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 320px;
  gap: 44px;
  align-items: start;
}

.zw-cal-main { min-width: 0; }

/* Below the sidebar's breakpoint the calendar is the page and the panel stacks under it.
   A 320px column beside a seven-column grid stops working long before phone width. */
@media (max-width: 1023px) {
  .zw-cal-toolbar,
  .zw-cal-shell { grid-template-columns: minmax(0, 1fr); gap: 24px; }
  .zw-cal-toolbar__bar { width: 100%; }
}

/* --- the month grid --------------------------------------------------------- */

.zw-cal-month {
  background: var(--zw-surface);
  border: 1px solid var(--zw-border-warm-2);
  border-radius: var(--zw-radius-md);
  box-shadow: 0 1px 2px rgba(28, 28, 30, 0.04);
  overflow: hidden;
}

.zw-cal-weekdays {
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  border-bottom: 1px solid var(--zw-border-warm-inner);
}

.zw-cal-weekdays span {
  padding: 10px 12px;
  font-size: 12px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--zw-muted);
}

/* Each week is its own grid so a spanning bar can be positioned by column within it.
   The vertical rules are a repeating gradient rather than borders on cells, because the
   cells are not elements — the day number, the bars and the chips are all placed
   directly into this one grid. */
.zw-cal-week {
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  grid-auto-rows: min-content;
  row-gap: 5px;
  padding: 8px 0 10px;
  min-height: 104px;
  background-image: repeating-linear-gradient(
    to right,
    transparent 0,
    transparent calc(100% / 7 - 1px),
    var(--zw-border-warm-grid) calc(100% / 7 - 1px),
    var(--zw-border-warm-grid) calc(100% / 7)
  );
}

.zw-cal-week + .zw-cal-week { border-top: 1px solid var(--zw-border-warm-grid); }

.zw-cal-daynum {
  padding: 2px 8px;
  font-size: 13px;
  color: var(--zw-muted);
}

/* Days belonging to the neighbouring month. They still carry events, so they are dimmed
   rather than blanked. */
.zw-cal-daynum--outside { color: var(--zw-quiet); }

/* Today is the ACTION BLUE by the owner's decision. It is the one mark on the grid that
   is pure wayfinding rather than a category, so it does not compete with the chips — and
   nothing about it is clickable, which is the usual reason blue is reserved. */
.zw-cal-today {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 22px;
  height: 22px;
  padding: 0 5px;
  background: var(--zw-blue-700);
  border-radius: var(--zw-radius-pill);
  font-size: 13px;
  font-weight: 600;
  color: #ffffff;
}

/* --- category palette -------------------------------------------------------
   The kit designs four categories and Event::CATEGORIES has nine, so five tones are
   drawn from the same muted --zw-pin-* / --zw-tool-* family rather than invented.

   Two deliberate departures from the kit:

   1. No ACTION BLUE. The kit gives Repair #336699. The map already moved off it onto
      --zw-pin-slate, and while a chip *is* clickable — unlike a pin — blue in 3.0 means
      "this is the action". A grid where a third of the chips are blue says nothing is.

   2. Text is a darkened ink, not the tone. The kit puts its tone directly on its tint,
      which fails contrast for two of its own four categories (Swap #a68a3f on #f8f2e3 is
      2.9:1, Drive is 3.6:1) — at 12px, on the smallest text on the page. This follows the
      pattern brand_tokens.css already established with --zw-tool-*-ink: the tone carries
      the dot and the accent, a darker ink carries the label. */

.zw-cal-cat--webinar    { --zw-cal-tone: var(--zw-tool-wiki);    --zw-cal-tint: var(--zw-tool-wiki-tint);    --zw-cal-ink: var(--zw-tool-wiki-ink); }
.zw-cal-cat--workshop   { --zw-cal-tone: var(--zw-tool-calendar); --zw-cal-tint: var(--zw-tool-calendar-tint); --zw-cal-ink: var(--zw-tool-clay); }
.zw-cal-cat--repair     { --zw-cal-tone: var(--zw-pin-slate);    --zw-cal-tint: #eff3f7;                     --zw-cal-ink: #3f5c78; }
.zw-cal-cat--swap       { --zw-cal-tone: var(--zw-pin-ochre);    --zw-cal-tint: var(--zw-sand-tint);         --zw-cal-ink: #6b5626; }
.zw-cal-cat--dropoff    { --zw-cal-tone: var(--zw-pin-moss);     --zw-cal-tint: #eef4f0;                     --zw-cal-ink: #3a6150; }
.zw-cal-cat--tour       { --zw-cal-tone: var(--zw-green-600);    --zw-cal-tint: var(--zw-green-50);          --zw-cal-ink: var(--zw-green-700); }
.zw-cal-cat--cleanup    { --zw-cal-tone: var(--zw-moss);         --zw-cal-tint: #f0f4ec;                     --zw-cal-ink: #44633a; }
.zw-cal-cat--policy     { --zw-cal-tone: var(--zw-pin-violet);   --zw-cal-tint: var(--zw-tool-actions-tint); --zw-cal-ink: #5c4a7a; }
.zw-cal-cat--fundraiser { --zw-cal-tone: var(--zw-base);         --zw-cal-tint: #edf2ef;                     --zw-cal-ink: var(--zw-base); }
.zw-cal-cat--other      { --zw-cal-tone: var(--zw-muted);        --zw-cal-tint: var(--zw-border-warm-grid);  --zw-cal-ink: var(--zw-ink-2); }

/* --- bars and chips ---------------------------------------------------------- */

/* A multi-day event. Square ends where it continues into an adjacent week, rounded where
   it genuinely begins or ends — so the shape itself says whether there is more. */
.zw-cal-bar {
  display: flex;
  align-items: center;
  gap: 5px;
  height: 22px;
  margin: 0 4px;
  padding: 0 8px;
  background: var(--zw-cal-tint);
  border: none;
  border-radius: var(--zw-radius-xs);
  font-size: 12px;
  font-weight: 600;
  color: var(--zw-cal-ink);
  white-space: nowrap;
  overflow: hidden;
  cursor: pointer;
  text-align: left;
  transition: box-shadow var(--dur-2) var(--zw-ease-out), opacity var(--dur-2) var(--zw-ease-out);
}

.zw-cal-bar[data-continues-before="true"] {
  margin-left: 0;
  border-top-left-radius: 0;
  border-bottom-left-radius: 0;
}

.zw-cal-bar[data-continues-after="true"] {
  margin-right: 0;
  border-top-right-radius: 0;
  border-bottom-right-radius: 0;
}

.zw-cal-bar__label { overflow: hidden; text-overflow: ellipsis; }
.zw-cal-bar__arrow { opacity: 0.55; flex: none; }
.zw-cal-bar__arrow--end { margin-left: auto; }

.zw-cal-chip {
  display: flex;
  align-items: center;
  gap: 5px;
  margin: 0 4px;
  padding: 4px 8px;
  background: var(--zw-cal-tint);
  border: none;
  border-radius: var(--zw-radius-xs);
  font-size: 12px;
  color: var(--zw-cal-ink);
  overflow: hidden;
  white-space: nowrap;
  cursor: pointer;
  text-align: left;
  transition: box-shadow var(--dur-2) var(--zw-ease-out), opacity var(--dur-2) var(--zw-ease-out);
}

.zw-cal-chip__dot {
  width: 5px;
  height: 5px;
  flex: none;
  border-radius: var(--zw-radius-pill);
  background: var(--zw-cal-tone);
}

.zw-cal-chip__label { overflow: hidden; text-overflow: ellipsis; }

.zw-cal-bar:hover,
.zw-cal-chip:hover { box-shadow: inset 0 0 0 1px var(--zw-cal-tone); }

/* Selection has to read on both halves of a split bar at once, so it is a ring rather
   than a background change — a filled state would fight the category tint. */
.zw-cal-bar[data-selected="true"],
.zw-cal-chip[data-selected="true"],
.zw-cal-row[data-selected="true"] { box-shadow: inset 0 0 0 2px var(--zw-cal-tone); }

/* A day that has passed. The month still shows it — that is what a month is — but it
   steps back so the upcoming days carry the page. */
.zw-cal-bar[data-past="true"],
.zw-cal-chip[data-past="true"],
.zw-cal-row[data-past="true"] { opacity: 0.55; }

/* --- the list view ------------------------------------------------------------ */

.zw-cal-list {
  background: var(--zw-surface);
  border: 1px solid var(--zw-border-warm-2);
  border-radius: var(--zw-radius-md);
  box-shadow: 0 1px 2px rgba(28, 28, 30, 0.04);
  overflow: hidden;
}

.zw-cal-row {
  width: 100%;
  display: grid;
  grid-template-columns: 88px minmax(0, 1fr) auto;
  gap: 18px;
  align-items: center;
  padding: 16px 20px;
  background: none;
  border: none;
  border-bottom: 1px solid var(--zw-border-warm-inner);
  cursor: pointer;
  text-align: left;
  transition: background var(--dur-2) var(--zw-ease-out);
}

.zw-cal-row:last-child { border-bottom: none; }
.zw-cal-row:hover { background: var(--zw-surface-warm); }

.zw-cal-row__date { display: grid; gap: 1px; }

.zw-cal-row__dow {
  font-size: 12px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--zw-muted);
}

.zw-cal-row__day {
  font-size: 17px;
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--zw-cal-ink);
}

.zw-cal-row__body { display: grid; gap: 3px; min-width: 0; }

.zw-cal-row__title {
  display: flex;
  align-items: center;
  gap: 7px;
  font-size: 16px;
  font-weight: 600;
  color: var(--zw-ink);
}

.zw-cal-row__sub { font-size: 14px; line-height: 1.45; color: var(--zw-quiet); }

.zw-cal-row__meta {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 13px;
  color: var(--zw-muted);
  white-space: nowrap;
}

.zw-cal-list__empty { margin: 0; padding: 24px 20px; font-size: 14px; color: var(--zw-quiet); }

/* --- empty state + footnote ------------------------------------------------------ */

/* A month with nothing on it still renders a grid — the note sits beside the calendar
   rather than replacing it. */
.zw-cal-empty,
.zw-cal-footnote {
  margin-top: 18px;
  padding: 14px 16px;
  background: var(--zw-paper-3);
  border: 1px solid var(--zw-border-warm);
  border-radius: var(--zw-radius-md);
  display: flex;
  gap: 14px;
  flex-wrap: wrap;
  align-items: center;
  font-size: 14px;
  line-height: 1.5;
  color: var(--zw-muted);
}

.zw-cal-empty__link { margin-left: auto; font-weight: 600; color: var(--zw-ink); }

.zw-cal-footnote__actions { margin-left: auto; display: flex; gap: 8px; flex-wrap: wrap; }

.zw-cal-footnote__button {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 7px 13px;
  font-size: 13px;
  font-weight: 600;
  color: var(--zw-ink-2);
  background: var(--zw-surface);
  border: 1px solid var(--zw-border-warm-2);
  border-radius: var(--zw-radius-pill);
  text-decoration: none;
  white-space: nowrap;
  transition: background var(--dur-2) var(--zw-ease-out), border-color var(--dur-2) var(--zw-ease-out);
}

.zw-cal-footnote__button:hover {
  background: var(--zw-border-warm-grid);
  border-color: var(--zw-border-warm-soft);
  color: var(--zw-ink);
}

/* --- the sidebar ------------------------------------------------------------------ */

.zw-cal-aside {
  position: sticky;
  top: 76px;
  display: grid;
  gap: 12px;
  align-self: start;
}

@media (max-width: 1023px) {
  .zw-cal-aside { position: static; }
}

/* The card shell moved to ToolCardComponent (.zw-tool-card): the Actions tool had
   hand-rolled the same five declarations, so it is a component now rather than a shape
   two stylesheets each keep their own copy of. The __head/__kind/__eyebrow children below
   stay here — they are this panel's contents, not the card. */

.zw-cal-panel[hidden] { display: none; }

.zw-cal-panel__head { display: flex; align-items: baseline; gap: 10px; }

.zw-cal-panel__kind { font-size: 13px; font-weight: 600; color: var(--zw-muted); }

.zw-cal-panel__eyebrow {
  font-size: 13px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--zw-muted);
}

.zw-cal-panel__close {
  margin-left: auto;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  padding: 0;
  font-size: 15px;
  line-height: 1;
  background: none;
  border: none;
  border-radius: var(--zw-radius-xs);
  cursor: pointer;
  color: var(--zw-muted);
  transition: background var(--dur-2) var(--zw-ease-out), color var(--dur-2) var(--zw-ease-out);
}

.zw-cal-panel__close:hover { background: var(--zw-border-warm-grid); color: var(--zw-ink); }

.zw-cal-panel__title {
  font-size: 20px;
  font-weight: 600;
  letter-spacing: -0.015em;
  line-height: 1.25;
  color: var(--zw-ink);
  margin: 8px 0 10px;
}

.zw-cal-panel__facts {
  display: grid;
  gap: 7px;
  margin: 0;
  padding-bottom: 14px;
  border-bottom: 1px solid var(--zw-border-warm-inner);
}

.zw-cal-panel__facts > div { display: flex; gap: 9px; font-size: 14px; color: var(--zw-ink-2); }
.zw-cal-panel__facts dt { flex: none; width: 58px; color: var(--zw-muted); }
.zw-cal-panel__facts dd { margin: 0; }
.zw-cal-panel__facts > div[hidden] { display: none; }

.zw-cal-panel__desc[hidden] { display: none; }
.zw-cal-panel__desc { margin: 14px 0 0; font-size: 15px; line-height: 1.55; color: var(--zw-muted); }

.zw-cal-panel__actions { margin-top: 16px; display: grid; gap: 8px; }

/* The one place on this page that is genuinely an action, and therefore the one place
   that is allowed to be the ACTION BLUE. */
.zw-cal-panel__rsvp {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 40px;
  font-size: 14px;
  font-weight: 600;
  background: var(--zw-blue-600);
  color: #ffffff;
  border: 1px solid transparent;
  border-radius: var(--zw-radius-sm);
  cursor: pointer;
  text-decoration: none;
  transition: background var(--dur-2) var(--zw-ease-out);
}

.zw-cal-panel__rsvp:hover { background: var(--zw-blue-700); }
.zw-cal-panel__rsvp[hidden] { display: none; }

.zw-cal-panel__going { font-size: 13px; color: var(--zw-quiet); text-align: center; }

.zw-cal-panel__links { margin-top: 14px; display: flex; gap: 14px; font-size: 13px; }

.zw-cal-panel__hint {
  margin: 16px 0 0;
  padding-top: 14px;
  border-top: 1px solid var(--zw-border-warm-inner);
  font-size: 13px;
  line-height: 1.55;
  color: var(--zw-quiet);
}

/* --- next up ------------------------------------------------------------------------ */

.zw-cal-nextup { margin-top: 14px; display: grid; gap: 2px; }

.zw-cal-nextup__row {
  display: grid;
  grid-template-columns: 52px minmax(0, 1fr);
  gap: 12px;
  align-items: baseline;
  padding: 11px 10px;
  margin: 0 -10px;
  background: none;
  border: none;
  border-radius: var(--zw-radius-sm);
  cursor: pointer;
  text-align: left;
  transition: background var(--dur-2) var(--zw-ease-out);
}

.zw-cal-nextup__row:hover { background: var(--zw-surface-warm); }

.zw-cal-nextup__day {
  font-size: 13px;
  font-weight: 600;
  color: var(--zw-cal-ink);
  white-space: nowrap;
}

.zw-cal-nextup__body { display: grid; gap: 2px; min-width: 0; }
.zw-cal-nextup__title { font-size: 15px; font-weight: 600; color: var(--zw-ink); }
.zw-cal-nextup__sub { font-size: 13px; line-height: 1.45; color: var(--zw-quiet); }
.zw-cal-nextup__empty { margin: 14px 0 0; font-size: 13px; color: var(--zw-quiet); }

/* --- featured -------------------------------------------------------------------
   Emphasis only: nothing sorts, filters or pins on this. A featured entry swaps the
   usual tint background for a filled one with white text, so it lifts off the grid
   without introducing a colour. Featuring therefore costs no new token and cannot
   smuggle the ACTION BLUE onto a chip.

   The fill is --zw-cal-ink, NOT --zw-cal-tone. The tone is the dot's colour, tuned to
   read against a pale tint, and white text fails on two of the nine: workshop
   (#a68a3f, 3.2:1) and webinar (#5c7d9e, 4.0:1). The ink is the darkened variant each
   category already declares for exactly this reason, and white clears 4.5:1 on all nine.
   Filling with the tone would have repeated the contrast mistake this file criticises
   the kit for a hundred lines further up.

   A ring or a dot was the alternative and was rejected: the chip is 12px in a dense
   grid, where a 1px ring is close to invisible. */

.zw-cal-chip--featured,
.zw-cal-bar--featured {
  background: var(--zw-cal-ink);
  color: #ffffff;
}

.zw-cal-chip--featured .zw-cal-chip__dot { background: #ffffff; }
.zw-cal-bar--featured .zw-cal-bar__arrow { opacity: 0.75; }

/* Selection still has to read on a filled chip, where an inset ring in the same tone
   would vanish. */
.zw-cal-chip--featured[data-selected="true"],
.zw-cal-bar--featured[data-selected="true"] {
  box-shadow: inset 0 0 0 2px var(--zw-ink);
}

/* Featured has to read the same in both views. The grid fills the chip; a pale pill in the
   list was the same state whispered, easy to miss entirely. The row now carries an accent
   edge and a filled tag, in the category's own ink so no new colour appears. */
.zw-cal-row--featured {
  background: var(--zw-cal-tint);
  box-shadow: inset 3px 0 0 var(--zw-cal-ink);
}

.zw-cal-row--featured:hover { background: var(--zw-cal-tint); }

.zw-cal-row__featured {
  margin-left: 6px;
  padding: 2px 8px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: #ffffff;
  background: var(--zw-cal-ink);
  border-radius: var(--zw-radius-pill);
  white-space: nowrap;
}

/* --- sponsors in the detail panel -------------------------------------------------
   The same "Supported by" the event page shows, so an event reads the same on both. */

/* No border-top here. The facts block above already draws one, and with an empty
   description between them the two rules rendered as a double hairline with a gap. One
   separator, owned by the block above it. */
.zw-cal-panel__orgs {
  margin-top: 14px;
  display: grid;
  gap: 4px;
}

.zw-cal-panel__orgs[hidden] { display: none; }

/* Roles after the first need their own breathing room, not another rule. */
.zw-cal-panel__orgs ul + .zw-cal-panel__orgs-label { margin-top: 10px; }

.zw-cal-panel__orgs-label {
  font-size: 12px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--zw-muted);
}

.zw-cal-panel__orgs ul {
  margin: 8px 0 0;
  padding: 0;
  list-style: none;
  display: grid;
  gap: 4px;
  font-size: 14px;
  color: var(--zw-ink-2);
}

/* --- the recurring marker ---------------------------------------------------------
   The kit's ↻. Quiet on purpose: it says "this happens again", which is context rather
   than an instruction, so it must not compete with the event's name. */

.zw-cal-chip__repeat,
.zw-cal-row__repeat {
  flex: none;
  margin-left: auto;
  opacity: 0.6;
  font-size: 11px;
  line-height: 1;
}

.zw-cal-bar .zw-cal-chip__repeat { margin-left: 6px; }

/* --- the submission form ------------------------------------------------------- */

.zw-cal-field {
  width: 100%;
  margin-top: 6px;
  padding: 9px 12px;
  font-size: 15px;
  color: var(--zw-ink);
  background: var(--zw-surface);
  border: 1px solid var(--zw-border-warm-2);
  border-radius: var(--zw-radius-sm);
}

.zw-cal-field:focus {
  outline: none;
  border-color: var(--zw-blue-700);
  box-shadow: 0 0 0 3px var(--zw-tool-wiki-tint);
}

/* --- programs ---------------------------------------------------------------------
   A season the month's events sit inside, so it reads as ground rather than as another
   event: no category tone, no dot, and a hairline instead of a fill. It is a link — it
   leaves for the program's own page — so the label carries the underline on hover that
   every other link on the page does. */

.zw-cal-bar--program {
  height: 17px;
  font-size: 11px;
  font-weight: 500;
  background: var(--zw-paper-3);
  box-shadow: inset 0 0 0 1px var(--zw-border-warm-2);
  color: var(--zw-ink-2);
  text-decoration: none;
}

.zw-cal-bar--program:hover {
  background: var(--zw-surface-warm);
  color: var(--zw-ink);
}

.zw-cal-bar--program:hover .zw-cal-bar__label { text-decoration: underline; }

.zw-cal-more-programs {
  padding: 2px 10px;
  font-size: 11px;
  color: var(--zw-quiet);
}

.zw-cal-row--program {
  text-decoration: none;
  background: var(--zw-paper-3);
}

.zw-cal-row--program .zw-cal-row__dow { color: var(--zw-quiet); }
.zw-cal-row--program .zw-cal-row__meta { color: var(--zw-blue-700); font-weight: 600; }
.zw-cal-row--program:hover .zw-cal-row__title { text-decoration: underline; }
