/* ==========================================================================
   Where the numbers come from.

   Only what data-sources.html needs beyond components.css. The page header,
   the section rules, the banners, the data table and the empty states are all
   the shared ones.

   Two deliberate decisions run through this file.

   First, no thermal-ramp colour. Teal, amber, violet and signal are the map's
   legend on this site — they mean operational, under construction, proposed
   and "a resident reported something". A dataset being two months old is none
   of those, and borrowing the legend's colours for it would put a second
   meaning into a palette the map then has to contradict. Freshness uses the UI
   role tokens instead: --success, --warning, --danger. Those already exist for
   exactly this, and they are the same green/amber/red a reader expects from a
   status light.

   Second, the state is never carried by colour alone. Every flag prints the
   word — Current, Refresh due, Stale, No date in the file — and the number of
   days beside it. The colour is a second channel, not the channel.
   ========================================================================== */

/* The page header already carries a heavy rule under it, so the tally opens
   flush against it rather than adding a second gap. */
.ds-lede {
  padding-top: 0;
}

.ds-lede__note {
  margin: var(--space-4) 0 0;
  max-width: var(--container-narrow);
}

/* --------------------------------------------------------------------------
   The tally

   Six figures across the top: how many files, how many stale, how many
   undated, the oldest clock, and how much JSON this page read to say so. All
   of them are computed in the browser, so the tally cannot disagree with the
   cards below it.
   -------------------------------------------------------------------------- */

.ds-tally {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-3);
  margin-top: var(--space-5);
}

@media (min-width: 700px) {
  .ds-tally {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: var(--space-4);
  }
}

@media (min-width: 1100px) {
  .ds-tally {
    grid-template-columns: repeat(6, minmax(0, 1fr));
  }
}

.ds-tally__item {
  border-top: var(--rule-heavy) solid var(--border-strong);
  padding-top: var(--space-3);
}

.ds-tally__item--current {
  border-top-color: var(--success);
}

.ds-tally__item--due {
  border-top-color: var(--warning);
}

.ds-tally__item--stale {
  border-top-color: var(--danger);
}

.ds-tally__item--undated {
  border-top-color: var(--text-subtle);
}

.ds-tally__value {
  margin: 0 0 var(--space-1);
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
  font-size: var(--text-xl);
  font-weight: var(--weight-semibold);
  letter-spacing: var(--tracking-tight);
  color: var(--text);
  /* "3.4 MB" and six-digit counts are the widest things here. Let them break
     rather than force the grid column open on a 375px screen. */
  overflow-wrap: anywhere;
}

.ds-tally__label {
  margin: 0;
  font-family: var(--font-sans);
  font-size: var(--text-sm);
  line-height: var(--leading-snug);
  color: var(--text-muted);
}

/* --------------------------------------------------------------------------
   Dataset cards

   One card per file. A card is a single block on purpose: the path, what the
   file is, what it is used for, where it came from and how old it is are one
   claim, and splitting them into columns would let a later redesign drop the
   half that makes the other half checkable.
   -------------------------------------------------------------------------- */

.ds-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-5);
  margin-top: var(--space-5);
}

@media (min-width: 900px) {
  .ds-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--space-6);
  }
}

.ds-card {
  border: var(--border-width) solid var(--border);
  border-left: var(--rule-heavy) solid var(--border-strong);
  border-radius: var(--radius-md);
  background: var(--bg-raised);
  padding: var(--space-4);
  box-shadow: var(--shadow-sm);
}

@media (min-width: 700px) {
  .ds-card {
    padding: var(--space-5);
  }
}

/* The left rule is the card's own worst state, so a stale file is findable by
   scanning the edge of the column rather than by reading every card. */
.ds-card--current {
  border-left-color: var(--success);
}

.ds-card--due {
  border-left-color: var(--warning);
}

.ds-card--stale {
  border-left-color: var(--danger);
}

.ds-card--undated {
  border-left-color: var(--text-subtle);
}

.ds-card__head {
  margin-bottom: var(--space-3);
}

.ds-card__title {
  margin: 0 0 var(--space-1);
  font-family: var(--font-display);
  font-size: var(--text-xl);
  font-weight: var(--weight-bold);
  font-stretch: var(--width-display);
  letter-spacing: var(--tracking-tight);
  line-height: var(--leading-snug);
  color: var(--text);
}

.ds-card__path {
  margin: 0;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
}

/* The link to the raw file is the point of the card, and it is small type, so
   it gets a real target rather than the height of 12px text. */
