/* ==========================================================================
   How close are you?

   One question, one answer, one diagram. The design job here is different from
   the rest of the site: a visitor arrives having already decided what they want
   to know, so nothing on this page should compete with the number that answers
   it. Three consequences run through everything below.

     1. The answer outranks the input. Once a measurement exists, the finder
        card stops being the loudest thing on screen and the distance sentence
        takes over — set in the serif, at reading size, because it is a
        sentence and not a dashboard tile.

     2. The rings are a diagram, not a map. They carry no basemap, no scale bar
        and no zoom, because they are not to scale — the circles are evenly
        spaced so the half-mile ring survives on a 375px screen. Everything
        that has to be exact is set in type beside them.

     3. Status colour is the site legend and nothing else. Teal is running,
        amber is being built, violet is proposed. The rings themselves are
        drawn in the neutral rule colour so they never look like a fifth
        status.

   Motion: the rings sweep outward once as the figure comes into view and the
   cards land behind them. The un-animated CSS below IS the finished state —
   the animation only ever plays backwards out of it — so under
   prefers-reduced-motion, where js/nearby.js never adds .is-sweeping and
   animations.css switches animation off outright, the page draws complete on
   the first frame with nothing left pending.
   ========================================================================== */

/* ---- The finder ---------------------------------------------------------- */

.nearby-finder {
  max-width: var(--container-narrow);
  margin-bottom: var(--space-6);
}

.nearby-finder__title {
  font-family: var(--font-serif);
  font-size: var(--text-xl);
  letter-spacing: var(--tracking-tight);
  margin-bottom: var(--space-4);
}

.nearby-route__field {
  margin-bottom: 0;
}

/* Input and button share a line only while the input can still show a street
   address. Below that the button goes full width, which is the bigger tap
   target anyway. */
.nearby-route__row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

.nearby-route__row .input,
.nearby-route__row .select {
  flex: 1 1 14rem;
  min-width: 0;
}

.nearby-route__row .btn {
  flex: 1 0 auto;
}

@media (min-width: 480px) {
  .nearby-route__row .btn {
    flex: 0 0 auto;
    min-width: 7.5rem;
  }
}

/* The three routes are alternatives, not steps; a numbered list would say the
   wrong thing. */
.nearby-finder__or {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin: var(--space-5) 0;
  font-family: var(--font-sans);
  font-size: var(--text-xs);
  font-weight: var(--weight-bold);
  letter-spacing: var(--tracking-kicker);
  text-transform: uppercase;
  color: var(--text-subtle);
}

.nearby-finder__or::before,
.nearby-finder__or::after {
  content: "";
  flex: 1;
  height: var(--rule-width);
  background: var(--rule);
}

/* ---- Status -------------------------------------------------------------- */

.nearby-status {
  margin: var(--space-4) 0 0;
  font-family: var(--font-sans);
  font-size: var(--text-sm);
  line-height: var(--leading-normal);
  color: var(--text-muted);
}

/* Empty until something has happened. An empty bordered strip reads as a
   broken component. */
.nearby-status:empty {
  display: none;
}

.nearby-status--warning,
.nearby-status--error {
  padding-left: var(--space-3);
  border-left: var(--rule-heavy) solid var(--border-strong);
  color: var(--text);
}

.nearby-status--warning {
  border-left-color: var(--warning);
}

.nearby-status--error {
  border-left-color: var(--danger);
  color: var(--danger);
  font-weight: var(--weight-semibold);
}

/* ---- The answer ---------------------------------------------------------- */

.nearby-answer {
  margin-bottom: var(--space-7);
}

/* js/nearby.js focuses this section once it is built so a screen reader is
   taken to the answer. That focus is programmatic, so it gets a ring only when
   the visitor is actually driving from the keyboard — a mouse user should not
   see a box appear round half the page. */
.nearby-answer:focus {
  outline: none;
}

.nearby-answer:focus-visible {
  outline: 2px solid var(--focus-ring);
  outline-offset: 6px;
  border-radius: var(--radius-md);
}

.nearby-answer__title {
  font-family: var(--font-display);
  font-size: var(--text-2xl);
  font-stretch: var(--width-display);
  font-weight: var(--weight-black);
  letter-spacing: var(--tracking-tight);
  line-height: var(--leading-snug);
  margin: var(--space-1) 0 var(--space-4);
}

.nearby-headline {
  padding-bottom: var(--space-5);
  border-bottom: var(--rule-heavy) solid var(--rule-strong);
  margin-bottom: var(--space-6);
}

