/* ============================================================
   Block: network_map — interactive statewide partner map.
   Design source: H:169-254. Mobile-first per DECISIONS D3.

   The responsive story here is the one the mobile design is most
   specific about, because the desktop version cannot work on a
   phone. MEASURED at a 390px viewport (wrap gutter 2x20 + frame
   padding 2x12 leaves a 326px square image, and the seeded map is
   1400x1400): the closest two pins — VSU 71/66 and GENEDGE 66/60 —
   sit 25px apart center to center, and VT/NCI 27px. A 44x44 hit
   target needs 44px of clearance, so pin hit areas would overlap
   by nearly half. That, not the dot size, is why the pins cannot
   be controls here.

   So below 768px the pins are DECORATIVE — pointer-events:none,
   9px dots, no labels, no pulse rings — and the list is the only
   control. The readout panel is hidden and its content merges
   into the active row (the part renders the city in the row for
   exactly this reason). Interactive pins return at md with a
   44x44 hit area.

   Decorative is NOT the same as inert, though: the pins still
   mirror the list selection at every size (network-map.js has no
   breakpoint logic and toggles .is-active on rows and pins
   together). See the .is-active dot rule below — the map has to
   move when the list does, or the section reads as broken. */

.m434-network-head { margin-bottom: 24px; }

.m434-network-title {
  font-family: var(--display);
  font-weight: 700;
  font-size: 26px;
  line-height: 1.08;
  text-transform: uppercase;
  letter-spacing: -0.01em;
  color: var(--ink);
  margin: 10px 0 0;
}

.m434-network-status {
  display: flex;
  align-items: center;
  gap: 8px;
  font-family: var(--body);
  font-weight: 700;
  font-size: 10px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  /* --m434-muted-ink, not --slate. This line sits in the block HEAD,
     directly on the section ground, and the seeded home page puts the
     block on a Soft band: #6b7280 on #f4f5f7 is 4.43:1 at 10px/700,
     which is normal text by WCAG (7.5pt) and so wants 4.5:1. The same
     pairing was moved to --m434-slate-strong twice elsewhere this
     round; these three rules were left behind. The token also covers
     the Navy/Accent bands the block can be set to, where a flat
     #6b7280 is 3.13:1 / 1.81:1. */
  color: var(--m434-muted-ink);
  margin: 14px 0 0;
}

.m434-network-dot {
  width: 7px;
  height: 7px;
  flex: 0 0 auto;
  border-radius: 50%;
  background: var(--m434-crimson);
  animation: m434-blink 1.8s steps(1, end) infinite;
}

@keyframes m434-blink {
  0%, 55% { opacity: 1; }
  56%, 100% { opacity: 0.25; }
}

/* ---------- Layout: stacked on mobile, list first ---------- */
.m434-network-split {
  display: flex;
  flex-direction: column;
  gap: 24px;
}

/* ---------- The list (the control surface) ---------- */
.m434-network-list {
  list-style: none;
  margin: 0;
  padding: 0;
  box-shadow: 0 0 0 1px var(--line);
  background: var(--white);
}

.m434-network-row {
  display: flex;
  align-items: flex-start;
  gap: 14px;
  width: 100%;
  /* 64px minimum row height — D3's hit-target floor for list rows. */
  min-height: 64px;
  padding: 14px 16px;
  background: none;
  border: 0;
  border-top: 1px solid var(--line);
  text-align: left;
  cursor: pointer;
  transition: background 0.18s var(--m434-ease);
}

.m434-network-list li:first-child .m434-network-row { border-top: 0; }

.m434-network-row:hover { background: var(--m434-hover-row); }

/* The 3px accent left border is explicitly KEPT at every size (D3) —
   it is one of the motifs that carries the industrial language. */
.m434-network-row.is-active {
  background: var(--m434-hover-light);
  box-shadow: inset 3px 0 0 0 var(--red);
}

.m434-network-idx {
  flex: 0 0 auto;
  font-family: var(--display);
  font-weight: 700;
  font-size: 13px;
  line-height: 1.5;
  /* #6b7280, NOT the design's #9aa0a8: that fails AA at 2.60:1 on
     white and these numerals must stay readable (tokens.css note 3). */
  color: var(--m434-slate-mute);
  min-width: 1.6em;
}

.m434-network-row.is-active .m434-network-idx { color: var(--m434-accent-text); }

.m434-network-meta {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.m434-network-name {
  font-family: var(--body);
  font-weight: 700;
  font-size: 14px;
  line-height: 1.35;
  color: var(--ink);
}

/* Both sit inside .m434-network-list, which blocks.css registers as a
   light island — so --m434-muted-ink resolves to --m434-slate-strong
   whatever the band is. On the row grounds that matters on:
     #ffffff (rest)            7.56:1   (was 4.83:1)
     #f4f5f7 (.is-active)      6.93:1   (was 4.43:1 — the failure)
     #f9fafb (:hover)          7.23:1   (was 4.63:1) */
.m434-network-role {
  font-family: var(--body);
  font-size: 12px;
  line-height: 1.45;
  color: var(--m434-muted-ink);
}

.m434-network-city {
  font-family: var(--body);
  font-size: 11px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--m434-muted-ink);
}