.ds-card__path a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  overflow-wrap: anywhere;
}

.ds-card__size {
  color: var(--text-subtle);
}

.ds-card__what {
  margin: 0 0 var(--space-3);
  font-family: var(--font-serif);
  font-size: var(--text-base);
  line-height: var(--leading-normal);
  color: var(--text);
}

.ds-card__used,
.ds-card__upstream {
  margin: 0 0 var(--space-3);
  font-family: var(--font-sans);
  line-height: var(--leading-normal);
  color: var(--text-muted);
}

.ds-card__error {
  margin: 0;
  padding: var(--space-3);
  border-radius: var(--radius-sm);
  background: var(--danger-soft);
  color: var(--danger);
  font-size: var(--text-sm);
  line-height: var(--leading-normal);
}

/* --------------------------------------------------------------------------
   Clocks

   One block per dated fact. A file can carry several — data/activity.json
   carries four, because the day we wrote the file and the day the county last
   edited each of its three layers are four different questions and collapsing
   them into one date is how a site ends up claiming yesterday's freshness for
   a two-month-old count.
   -------------------------------------------------------------------------- */

.ds-clock {
  border-top: var(--rule-width) solid var(--rule);
  padding-top: var(--space-3);
  margin-top: var(--space-3);
}

.ds-clock__head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--space-2);
  margin-bottom: var(--space-1);
}

.ds-clock__label {
  font-family: var(--font-sans);
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
  color: var(--text);
}

.ds-clock__when {
  margin: 0 0 var(--space-1);
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
  font-size: var(--text-sm);
  color: var(--text);
}

.ds-clock__basis,
.ds-clock__link {
  margin: 0 0 var(--space-1);
  line-height: var(--leading-normal);
}

.ds-clock__link a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
}

/* --------------------------------------------------------------------------
   The flag
   -------------------------------------------------------------------------- */

.ds-flag {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-1) var(--space-2);
  border-radius: var(--radius-pill);
  font-family: var(--font-sans);
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  letter-spacing: 0.01em;
  line-height: var(--leading-snug);
  /* The longest of these reads "Stale — 87 days old, expected within 62". It
     has to wrap on a phone rather than push the card open. */
  overflow-wrap: anywhere;
}

.ds-flag__dot {
  flex: none;
  width: 8px;
  height: 8px;
  border-radius: var(--radius-pill);
  background: currentColor;
}

.ds-flag--current {
  background: var(--success-soft);
  color: var(--success);
}

.ds-flag--due {
  background: var(--warning-soft);
  color: var(--warning);
}

.ds-flag--stale {
  background: var(--danger-soft);
  color: var(--danger);
}

.ds-flag--undated,
.ds-flag--unscheduled {
  background: var(--bg-sunken);
  color: var(--text-muted);
}

/* --------------------------------------------------------------------------
   The meter

   How much of the window this clock has used. Past the window it pins at full
   and the caption carries the overshoot — a bar running off the end of its
   track says nothing that a longer bar would.
   -------------------------------------------------------------------------- */

.ds-meter {
  margin-top: var(--space-2);
}

.ds-meter__track {
  height: 6px;
  border-radius: var(--radius-pill);
  background: var(--bg-sunken);
  overflow: hidden;
}

.ds-meter__fill {
  display: block;
  height: 100%;
  border-radius: var(--radius-pill);
  background: var(--text-muted);
  transform-origin: left center;
  animation: ds-meter-grow var(--duration-slow) var(--ease-out) both;
}

.ds-clock--current .ds-meter__fill {
  background: var(--success);
}

.ds-clock--due .ds-meter__fill {
  background: var(--warning);
}

.ds-clock--stale .ds-meter__fill {
  background: var(--danger);
}

.ds-meter__caption {
  margin: var(--space-1) 0 0;
  line-height: var(--leading-snug);
}

@keyframes ds-meter-grow {
  from {
    transform: scaleX(0);
  }
  to {
    transform: scaleX(1);
  }
}

/* --------------------------------------------------------------------------
   Facts read out of each file
   -------------------------------------------------------------------------- */

.ds-dl {
  margin: var(--space-4) 0 0;
  padding-top: var(--space-3);
  border-top: var(--rule-width) solid var(--rule);
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-1) var(--space-4);
}

@media (min-width: 560px) {
  .ds-dl {
    grid-template-columns: minmax(0, 11rem) minmax(0, 1fr);
  }
}

