/* Running-assessment animation (planner ApplicationDetail "Running" state).
   The card column is Blazor-rendered; the map + pins are Leaflet (JS), so these
   styles are global (scoped .razor.css would not reach JS-created pin elements).
   Visual reference: sandbox/stream-animation/variant-b. */

.gsr-stage {
  --gsr-navy: #1a365d;
  --gsr-accent: #2563eb;
  --gsr-good: #16794a;
  --gsr-good-soft: #e7f4ee;
  --gsr-bad: #c2362b;
  --gsr-bad-soft: #fdeceb;
  --gsr-ink: #1a202c;
  --gsr-g700: #374151;
  --gsr-g500: #6b7280;
  --gsr-g300: #d1d5db;
  --gsr-g200: #e5e7eb;
  --gsr-g100: #f3f4f6;
  --gsr-g50: #f9fafb;
  --gsr-paper: #ffffff;
  --gsr-ease: cubic-bezier(0.22, 0.61, 0.36, 1);
  --gsr-dur: 620ms; /* one shared scroll feel - matches --scroll-dur in the marketing hero */
  font-family: "Inter", system-ui, -apple-system, sans-serif;
  color: var(--gsr-ink);
  border: 1px solid var(--gsr-g200);
  border-radius: 14px;
  overflow: hidden;
  background: var(--gsr-paper);
  box-shadow: 0 1px 2px rgba(16,24,40,0.04), 0 10px 30px rgba(16,24,40,0.06);
}