.m434-network-badge {
  margin-left: auto;
  flex: 0 0 auto;
  align-self: center;
  font-family: var(--body);
  font-weight: 700;
  font-size: 9px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--white);
  background: var(--m434-crimson);
  padding: 4px 7px;
}

/* ---------- The map frame ---------- */
.m434-network-frame {
  position: relative;
  background: var(--white);
  box-shadow: var(--m434-rule-inset);
  padding: 12px;
  /* Clips the pin hover labels at the frame edge. The rightmost pin sits at
     map_x 87%, and its 188px nowrap label overhung the viewport by 10px at
     exactly 768px — the width where labels un-hide — giving the whole document a
     horizontal scrollbar. `clip` rather than `hidden` so this never becomes a
     scroll container of its own.

     Clipping is acceptable rather than lossy: the readout panel already shows the
     active node's full name and city, so the label is a redundant affordance for
     pointer users, and losing a few characters on an edge pin beats a page that
     scrolls sideways on every screen. */
  overflow-x: clip;
}

.m434-network-map {
  display: block;
  width: 100%;
  height: auto;
}

/* Readout hidden below md — its content lives in the active row. */
.m434-network-readout { display: none; }

/* ---------- Pins: decorative below md ---------- */
.m434-network-pins {
  position: absolute;
  /* Inset by the frame padding so percentages are relative to the
     IMAGE, not the frame. Getting this wrong shifts every pin. */
  inset: 12px;
  pointer-events: none;
}

.m434-network-pin {
  position: absolute;
  transform: translate(-50%, -50%);
  padding: 0;
  border: 0;
  background: none;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.4s var(--m434-ease) var(--m434-pin-delay, 0ms),
              transform 0.4s var(--m434-ease) var(--m434-pin-delay, 0ms);
}

.is-pinned .m434-network-pin { opacity: 1; }

.m434-network-pin-dot {
  display: block;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--red);
  box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.85);
  /* Transition lives HERE, not in the md block where it used to, because
     the selected state below is now a mobile-first state. Finite, so the
     global prefers-reduced-motion rule in global.css flattens it to
     0.001ms and the end state still lands — nothing to add to the reduce
     block at the foot of this file. */
  transition: transform 0.18s var(--m434-ease), box-shadow 0.18s var(--m434-ease);
}

.m434-network-pin.is-operator .m434-network-pin-dot { background: var(--m434-crimson); }

/* SELECTED PIN — mobile-first, deliberately BEYOND the approved design.
   FB-046: tapping a list row moved the row highlight but nothing on the
   map, because the only selected-pin styling used to live in the md block
   below (with the hover labels and the pulse ring). Below 768px the map
   had no selected state at all and read as a dead image.

   That inertness matched the spec — "VSMA - Mobile + Tablet.dc.html":268
   calls the 390px map "a static locator, the list is the interaction",
   :285 stamps "DOTS ARE DECORATIVE, NOT TARGETS" on the artboard, and the
   model at :490-492 builds staticPins with no isActive branch. But
   DECISIONS D3 UPDATE (docs/specs/DECISIONS.md:76-100) only lists "map pin
   hover labels + vsmaPulse rings" as hidden below 768px — losing the
   selection entirely went further than the decision the code cites. This
   rule is the smaller deviation of the two: the pins stay non-interactive
   (still pointer-events:none, still no 44px target), they just answer the
   list. Recorded so a later design QA reads it as intent, not a regression.

   WHY WHITE + A DARK HAIRLINE AND NOT AN ACCENT GLOW: the seeded map is a
   flat silhouette filled with rgb(229,118,30) — the exact value of
   --vaccent, so the exact value of --red. All five pins sample that color
   underneath them, which means a non-operator dot is invisible except for
   its white ring, and an rgba(var(--vaccent),…) halo would be orange on
   orange on orange. White reads on the landmass, and the --navy hairline
   reads on both the landmass and the white ground outside it.

   WHY THE FOOTPRINT IS SMALL: 9px x 1.35 + 2 x 4px x 1.35 = 23px across,
   which stays inside the 25px closest-pin separation measured in the
   header — the selected pin must not swallow its neighbour. */
.m434-network-pin.is-active .m434-network-pin-dot {
  transform: scale(1.35);
  box-shadow: 0 0 0 3px var(--white), 0 0 0 4px var(--navy);
}

/* Labels and pulse rings are hidden below 768px (D3). */
.m434-network-pin-label { display: none; }