.ds-dl dt {
  font-family: var(--font-sans);
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: var(--tracking-kicker);
  color: var(--text-subtle);
  align-self: baseline;
}

.ds-dl dd {
  margin: 0 0 var(--space-2);
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
  font-size: var(--text-sm);
  line-height: var(--leading-normal);
  color: var(--text);
  overflow-wrap: anywhere;
}

@media (min-width: 560px) {
  .ds-dl dd {
    margin-bottom: var(--space-1);
  }
}

/* --------------------------------------------------------------------------
   The windows
   -------------------------------------------------------------------------- */

.ds-windows {
  margin-top: var(--space-5);
}

.ds-windows__list {
  margin: 0;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-4);
}

/* Term and reason side by side once there is room, with the heavy rule running
   across both so a row reads as one statement rather than two stacked lists. */
@media (min-width: 800px) {
  .ds-windows__list {
    grid-template-columns: minmax(0, 14rem) minmax(0, 1fr);
    gap: var(--space-5) var(--space-6);
  }

  .ds-windows__list dd {
    margin-top: 0;
    padding-top: var(--space-2);
    border-top: var(--rule-heavy) solid var(--text);
  }
}

.ds-windows__list dt {
  border-top: var(--rule-heavy) solid var(--text);
  padding-top: var(--space-2);
  font-family: var(--font-sans);
  font-size: var(--text-base);
  font-weight: var(--weight-semibold);
  color: var(--text);
}

.ds-windows__days {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: var(--text-xs);
  font-weight: var(--weight-normal);
  color: var(--text-subtle);
}

.ds-windows__list dd {
  margin: var(--space-2) 0 0;
  font-family: var(--font-serif);
  font-size: var(--text-sm);
  line-height: var(--leading-normal);
  color: var(--text-muted);
}

.ds-windows__note {
  margin-top: var(--space-4);
}

.ds-caveat {
  margin-top: var(--space-5);
  padding-top: var(--space-4);
  border-top: var(--rule-width) solid var(--rule);
}

/* --------------------------------------------------------------------------
   Upstream publishers
   -------------------------------------------------------------------------- */

.ds-group {
  margin-top: var(--space-6);
}

.ds-group:first-child {
  margin-top: var(--space-5);
}

.ds-group__title {
  margin: 0 0 var(--space-2);
  font-family: var(--font-display);
  font-size: var(--text-xl);
  font-weight: var(--weight-bold);
  font-stretch: var(--width-display);
  letter-spacing: var(--tracking-tight);
  color: var(--text);
}

.ds-group__note {
  margin: 0 0 var(--space-4);
  max-width: var(--container-narrow);
  font-family: var(--font-serif);
  font-size: var(--text-sm);
  line-height: var(--leading-normal);
}

.ds-source-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-4);
}

@media (min-width: 900px) {
  .ds-source-list {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--space-4) var(--space-6);
  }
}

.ds-source {
  border-top: var(--rule-width) solid var(--rule);
  padding-top: var(--space-3);
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  /* Without this the tile-URL <code> below — one long unbreakable token —
     blows the grid track open and takes the whole page sideways with it. A
     grid and flex item's automatic minimum is its content, and this content is
     deliberately not allowed to wrap. */
  min-width: 0;
}

.ds-source__name {
  font-family: var(--font-sans);
  font-size: var(--text-base);
  font-weight: var(--weight-semibold);
  line-height: var(--leading-snug);
  overflow-wrap: anywhere;
}

a.ds-source__name {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
}

.ds-source__name--plain {
  color: var(--text);
}

.ds-source__pub {
  font-family: var(--font-sans);
  font-size: var(--text-sm);
  color: var(--text-muted);
}

.ds-source__use {
  font-family: var(--font-serif);
  font-size: var(--text-sm);
  line-height: var(--leading-normal);
  color: var(--text-muted);
}

.ds-source__cadence {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: 0.02em;
  color: var(--text-subtle);
}

/* Tile URL templates are long and have no natural break points. They wrap
   mid-token rather than scrolling: a scrollable box needs its own keyboard
   affordance to be reachable without a mouse, and a wrapped URL needs none and
   shows the whole endpoint at once, which is the reason it is printed here. */
.ds-source__endpoint {
  display: block;
  min-width: 0;
  max-width: 100%;
  padding: var(--space-2);
  border-radius: var(--radius-sm);
  background: var(--bg-sunken);
  font-size: var(--text-xs);
  line-height: var(--leading-normal);
  color: var(--text-muted);
  white-space: normal;
  overflow-wrap: anywhere;
}