/* The sentence that answers the question. Serif, reading size, because it is
   prose — the numbers inside it are already carrying the emphasis. */
.nearby-headline__lead {
  font-family: var(--font-serif);
  font-size: var(--text-lg);
  line-height: var(--leading-normal);
  color: var(--text);
  margin: 0 0 var(--space-5);
  max-width: 46ch;
}

.nearby-inside {
  margin-bottom: var(--space-5);
}

/* ---- Facts about the nearest --------------------------------------------- */

.nearby-facts {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: var(--space-3);
}

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

.nearby-facts > li {
  display: grid;
  gap: 2px;
  padding-top: var(--space-2);
  border-top: var(--rule-width) solid var(--rule);
  min-width: 0;
}

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

.nearby-facts__value {
  font-family: var(--font-sans);
  font-size: var(--text-base);
  color: var(--text);
  /* Operator names out of the county's record are long and unbroken; on a
     375px screen they have to be allowed to wrap mid-word rather than push
     the page sideways. */
  overflow-wrap: anywhere;
}

/* ---- The figure: diagram + ring cards ------------------------------------ */

.nearby-figure {
  display: grid;
  gap: var(--space-6);
}

/* The diagram earns a column of its own only when there is room for the cards
   to stay two-wide beside it. Below that it sits above them, which is the
   right reading order on a phone: picture, then numbers. */
@media (min-width: 960px) {
  .nearby-figure {
    grid-template-columns: minmax(0, 20rem) minmax(0, 1fr);
    align-items: start;
    gap: var(--space-7);
  }
}

.nearby-diagram {
  margin: 0 auto;
  max-width: 22rem;
  width: 100%;
}

.nearby-diagram__svg {
  display: block;
  width: 100%;
  height: auto;
  overflow: visible;
}

/* Neutral on purpose. The rings are a measuring instrument, not a status. */
.nearby-diagram__ring {
  fill: none;
  stroke: var(--border-strong);
  stroke-width: 1;
}

/* The five-mile ring is the edge of what this page knows about, so it is drawn
   a shade heavier than the three inside it. */
.nearby-diagram__ring--outer {
  stroke: var(--text-subtle);
}

.nearby-diagram__label {
  fill: var(--text-muted);
  font-family: var(--font-mono);
  font-size: 11px;
  text-anchor: middle;
  /* A halo in the paper colour so a mile label stays readable where a dot
     lands under it. paint-order is what puts the stroke behind the glyph
     instead of thickening it. */
  stroke: var(--bg);
  stroke-width: 4px;
  stroke-linejoin: round;
  paint-order: stroke fill;
}

.nearby-diagram__you {
  fill: var(--text);
  stroke: var(--bg);
  stroke-width: 2;
}

.nearby-diagram__dot {
  stroke: var(--bg);
  stroke-width: 1.25;
}

.nearby-diagram__dot--operational { fill: var(--status-operational); }
.nearby-diagram__dot--construction { fill: var(--status-construction); }
.nearby-diagram__dot--proposed { fill: var(--status-proposed); }
.nearby-diagram__dot--unknown { fill: var(--text-subtle); }

.nearby-diagram__caption {
  margin: var(--space-4) 0 0;
  max-width: 34ch;
}

@media (min-width: 960px) {
  .nearby-diagram__caption {
    margin-inline: 0;
  }
}

/* ---- The ring cards ------------------------------------------------------ */

.nearby-rings {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: var(--space-4);
}