/* ---------- md: two columns, interactive pins, readout ---------- */
@media (min-width: 768px) {
  .m434-network-head { margin-bottom: 32px; }
  .m434-network-title { font-size: 34px; }

  .m434-network-split {
    flex-direction: row;
    align-items: stretch;
    gap: 32px;
  }

  .m434-network-list { flex: 0 0 340px; }
  .m434-network-frame { flex: 1 1 auto; }

  /* The city is in the readout now, so the row stops repeating it. */
  .m434-network-city { display: none; }

  .m434-network-readout {
    display: flex;
    flex-direction: column;
    gap: 4px;
    position: absolute;
    top: 24px;
    left: 24px;
    z-index: 2;
    min-width: 240px;
    max-width: 60%;
    background: var(--white);
    box-shadow: var(--m434-rule-inset), var(--shadow-sm);
    padding: 14px 16px;
  }

  .m434-network-readout-logo {
    display: flex;
    align-items: center;
    justify-content: flex-start;
    width: 120px;
    height: 56px;
    margin-bottom: 6px;
  }

  .m434-network-readout-logo img {
    max-width: 100%;
    max-height: 100%;
    width: auto;
    height: auto;
    object-fit: contain;
  }

  /* The no-logo state is a SUPPORTED design decision for VSU and
     GENEDGE, not a broken-image fallback (asset-manifest.md note 2). */
  .m434-network-readout-logo--text {
    font-family: var(--display);
    font-weight: 700;
    font-size: 26px;
    letter-spacing: 0.06em;
    color: var(--m434-accent-text);
  }

  .m434-network-readout-name {
    font-family: var(--body);
    font-weight: 700;
    font-size: 15px;
    color: var(--ink);
  }

  .m434-network-readout-city {
    font-family: var(--body);
    font-size: 11px;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--slate);
  }

  /* Pins become real controls: 44x44 hit area around a 12px dot. */
  .m434-network-pins { pointer-events: none; }

  .m434-network-pin {
    pointer-events: auto;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    cursor: pointer;
  }

  .m434-network-pin-dot {
    width: 12px;
    height: 12px;
  }

  /* md keeps the treatment it always had: a plain 1.5x dot whose selected
     state is carried by the pulse ring and the hover label below. The
     box-shadow is put back to the resting ring on purpose — without this
     line the mobile-first halo above would inherit up and stack a static
     white/navy reticle under the pulse, which is a change to a screen
     FB-046 never complained about. Reset, not removal: change it here if
     the md ring is ever revisited (the spec's tabletPins at
     "VSMA - Mobile + Tablet.dc.html":497-503 do want a static glow, which
     this build answered with the pulse instead — a separate, unfiled gap). */
  .m434-network-pin.is-active .m434-network-pin-dot {
    transform: scale(1.5);
    box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.85);
  }

  /* Pulse ring on the active pin only — an animation on all five is
     the kind of motion that makes a page feel broken. */
  .m434-network-pin.is-active::before {
    content: "";
    position: absolute;
    width: 12px;
    height: 12px;
    border-radius: 50%;
    box-shadow: 0 0 0 0 rgba(var(--vaccent), 0.5);
    animation: m434-pulse 1.8s var(--m434-ease) infinite;
  }

  @keyframes m434-pulse {
    to { box-shadow: 0 0 0 18px rgba(var(--vaccent), 0); }
  }

  .m434-network-pin-label {
    display: block;
    position: absolute;
    bottom: calc(100% - 4px);
    left: 50%;
    transform: translateX(-50%);
    white-space: nowrap;
    opacity: 0;
    pointer-events: none;
    font-family: var(--body);
    font-weight: 700;
    font-size: 10px;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--white);
    background: var(--navy);
    padding: 4px 8px;
    box-shadow: var(--shadow-sm);
    transition: opacity 0.18s var(--m434-ease);
  }

  .m434-network-pin:hover .m434-network-pin-label,
  .m434-network-pin.is-active .m434-network-pin-label { opacity: 1; }

  /* Corner ticks return at md (global.css un-hides .m434-corner-tick). */
  .m434-corner-tick {
    position: absolute;
    width: 12px;
    height: 12px;
    border-color: var(--red);
    border-style: solid;
    border-width: 0;
  }
  .m434-network-frame .m434-corner-tick--tl { top: 6px;    left: 6px;  border-top-width: 2px; border-left-width: 2px; }
  .m434-network-frame .m434-corner-tick--tr { top: 6px;    right: 6px; border-top-width: 2px; border-right-width: 2px; }
  .m434-network-frame .m434-corner-tick--bl { bottom: 6px; left: 6px;  border-bottom-width: 2px; border-left-width: 2px; }
  .m434-network-frame .m434-corner-tick--br { bottom: 6px; right: 6px; border-bottom-width: 2px; border-right-width: 2px; }

  .m434-network-fig,
  .m434-network-axis {
    position: absolute;
    font-family: var(--body);
    font-weight: 700;
    font-size: 9px;
    letter-spacing: 0.2em;
    text-transform: uppercase;
    color: var(--m434-slate-mute);
  }
  .m434-network-fig { bottom: 16px; left: 20px; }
  .m434-network-axis { top: 50%; right: 14px; transform: translateY(-50%); }
}

@media (min-width: 1024px) {
  .m434-network-title { font-size: 40px; }
  .m434-network-split { gap: 44px; }
  .m434-network-list { flex: 0 0 420px; }
}

/* Reduced motion: kill the two infinite animations outright. The
   global rule collapses durations, which for an infinite loop still
   leaves it looping — just imperceptibly fast. */
@media (prefers-reduced-motion: reduce) {
  .m434-network-dot { animation: none; opacity: 1; }
  .m434-network-pin.is-active::before { animation: none; box-shadow: none; }
}