/* --------------------------------------------------------------------------
   What this site does not know
   -------------------------------------------------------------------------- */

.ds-unknown-list {
  list-style: none;
  margin: var(--space-5) 0 0;
  padding: 0;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-5);
}

@media (min-width: 1000px) {
  .ds-unknown-list {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: var(--space-6);
  }
}

.ds-unknown {
  border-top: var(--rule-heavy) solid var(--text);
  padding-top: var(--space-3);
}

.ds-unknown__claim {
  margin: 0 0 var(--space-2);
  font-family: var(--font-sans);
  font-size: var(--text-base);
  font-weight: var(--weight-semibold);
  line-height: var(--leading-snug);
  color: var(--text);
}

.ds-unknown__why {
  margin: 0;
  font-family: var(--font-serif);
  font-size: var(--text-sm);
  line-height: var(--leading-normal);
  color: var(--text-muted);
}

/* The withheld figures sit on the ink ground. They are the one part of this
   page that is not a thing we could fix by working harder, and the change of
   ground says so before the words do. */
.ds-dark {
  margin-top: var(--space-6);
  padding: var(--space-5) var(--space-4);
  border-radius: var(--radius-lg);
  background: var(--bg-ink);
  color: var(--text-on-ink);
}

@media (min-width: 700px) {
  .ds-dark {
    padding: var(--space-6);
  }
}

.ds-dark__title {
  margin: 0 0 var(--space-2);
  font-family: var(--font-display);
  font-size: var(--text-2xl);
  font-weight: var(--weight-bold);
  font-stretch: var(--width-display);
  letter-spacing: var(--tracking-tight);
  line-height: var(--leading-snug);
  color: var(--text-on-ink);
}

.ds-dark__lead,
.ds-dark__empty {
  margin: 0;
  max-width: var(--container-narrow);
  font-family: var(--font-serif);
  font-size: var(--text-sm);
  line-height: var(--leading-normal);
  color: var(--text-on-ink-muted);
}

.ds-dark a {
  color: var(--teal-bright);
}

.ds-dark a:hover {
  color: var(--text-on-ink);
}

.ds-withheld {
  list-style: none;
  margin: var(--space-5) 0 0;
  padding: 0;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-5);
}

@media (min-width: 900px) {
  .ds-withheld {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--space-5) var(--space-6);
  }
}

.ds-withheld__item {
  border-top: var(--rule-width) solid var(--border-on-ink);
  padding-top: var(--space-3);
}

.ds-withheld__claim {
  margin: 0 0 var(--space-2);
  font-family: var(--font-sans);
  font-size: var(--text-base);
  font-weight: var(--weight-semibold);
  line-height: var(--leading-snug);
  color: var(--text-on-ink);
}

.ds-withheld__why {
  margin: 0 0 var(--space-2);
  font-family: var(--font-serif);
  font-size: var(--text-sm);
  line-height: var(--leading-normal);
  color: var(--text-on-ink-muted);
}

.ds-withheld__source {
  margin: 0;
  line-height: var(--leading-normal);
  color: var(--text-on-ink-muted);
}

.ds-withheld__source a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  overflow-wrap: anywhere;
}

/* --------------------------------------------------------------------------
   The refresh schedule table
   -------------------------------------------------------------------------- */

.ds-table {
  /* Three columns of prose need room; below this the shared .table-scroll
     wrapper takes over and the table scrolls inside its own box rather than
     the page scrolling sideways. */
  min-width: 44rem;
}

.ds-table th[scope="row"] {
  font-family: var(--font-mono);
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
  vertical-align: top;
  white-space: normal;
}

.ds-table td {
  vertical-align: top;
  font-size: var(--text-sm);
  line-height: var(--leading-normal);
}

.ds-table__sub {
  display: block;
  margin-top: var(--space-1);
  font-family: var(--font-sans);
  font-size: var(--text-xs);
  font-weight: var(--weight-normal);
  line-height: var(--leading-normal);
  color: var(--text-muted);
}

.ds-schedule__note {
  margin-top: var(--space-4);
  max-width: var(--container-narrow);
}

/* --------------------------------------------------------------------------
   Motion

   The only movement on this page is the meters drawing themselves once, which
   is a small honesty: a bar that grows makes it obvious it is measured rather
   than decorative. Anyone who has asked their system not to animate gets the
   measured bar with no growth at all — the information is identical.
   -------------------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  .ds-meter__fill {
    animation: none;
    transform: none;
  }
}