@media (min-width: 560px) {
  .nearby-rings {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

.nearby-ring {
  background: var(--bg-raised);
  border: var(--border-width) solid var(--border);
  border-radius: var(--radius-lg);
  padding: var(--space-4);
  box-shadow: var(--shadow-sm);
  min-width: 0;
}

.nearby-ring--empty {
  background: var(--bg-tint);
  box-shadow: none;
}

.nearby-ring__kicker {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text-subtle);
  margin: 0;
}

.nearby-ring__count {
  font-family: var(--font-display);
  font-stretch: var(--width-display);
  font-size: var(--text-2xl);
  font-weight: var(--weight-black);
  line-height: var(--leading-tight);
  letter-spacing: var(--tracking-tighter);
  color: var(--text);
  margin: var(--space-2) 0 0;
}

.nearby-ring--empty .nearby-ring__count {
  color: var(--text-subtle);
}

.nearby-ring__unit {
  font-family: var(--font-sans);
  font-size: var(--text-sm);
  color: var(--text-muted);
  margin: 0 0 var(--space-3);
}

.nearby-ring__parcels {
  color: var(--text-subtle);
}

.nearby-ring__none {
  margin: 0;
  color: var(--text-muted);
}

.nearby-ring__rows {
  list-style: none;
  margin: 0;
  padding: 0;
  border-top: var(--rule-width) solid var(--rule);
}

.nearby-ring__row {
  display: flex;
  align-items: baseline;
  gap: var(--space-2);
  padding: var(--space-2) 0;
  border-bottom: var(--rule-width) solid var(--rule);
  font-family: var(--font-sans);
  font-size: var(--text-sm);
}

.nearby-ring__row-label {
  flex: 1 1 auto;
  color: var(--text-muted);
  min-width: 0;
}

.nearby-ring__row-value {
  font-weight: var(--weight-bold);
  color: var(--text);
}

/* The legend, at text size. Sits on the baseline of the label beside it. */
.nearby-ring__swatch {
  display: inline-block;
  flex: 0 0 auto;
  width: 0.65em;
  height: 0.65em;
  border-radius: var(--radius-pill);
  background: var(--text-subtle);
  margin-right: 0.15em;
  /* Colour alone never carries the meaning here — every swatch has its label
     written next to it — so this is reinforcement, not the signal. */
}

.nearby-ring__swatch--operational { background: var(--status-operational); }
.nearby-ring__swatch--construction { background: var(--status-construction); }
.nearby-ring__swatch--proposed { background: var(--status-proposed); }
.nearby-ring__swatch--unknown { background: var(--text-subtle); }

.nearby-ring__area {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: var(--space-1) var(--space-3);
  margin: var(--space-3) 0 0;
  font-family: var(--font-sans);
  font-size: var(--text-xs);
}

.nearby-ring__area dt {
  color: var(--text-subtle);
  min-width: 0;
}

.nearby-ring__area dd {
  margin: 0;
  text-align: right;
  font-weight: var(--weight-semibold);
  color: var(--text);
  white-space: nowrap;
}

/* ---- Provenance and the list --------------------------------------------- */

.nearby-provenance {
  margin: var(--space-6) 0 0;
  padding-top: var(--space-4);
  border-top: var(--rule-width) solid var(--rule);
  max-width: 68ch;
}

.nearby-block {
  margin-bottom: var(--space-7);
}

.nearby-block__title {
  font-family: var(--font-display);
  font-stretch: var(--width-display);
  font-size: var(--text-xl);
  font-weight: var(--weight-bold);
  letter-spacing: var(--tracking-tight);
  margin-bottom: var(--space-2);
}

.nearby-block .muted {
  margin-bottom: var(--space-4);
}

/* The distance column is the one being compared down the page, so it gets the
   mono face the rest of the site uses for anything read as data. */
.nearby-table td.numeric {
  font-family: var(--font-mono);
  white-space: nowrap;
}

/* ---- Motion --------------------------------------------------------------
   Everything above is the finished state. The two keyframes below start from
   somewhere else and end exactly there, and .is-sweeping — added once, by
   js/nearby.js, and only when the visitor has not asked for reduced motion —
   is the only thing that applies them. `backwards` is what holds the start
   frame during the delay; without it every ring would flash in complete and
   then animate.
   -------------------------------------------------------------------------- */

@keyframes nearby-sweep {
  from {
    transform: scale(0.2);
    opacity: 0;
  }
  to {
    transform: scale(1);
    opacity: 1;
  }
}

@keyframes nearby-land {
  from {
    transform: translateY(10px);
    opacity: 0;
  }
  to {
    transform: translateY(0);
    opacity: 1;
  }
}

.nearby-figure.is-sweeping .nearby-diagram__ring,
.nearby-figure.is-sweeping .nearby-diagram__dot,
.nearby-figure.is-sweeping .nearby-diagram__label {
  transform-origin: 160px 160px;
  transform-box: view-box;
  animation: nearby-sweep var(--duration-slow) var(--ease-out) backwards;
  animation-delay: calc(var(--ring-index, 0) * 260ms);
}

/* The count for a ring lands as that ring arrives — same index, same clock,
   plus the sweep's own length so the number appears once its circle has
   finished drawing rather than racing it. */
.nearby-figure.is-sweeping .nearby-ring {
  animation: nearby-land var(--duration-base) var(--ease-out) backwards;
  animation-delay: calc(var(--ring-index, 0) * 260ms + 220ms);
}

.nearby-figure.is-sweeping .nearby-diagram__you {
  animation: nearby-sweep var(--duration-base) var(--ease-spring) backwards;
  transform-origin: 160px 160px;
  transform-box: view-box;
}