/* ---- header ---- */
.gsr-head {
  display: flex; flex-wrap: wrap; align-items: center; gap: 10px;
  padding: 14px 18px; border-bottom: 1px solid var(--gsr-g100);
}
.gsr-head .gsr-ref {
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
  font-size: 12.5px; font-weight: 700; color: var(--gsr-navy); letter-spacing: 0.01em;
}
.gsr-head .gsr-ref .sep { color: var(--gsr-g300); margin: 0 6px; }
.gsr-head .gsr-ref .council { color: var(--gsr-g500); font-weight: 600; }
.gsr-head .gsr-addr {
  flex: 1 1 240px; min-width: 0; font-size: 13px; color: var(--gsr-g700);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.gsr-tally { display: flex; gap: 8px; margin-left: auto; }
.gsr-pill {
  font-size: 11.5px; font-weight: 600; color: var(--gsr-g700);
  background: var(--gsr-g50); border: 1px solid var(--gsr-g200);
  padding: 4px 10px; border-radius: 999px; white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.gsr-pill b { color: var(--gsr-accent); font-weight: 800; }

/* ---- split body: map left, reading column right ---- */
/* grid-template-rows pins the row to 460px (a bare height lets the auto row grow to
   content, so a tall card column overflows down over the status bar); overflow:hidden
   is the backstop. The reading column clips inside .gsr-track, not here. */
.gsr-body { display: grid; grid-template-columns: 1fr 1fr; grid-template-rows: 460px; height: 460px; overflow: hidden; }
.gsr-map { height: 100%; background: #eef1f4; }
.leaflet-container { background: #eef1f4 !important; font-family: inherit !important; }

.gsr-col {
  display: flex; flex-direction: column; min-width: 0; min-height: 0;
  border-left: 1px solid var(--gsr-g100); background: var(--gsr-paper);
}
.gsr-col-head {
  display: flex; align-items: center; gap: 8px;
  padding: 12px 18px 8px; font-size: 11px; font-weight: 700;
  letter-spacing: 0.08em; text-transform: uppercase; color: var(--gsr-g500);
}
.gsr-assessing { margin-left: auto; color: var(--gsr-accent); letter-spacing: 0.02em; }
.gsr-assessing .dot {
  display: inline-block; width: 6px; height: 6px; border-radius: 50%;
  background: var(--gsr-accent); margin-right: 5px; vertical-align: middle;
  animation: gsr-pulse 1.6s ease-in-out infinite;
}

/* ---- the streaming card column ---- */
/* Bottom-anchored: overflow clips at the TOP, so pruning the oldest (already
   off-screen) card causes no visible movement. The 30px bottom padding is the
   reading reserve - the active card parks with breathing room beneath it instead
   of jamming against the edge (READING_RESERVE in the marketing hero). Card
   spacing lives on .gsr-card-wrap margin (not flex gap) so it can animate from 0. */
.gsr-track {
  position: relative; flex: 1 1 auto; min-height: 0; overflow: hidden;
  display: flex; flex-direction: column; justify-content: flex-end;
  padding: 6px 18px 30px;
}
/* fade the top so older cards dissolve as they scroll out */
.gsr-track::before {
  content: ""; position: absolute; left: 0; right: 0; top: 0; height: 34px; z-index: 2;
  background: linear-gradient(180deg, var(--gsr-paper) 0%, rgba(255,255,255,0) 100%);
  pointer-events: none;
}

/* Each card sits in a grid wrapper that grows 0fr -> 1fr on insertion
   (@starting-style). The bottom-anchored column pushes the older cards up at the
   SAME duration/easing as the card's own entrance, so the whole stack moves as one
   glide - the Blazor equivalent of the marketing hero's #track transform scroll.
   Older browsers without @starting-style just show the card at full height. */
.gsr-card-wrap {
  display: grid; grid-template-rows: 1fr; margin-top: 10px;
  flex: 0 0 auto; /* never shrink: excess height must clip off the track's top, not squash the cards */
  transition: grid-template-rows var(--gsr-dur) var(--gsr-ease),
              margin-top var(--gsr-dur) var(--gsr-ease);
}
/* Scoped to .is-live (set one render after the initial history paints): without the
   gate, @starting-style applies to EVERY wrapper's first style pass, so a page load
   or circuit reconnect of a mid-run assessment would collapse the whole column to
   zero height and regrow it. Only wrappers inserted while live animate. */
@starting-style {
  .is-live .gsr-card-wrap { grid-template-rows: 0fr; margin-top: 0; }
}

/* Entrance fill is `backwards`, NOT `both`: a forwards fill keeps the final
   keyframe's opacity:1 applied forever, and animated values beat normal author
   rules - it silently disabled .is-past's dimming. Demotion to .is-past fades on
   a gentler ease so it reads as settling, not snapping (matches the hero). */
.gsr-card {
  background: var(--gsr-paper); border: 1px solid var(--gsr-g200); border-radius: 12px;
  box-shadow: 0 1px 2px rgba(16,24,40,0.04), 0 6px 18px rgba(16,24,40,0.05);
  overflow: hidden; min-height: 0;
  animation: gsr-card-in var(--gsr-dur) var(--gsr-ease) backwards;
  transition: opacity 600ms ease, filter 600ms ease;
}
.gsr-card.is-past { opacity: 0.5; filter: saturate(0.85); }
.gsr-card.is-focus { border-color: rgba(37,99,235,0.40); box-shadow: 0 0 0 3px rgba(37,99,235,0.10), 0 6px 18px rgba(16,24,40,0.06); }

.gsr-card-head { display: flex; align-items: center; gap: 11px; padding: 11px 14px; }
.gsr-card.has-body .gsr-card-head { border-bottom: 1px solid var(--gsr-g100); }
.gsr-icon {
  flex: 0 0 auto; width: 30px; height: 30px; border-radius: 8px;
  display: grid; place-items: center; font-size: 14px; font-weight: 700;
  background: #eef4ff; color: var(--gsr-accent); border: 1px solid #dbe6ff;
}
.gsr-icon.pol { background: #f3f0ff; color: #6d4fcf; border-color: #e6e0fb; }
.gsr-icon.out { background: var(--gsr-good-soft); color: var(--gsr-good); border-color: #cae6d7; }
.gsr-icon.note { background: #fff; color: var(--gsr-g500); border-color: var(--gsr-g200); }
/* comparable (planning-bot decisions/appeals) - navy, ties to the map pins */
.gsr-icon.comp { background: #e8eef7; color: var(--gsr-navy); border-color: #cdddf2; }
/* tool (any other command the model runs) - neutral, deliberately unflashy */
.gsr-icon.tool { background: var(--gsr-g100); color: var(--gsr-g500); border-color: var(--gsr-g200); }

.gsr-meta { min-width: 0; flex: 1; }
.gsr-title { font-size: 13px; font-weight: 700; color: var(--gsr-ink); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.gsr-sub {
  margin-top: 2px; font-size: 11.5px; color: var(--gsr-g500);
  display: flex; align-items: center; gap: 7px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.gsr-sub .loc { color: var(--gsr-g700); font-weight: 600; font-variant-numeric: tabular-nums; }
.gsr-sub .dot { width: 3px; height: 3px; border-radius: 50%; background: var(--gsr-g300); flex: 0 0 auto; }
.gsr-tag {
  flex: 0 0 auto; font-size: 10px; font-weight: 700; letter-spacing: 0.04em; text-transform: uppercase;
  color: var(--gsr-g500); background: var(--gsr-g50); border: 1px solid var(--gsr-g200);
  padding: 3px 8px; border-radius: 6px;
}

/* document body with a one-shot reading sweep */
.gsr-card-body {
  position: relative; padding: 11px 14px 13px; max-height: 112px; overflow: hidden;
  font-size: 11.6px; line-height: 1.6; color: var(--gsr-g700); white-space: pre-wrap;
  letter-spacing: -0.003em;
}
.gsr-card-body::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 36px;
  background: linear-gradient(180deg, rgba(255,255,255,0) 0%, #fff 92%);
}
.gsr-card.is-focus.has-body .gsr-card-body .gsr-sweep {
  position: absolute; left: 0; right: 0; top: 0; height: 26px; z-index: 0;
  background: linear-gradient(180deg, rgba(37,99,235,0) 0%, rgba(37,99,235,0.10) 50%, rgba(37,99,235,0) 100%);
  animation: gsr-sweep 1500ms var(--gsr-ease) forwards;
}

/* policy verification chip */
.gsr-chip {
  display: inline-flex; align-items: center; gap: 7px; margin: 0 14px 12px;
  font-size: 12px; font-weight: 700; color: var(--gsr-good);
  background: var(--gsr-good-soft); border: 1px solid #cae6d7;
  padding: 5px 11px; border-radius: 999px;
}
.gsr-chip .tick { font-size: 11px; }

.gsr-note-text { padding: 11px 14px; font-size: 12.5px; color: var(--gsr-g700); font-style: italic; white-space: normal; }

/* ---- status line ---- */
.gsr-status {
  display: flex; align-items: center; gap: 10px;
  padding: 12px 18px; border-top: 1px solid var(--gsr-g100);
  font-size: 13px; font-weight: 600; color: var(--gsr-navy);
}
.gsr-spin {
  width: 14px; height: 14px; flex: 0 0 auto; border-radius: 50%;
  border: 2px solid var(--gsr-g200); border-top-color: var(--gsr-accent);
  animation: gsr-rot 900ms linear infinite;
}
.gsr-status-email {
  margin-left: auto; padding-left: 14px; flex: 0 0 auto;
  font-weight: 500; color: var(--gsr-g500); white-space: nowrap;
}

/* ---- Leaflet pins (JS-created, global) ---- */
.gs-pin { position: relative; width: 0; height: 0; }
.gs-pin .pin-body { position: absolute; left: -13px; top: -34px; width: 26px; height: 34px;
  transform-origin: 50% 100%; animation: gsr-pin-drop 700ms cubic-bezier(0.22,1.4,0.36,1) both; }
.gs-pin .pin-svg { display: block; filter: drop-shadow(0 4px 7px rgba(26,54,93,0.40)); }
.gs-pin .pulse { position: absolute; left: -13px; top: -2px; width: 26px; height: 13px; }
.gs-pin .pulse::before { content: ""; position: absolute; left: 50%; top: 50%; width: 18px; height: 18px;
  margin: -9px 0 0 -9px; border-radius: 50%; border: 2px solid rgba(37,99,235,0.55);
  animation: gsr-ping 2600ms ease-out infinite; }
.gs-pin.gs-pin-comp .pin-body { left: -9px; top: -24px; width: 18px; height: 24px;
  animation: gsr-pin-drop 620ms cubic-bezier(0.22,1.4,0.36,1) both; }
.gs-pin.gs-pin-comp .pin-svg { filter: drop-shadow(0 3px 5px rgba(16,24,40,0.30)); }
.gs-pin-comp .comp-flag {
  position: absolute; left: 0; top: -46px; transform: translateX(-50%); white-space: nowrap;
  font-family: "Inter", system-ui, sans-serif; font-size: 9.5px; font-weight: 800;
  line-height: 1; letter-spacing: 0.04em; text-transform: uppercase;
  color: var(--gsr-good, #16794a); background: #fff; border: 1px solid #cae6d7;
  border-radius: 999px; padding: 3px 7px; box-shadow: 0 2px 7px rgba(16,24,40,0.22);
  animation: gsr-flag-in 460ms ease 200ms both;
}
.gs-pin-comp.refused .comp-flag { color: #c2362b; border-color: #f3c9c4; }
.gs-pin-comp.other .comp-flag { color: #6b7280; border-color: #d1d5db; }

/* stacked-group flag: per-category coloured segments + middot separators */
.gs-pin-comp.mixed .comp-flag { color: #374151; border-color: #d1d5db; }
.gs-pin-comp .comp-flag .seg.approved { color: #16794a; }
.gs-pin-comp .comp-flag .seg.refused { color: #c2362b; }
.gs-pin-comp .comp-flag .seg.other { color: #6b7280; }
.gs-pin-comp .comp-flag .mid { color: #d1d5db; margin: 0 3px; }

/* count disc over the pin head of a stacked group */
.gs-pin-comp .comp-count {
  position: absolute; left: 3px; top: -28px; min-width: 14px; height: 14px;
  border-radius: 999px; background: #1a365d; color: #fff; border: 1.5px solid #fff;
  font-family: "Inter", system-ui, sans-serif; font-size: 9px; font-weight: 800;
  line-height: 14px; text-align: center; padding: 0 3px; box-sizing: border-box;
  box-shadow: 0 2px 5px rgba(16,24,40,0.3);
}

/* setIcon swaps the whole element on a count bump: suppress the re-drop entrance,
   bump the flag instead (its own animation, replacing gsr-flag-in's shorthand). */
.gs-pin.gs-update .pin-body { animation: none; }
.gs-pin.gs-update .comp-flag { animation: gsr-flag-bump 420ms cubic-bezier(0.22,1.4,0.36,1) both; }

/* focused comparable ("reading decision X"): static border/shadow signal plus a
   looping pulse. The pulse is its OWN animation because gsr-flag-in's fill-mode
   would beat a plain transform rule (same trap as the card entrance). */
.gs-pin-comp.gs-focused .comp-flag {
  border-color: rgba(37,99,235,0.55);
  box-shadow: 0 0 0 3px rgba(37,99,235,0.14), 0 2px 7px rgba(16,24,40,0.22);
  animation: gsr-focus-flag 1500ms ease-in-out infinite;
}
.gs-pin-comp.gs-focused::after {       /* ring at the pin tip, like the site pulse */
  content: ""; position: absolute; left: -9px; top: -9px; width: 18px; height: 18px;
  border-radius: 50%; border: 2px solid rgba(37,99,235,0.55);
  animation: gsr-ping 1800ms ease-out infinite;
}

/* ---- keyframes ---- */
/* No opacity in `to`: the animation interpolates to the underlying cascade value
   (1 for is-focus, 0.5 for is-past), so a card that mounts already demoted fades to
   its dimmed state instead of brightening to 1 and snapping when the fill releases
   (animation-end reversion does not fire transitions). */
@keyframes gsr-card-in { from { opacity: 0; transform: translateY(22px); } to { transform: translateY(0); } }
@keyframes gsr-sweep { 0% { transform: translateY(-10px); opacity: 0; } 20% { opacity: 1; } 100% { transform: translateY(96px); opacity: 0; } }
@keyframes gsr-pulse { 0%,100% { opacity: 0.4; transform: scale(1); } 50% { opacity: 1; transform: scale(1.3); } }
@keyframes gsr-rot { to { transform: rotate(360deg); } }
@keyframes gsr-pin-drop { 0% { transform: translateY(-26px) scale(0.6); opacity: 0; } 60% { opacity: 1; } 100% { transform: translateY(0) scale(1); opacity: 1; } }
/* The flag keeps its translateX(-50%) centring through the entrance. */
@keyframes gsr-flag-in { 0% { opacity: 0; transform: translate(-50%, -6px); } 100% { opacity: 1; transform: translate(-50%, 0); } }
@keyframes gsr-flag-bump {
  0% { transform: translate(-50%, 0) scale(1); }
  35% { transform: translate(-50%, -4px) scale(1.14); }
  100% { transform: translate(-50%, 0) scale(1); }
}
@keyframes gsr-focus-flag {
  0%, 100% { transform: translate(-50%, 0) scale(1); }
  50% { transform: translate(-50%, -2px) scale(1.08); }
}
@keyframes gsr-ping { 0% { transform: scale(0.4); opacity: 0.85; } 80% { transform: scale(3.4); opacity: 0; } 100% { transform: scale(3.4); opacity: 0; } }

/* ---- mobile: stack map above the column ---- */
@media (max-width: 720px) {
  .gsr-body { grid-template-columns: 1fr; grid-template-rows: auto; height: auto; }
  .gsr-map { height: 220px; }
  .gsr-col { border-left: none; border-top: 1px solid var(--gsr-g100); }
  .gsr-track { height: 320px; }
  .gsr-head .gsr-tally { margin-left: 0; flex-basis: 100%; }
  /* The live caption needs the whole row on narrow screens. */
  .gsr-status-email { display: none; }
}

/* ---- reduced motion ---- */
@media (prefers-reduced-motion: reduce) {
  .gsr-card, .gs-pin .pin-body, .gs-pin.gs-pin-comp .pin-body, .gs-pin-comp .comp-flag { animation: none !important; }
  /* focus highlight keeps its static border/shadow; only the motion goes */
  .gs-pin-comp.gs-focused .comp-flag, .gs-pin-comp.gs-focused::after { animation: none !important; }
  .gsr-card-wrap, .gsr-card { transition: none !important; }
  .gsr-card.is-focus.has-body .gsr-card-body .gsr-sweep { animation: none !important; opacity: 0 !important; }
  .gsr-spin, .gsr-assessing .dot, .gs-pin .pulse::before { animation: none !important; }
}
