/* Hawk Mesh Site Planner
 *
 * Palette taken from the Hawk Mesh site and coverage map so this reads as
 * part of the same product: deep red on a warm charcoal, coral for accents,
 * Helvetica Neue with wide letterspacing on uppercase labels.
 */

:root {
  --red:        #A81824;
  --red-bright: #d0212f;
  --red-hover:  #8f1320;
  --coral:      #f0997b;
  --charcoal:   #241818;
  --ink:        #2c2222;
  --panel:      #1a1010;
  --panel-2:    #241818;
  --panel-3:    #2c2222;
  --line:       rgba(255,255,255,.09);
  --line-soft:  rgba(255,255,255,.055);
  --text:       #f4ecec;
  --dim:        #c0b0b0;
  --dimmer:     #9a8e8e;
  --cream:      #faf6f6;

  /* Status colours, warmed slightly so they sit inside the palette. */
  --good: #4fc98a;
  --warn: #e8a33c;
  --bad:  #ef5f6b;
  --link: #7fb2e8;

  --hawk:      var(--red);
  --hawk-glow: rgba(168, 24, 36, .35);
  --radius: 10px;
  --mono: ui-monospace, "SF Mono", Menlo, monospace;
  --sans: "Helvetica Neue", Helvetica, Arial, sans-serif;
}

* { box-sizing: border-box; }

html, body {
  margin: 0; height: 100%; overflow: hidden;
  background: var(--charcoal); color: var(--text);
  font: 14px/1.55 var(--sans);
  -webkit-font-smoothing: antialiased;
  /* Dragging the aim handle across the map must not smear a text selection
     over the whole UI. Inputs opt back in below. */
  user-select: none; -webkit-user-select: none;
}

input, textarea, select, .coord, .leaflet-popup-content {
  user-select: text; -webkit-user-select: text;
}

#map { position: absolute; inset: 0; background: #0d0808; }

/* ---------------------------------------------------------------- chrome */

.topbar {
  position: absolute; top: 0; left: 0; right: 0; height: 56px; z-index: 900;
  display: flex; align-items: center; gap: 18px; padding: 0 18px;
  background: linear-gradient(180deg, rgba(26,16,16,.97), rgba(26,16,16,.84) 70%, transparent);
  pointer-events: none;
}
.topbar > * { pointer-events: auto; }

.brand { display: flex; align-items: center; gap: 13px; }
.brand img { height: 30px; width: auto; display: block; }
.brand .tag {
  font-size: 11px; font-weight: 700; letter-spacing: .15em;
  text-transform: uppercase; color: var(--coral);
  border-left: 1px solid var(--line); padding-left: 13px;
}

.stat-strip { display: flex; gap: 22px; margin-left: auto;
  padding-right: 6px; }
.stat { text-align: right; line-height: 1.15; }
.stat b { display: block; font-family: var(--mono); font-size: 15px; }
.stat span { font-size: 10px; white-space: nowrap; color: var(--dimmer); text-transform: uppercase;
  letter-spacing: .09em; }

/* --------------------------------------------------------------- panels */

.panel {
  position: absolute; z-index: 850;
  background: rgba(20,12,12,.94);
  backdrop-filter: blur(18px) saturate(1.3);
  -webkit-backdrop-filter: blur(18px) saturate(1.3);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: 0 18px 50px rgba(0,0,0,.55);
}

#sidebar { top: 66px; left: 14px; bottom: 14px; width: 330px;
  display: flex; flex-direction: column; }
#inspector { top: 66px; right: 14px; width: 356px; max-height: calc(100% - 80px);
  display: flex; flex-direction: column; }

.panel-head {
  padding: 13px 15px 11px; border-bottom: 1px solid var(--line-soft);
  display: flex; align-items: center; gap: 9px; flex: 0 0 auto;
}
.panel-head h2 { margin: 0; font-size: 11px; letter-spacing: .16em;
  text-transform: uppercase; color: var(--dim); font-weight: 600; }
.panel-head .count { margin-left: auto; font-family: var(--mono);
  font-size: 11px; color: var(--dimmer); }
.panel-body { overflow-y: auto; padding: 9px; flex: 1 1 auto; }
.panel-body::-webkit-scrollbar,
.panel-scroll::-webkit-scrollbar { width: 9px; }
.panel-body::-webkit-scrollbar-thumb,
.panel-scroll::-webkit-scrollbar-thumb { background: #3a2a2a; border-radius: 9px;
  border: 2px solid var(--panel); }

/* One scroll column for everything under the inspector head. min-height: 0
 * is what lets a flex child actually shrink and scroll instead of forcing
 * the panel taller than its max-height and clipping the tail. */
.panel-scroll { overflow-y: auto; flex: 1 1 auto; min-height: 0;
  display: flex; flex-direction: column; }
.panel-scroll .panel-body { overflow-y: visible; flex: none; }

/* Inspector tab panes. The tab strip must never be squashed by pane
 * content, and a disabled tab reads as present-but-not-yet: Radio and Solar
 * mean nothing until a node exists to configure. */
#inspector > .seg.tabs { flex: 0 0 auto; }
.itab { flex: 0 0 auto; }
.seg button:disabled { opacity: .35; cursor: default; }
.seg button:disabled:hover { background: none; color: var(--dim); }

/* ------------------------------------------------------------ site cards */

.site {
  padding: 10px 11px; border-radius: 9px; cursor: pointer; margin-bottom: 5px;
  border: 1px solid transparent; transition: background .12s, border-color .12s;
}
.site:hover { background: var(--panel-2); border-color: rgba(255,255,255,.14); }
.site.active { background: rgba(168,24,36,.18);
  border-color: rgba(208,33,47,.65); }

.site-top { display: flex; align-items: baseline; gap: 8px; }
.site .rank { font-family: var(--mono); font-weight: 700; color: var(--hawk);
  font-size: 12px; min-width: 26px; }
.site.park .rank { color: var(--warn); }
.site .elev { font-weight: 600; font-size: 15px; }
.site .score { margin-left: auto; font-family: var(--mono); font-size: 12px;
  color: var(--dim); }
.site-sub { display: flex; gap: 9px; margin-top: 4px; padding-left: 34px;
  font-size: 11.5px; color: var(--dimmer); flex-wrap: wrap; }
.site-sub .tag { font-family: var(--mono); }
.site-sub .tag.ok { color: var(--good); }
.site-sub .tag.warn { color: var(--warn); }
.site-sub .tag.none { color: var(--bad); }

.scorebar { height: 3px; border-radius: 2px; background: rgba(255,255,255,.08);
  margin-top: 8px; margin-left: 34px; overflow: hidden; }
.scorebar i { display: block; height: 100%;
  background: linear-gradient(90deg, var(--red), var(--coral)); }

/* -------------------------------------------------------------- controls */

.ctl { padding: 12px 14px; border-bottom: 1px solid var(--line-soft); }
.ctl:last-child { border-bottom: none; }
.ctl label { display: block; font-size: 10px; text-transform: uppercase;
  letter-spacing: .14em; color: var(--dimmer); margin-bottom: 7px;
  font-weight: 700; }
.field-hint { margin: 7px 2px 0; font-size: 11.5px; line-height: 1.45;
  color: var(--dimmer); }

select, input[type=text] {
  width: 100%; padding: 8px 10px; border-radius: 8px; font: inherit;
  font-size: 13px; background: var(--panel-2); color: var(--text);
  border: 1px solid var(--line); outline: none;
}
select:focus, input:focus { border-color: var(--red-bright); }

input[type=range] { width: 100%; accent-color: var(--red-bright); }

.row { display: flex; gap: 9px; align-items: center; }
.row > * { flex: 1; }
.val { font-family: var(--mono); font-size: 12px; color: var(--text);
  flex: 0 0 auto; min-width: 54px; text-align: right; }

button.act {
  width: 100%; padding: 10px; border-radius: 9px; cursor: pointer;
  font: inherit; font-weight: 600; font-size: 13px;
  background: var(--red); color: #fff; border: none;
  letter-spacing: .04em;
  box-shadow: 0 4px 16px var(--hawk-glow);
}
button.act:hover { background: var(--red-bright); }
button.act:hover { filter: brightness(1.1); }
button.act.ghost { background: var(--panel-2); color: var(--text);
  border: 1px solid var(--line); box-shadow: none; }
button.act:disabled { opacity: .45; cursor: default; }

.seg { display: flex; background: var(--panel-2); border: 1px solid var(--line);
  border-radius: 8px; overflow: hidden; }
.seg button { flex: 1; padding: 7px 4px; background: none; border: none;
  color: var(--dim); font: inherit; font-size: 12px; cursor: pointer; }
.seg button.on { background: var(--red); color: #fff; font-weight: 700; }

/* ------------------------------------------------------------- inspector */

.insp-title { padding: 14px 15px 10px; border-bottom: 1px solid var(--line-soft); }
.insp-title h3 { margin: 0 0 3px; font-size: 17px; }
.insp-title .coord { font-family: var(--mono); font-size: 11.5px;
  color: var(--dim); cursor: pointer; }
.insp-title .coord:hover { color: var(--link); }

.metrics { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1px;
  background: var(--line-soft); border-bottom: 1px solid var(--line-soft); }
.metric { background: var(--panel); padding: 10px 8px; text-align: center; }
.metric b { display: block; font-family: var(--mono); font-size: 16px; }
.metric span { font-size: 9px; color: var(--dimmer); text-transform: uppercase;
  letter-spacing: .1em; font-weight: 700; }

.rec { margin: 12px 14px; padding: 12px; border-radius: 10px;
  background: linear-gradient(145deg, rgba(168,24,36,.22), rgba(168,24,36,.06));
  border: 1px solid rgba(208,33,47,.38); }
.rec h4 { margin: 0 0 3px; font-size: 10px; letter-spacing: .14em;
  font-weight: 700; text-transform: uppercase; color: var(--coral); }
.rec .pick { font-size: 15px; font-weight: 600; margin-bottom: 2px; }
.rec .aim { font-family: var(--mono); font-size: 12px; color: var(--text);
  margin-bottom: 7px; }
.rec p { margin: 0; font-size: 12px; color: var(--dim); line-height: 1.5; }
.rec button { margin-top: 10px; }

.linklist { padding: 4px 10px 12px; }
.linklist h4 { margin: 12px 4px 7px; font-size: 10px; letter-spacing: .14em;
  font-weight: 700; text-transform: uppercase; color: var(--dimmer); }
.lk { display: flex; align-items: center; gap: 9px; padding: 7px 8px;
  border-radius: 7px; font-size: 12.5px; }
.lk:hover { background: var(--panel-2); }
.lk .bar { width: 3px; height: 26px; border-radius: 2px; flex: 0 0 auto; }
.lk .nm { flex: 1; overflow: hidden; text-overflow: ellipsis;
  white-space: nowrap; }
.lk .dt { font-family: var(--mono); font-size: 11.5px; color: var(--dim);
  text-align: right; flex: 0 0 auto; }

/* ---------------------------------------------------------------- legend */

#legend { bottom: 14px; left: 358px; padding: 11px 13px; font-size: 11.5px; }
#legend h4 { margin: 0 0 8px; font-size: 10px; letter-spacing: .14em;
  font-weight: 700; text-transform: uppercase; color: var(--dimmer); }
.lgrow { display: flex; align-items: center; gap: 8px; margin: 4px 0;
  color: var(--dim); }
.sw { width: 12px; height: 12px; border-radius: 50%; flex: 0 0 auto; }
.swline { width: 16px; height: 0; flex: 0 0 auto; }

.ramp { height: 9px; border-radius: 5px; margin: 7px 0 4px;
  background: linear-gradient(90deg, #3b1d5e, #1d4e89, #12857f, #63a832, #e8c520, #e85d20); }
.ramp-lab { display: flex; justify-content: space-between;
  font-family: var(--mono); font-size: 10px; color: var(--dimmer); }

/* ---------------------------------------------------------------- misc */

.toast {
  position: absolute; bottom: 18px; left: 50%; transform: translateX(-50%);
  z-index: 1200; padding: 9px 16px; border-radius: 999px; font-size: 12.5px;
  background: rgba(20,12,12,.96); border: 1px solid var(--line);
  box-shadow: 0 8px 28px rgba(0,0,0,.6); opacity: 0;
  transition: opacity .2s; pointer-events: none;
}
.toast.show { opacity: 1; }

.spinner { display: inline-block; width: 12px; height: 12px; margin-right: 7px;
  border: 2px solid var(--line); border-top-color: var(--coral);
  border-radius: 50%; animation: spin .7s linear infinite;
  vertical-align: -2px; }
@keyframes spin { to { transform: rotate(360deg); } }

.empty { padding: 40px 20px; text-align: center; color: var(--dimmer);
  font-size: 13px; line-height: 1.6; }

/* Leaflet overrides so controls match the dark shell. */
.leaflet-control-zoom a {
  background: rgba(20,12,12,.94) !important; color: var(--text) !important;
  border-color: var(--line) !important;
}
.leaflet-control-zoom a:hover { background: var(--panel-2) !important; }
.leaflet-control-attribution {
  background: rgba(13,8,8,.8) !important; color: var(--dimmer) !important;
  font-size: 10px !important;
}
.leaflet-control-attribution a { color: var(--dim) !important; }
.leaflet-popup-content-wrapper, .leaflet-popup-tip {
  background: var(--panel); color: var(--text); border: 1px solid var(--line);
  box-shadow: 0 12px 36px rgba(0,0,0,.6);
}
.leaflet-popup-content { margin: 12px 14px; font-size: 13px; }
.leaflet-popup-content b { color: var(--text); }
.leaflet-container { background: #0d0808; font-family: var(--sans); }

@media (max-width: 1100px) {
  #sidebar { width: 280px; }
  #inspector { width: 310px; }
  #legend { left: 306px; }
}
/* ------------------------------------------------------- phones / tablets */

/* The bottom bar only exists on narrow screens. */
.mobilebar { display: none; }

@media (max-width: 820px) {
  /* On a phone the map IS the app. The two side panels stop being fixed
     furniture that squeezes the map into a strip between them, and become
     bottom sheets you pull up from a tab bar - closed by default, so you land
     on a full-screen map and can just place a node. */
  #sidebar, #inspector {
    /* fixed, not absolute: the sheets and the tab bar must be positioned
       against the same viewport, or they disagree about where "the bottom"
       is and the sheet parks in the wrong place. */
    position: fixed;
    left: 0; right: 0; width: auto; top: auto;
    display: block; overflow-y: auto; -webkit-overflow-scrolling: touch;
    max-height: min(55vh, calc(100vh - 150px));
    border-radius: 15px 15px 0 0;
    border-left: 0; border-right: 0; border-bottom: 0;
    /* Sit directly on top of the tab bar when open. Closing must travel the
       panel's own height PLUS that offset, or the top of the sheet stays
       poking above the bottom edge. */
    bottom: calc(60px + env(safe-area-inset-bottom, 0px));
    transform: translateY(calc(100% + 72px + env(safe-area-inset-bottom, 0px)));
    transition: transform .22s ease;
    z-index: 1150;
    box-shadow: 0 -14px 40px rgba(0,0,0,.55);
  }
  body.sheet-sidebar   #sidebar   { transform: none; }
  body.sheet-inspector #inspector { transform: none; }

  /* A grab handle, so it reads as a sheet you can dismiss. */
  #sidebar::before, #inspector::before {
    content: ''; display: block; width: 38px; height: 4px; border-radius: 3px;
    background: rgba(255,255,255,.22); margin: 9px auto 2px;
  }

  /* Inside a scrolling column nothing may flex or clip. */
  #sidebar .pane, #inspector .itab { display: block; }
  #sidebar .panel-body, #inspector .panel-body {
    overflow: visible; max-height: none; flex: none;
  }
  #sidebar > .seg.tabs, #sidebar > .ctl,
  .pane > .panel-head, .pane > .ctl, .pane > .panel-body { flex: none; }

  #legend { display: none; }

  /* Leaflet's zoom buttons must clear the bar. */
  .leaflet-bottom.leaflet-right {
    bottom: calc(58px + env(safe-area-inset-bottom, 0px));
  }

  .mobilebar {
    display: flex; position: fixed; left: 0; right: 0; bottom: 0; z-index: 1300;
    background: rgba(20,12,12,.97);
    backdrop-filter: blur(16px); -webkit-backdrop-filter: blur(16px);
    border-top: 1px solid var(--line);
    padding-bottom: env(safe-area-inset-bottom, 0px);
  }
  .mobilebar button {
    flex: 1; background: none; border: 0; color: var(--dimmer);
    font: inherit; font-size: 10.5px; font-weight: 700; letter-spacing: .06em;
    text-transform: uppercase; padding: 9px 4px 10px; cursor: pointer;
    display: flex; flex-direction: column; align-items: center; gap: 3px;
    -webkit-tap-highlight-color: transparent;
  }
  .mobilebar button svg { width: 21px; height: 21px; stroke: currentColor;
    fill: none; stroke-width: 1.7; }
  .mobilebar button.on { color: var(--coral); }

  /* ---- compact chrome ----
     The top bar was laid out for a desktop: logo + wordmark + sign-in + two
     stats needs ~470px, so on a phone it overflowed and clipped the area name.
     Strip it to the essentials and let the name truncate instead of run off. */
  .topbar { height: 48px; gap: 10px; padding: 0 12px; }
  .brand { gap: 9px; }
  .brand img { height: 22px; }
  .brand .tag { display: none; }          /* the logo is the brand already */
  .stat-strip { gap: 12px; min-width: 0; }
  .stat { min-width: 0; }
  .stat b { font-size: 12.5px; max-width: 42vw; overflow: hidden;
            text-overflow: ellipsis; white-space: nowrap; }
  .stat span { font-size: 8.5px; letter-spacing: .07em; }
  .acct { padding: 6px 11px; font-size: 11.5px; white-space: nowrap; }

  /* ---- sheet contents: shrink to fit, never clip ----
     Everything inside was sized for a 356px desktop panel. On a narrow phone
     the four-tab strip and the mast presets were the first to overflow, so the
     last option simply vanished off the right edge. */
  #sidebar, #inspector { max-width: 100%; }
  .ctl { padding: 11px 13px; }
  .ctl label { font-size: 9.5px; letter-spacing: .1em; margin-bottom: 6px; }
  .seg { width: 100%; }
  .seg button { min-width: 0; padding: 8px 2px; font-size: 11px;
                letter-spacing: 0; white-space: nowrap; overflow: hidden;
                text-overflow: ellipsis; }
  /* width:auto, not 100% - this one carries side margins, and a 100% width
     plus margins overflows the panel and puts a scrollbar under the sheet. */
  .seg.tabs { margin: 10px 12px 0; width: auto; }
  .seg.tabs button { padding: 9px 2px; font-size: 11.5px; }
  select, input[type=text] { font-size: 15px; }  /* >=16px avoids iOS zoom-on-focus
                                                    at 16; 15 is fine with the
                                                    viewport lock we set */
  .metrics { grid-template-columns: repeat(3, 1fr); }
  .metric b { font-size: 15px; }
  .metric span { font-size: 8.5px; letter-spacing: .06em; }
  .val { min-width: 46px; font-size: 11.5px; }
  .ant-pick { gap: 9px; }
  .ant-pick #antenna-icon { width: 28px; height: 28px; }
  .clientpick { gap: 9px; }
  .devart { width: 52px; }
}

/* --------------------------------------------- on-map dismiss badge -------
 * Anything the app draws over the map that the user asked for - a scanned
 * box, a planned route - carries its own way out, right where it is. Having
 * to hunt back through a panel for the control that made it was the clunky
 * part. */
.mapbadge {
  display: flex; align-items: center; gap: 7px; white-space: nowrap;
  background: rgba(20,12,12,.94); border: 1px solid var(--line);
  border-radius: 999px; padding: 5px 6px 5px 12px;
  font: 700 11px/1 var(--sans); letter-spacing: .06em; text-transform: uppercase;
  color: var(--coral); box-shadow: 0 6px 20px rgba(0,0,0,.55);
  backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);
}
.mapbadge button {
  width: 20px; height: 20px; border-radius: 50%; border: 0; cursor: pointer;
  background: rgba(255,255,255,.10); color: var(--text);
  font: 400 14px/1 var(--sans); display: grid; place-items: center;
  -webkit-tap-highlight-color: transparent;
}
.mapbadge button:hover { background: var(--red); color: #fff; }
@media (max-width: 820px) {
  /* Bigger tap target on a phone. */
  .mapbadge { padding: 7px 7px 7px 13px; font-size: 11.5px; }
  .mapbadge button { width: 26px; height: 26px; font-size: 16px; }
}

/* Very narrow phones: one more notch down so nothing has to clip. */
@media (max-width: 400px) {
  .stat b { max-width: 38vw; }
  .seg button { font-size: 10px; }
  .seg.tabs button { font-size: 10.5px; }
  .metrics { grid-template-columns: repeat(2, 1fr); }
  .mobilebar button { font-size: 9.5px; }
}

@media (max-width: 520px) {
  .layergrid { grid-template-columns: 1fr; }
  .seg.tabs button, .seg button { font-size: 11px; }
  .metrics { grid-template-columns: repeat(2, 1fr); }
}


/* ------------------------------------------------- antenna picker + aiming */

.ant-pick { display: flex; align-items: center; gap: 11px; }
.ant-pick #antenna-icon { flex: 0 0 auto; width: 34px; height: 34px;
  display: grid; place-items: center; }
.ant-spec { font-family: var(--mono); font-size: 10.5px; color: var(--dimmer);
  margin-top: 5px; }

/* States which receiver the painted coverage belongs to. Goes warm when the
 * footprint is bound to the probe device, because in that mode it moves. */
.cov-rx-note { font-size: 11px; line-height: 1.45; color: var(--dimmer);
  margin-top: 8px; padding-left: 8px; border-left: 2px solid var(--line-soft); }
.cov-rx-note.bound { color: var(--coral, #f0997b); border-left-color: #d0212f; }

/* Which product this node is. Carries the brand red so a Hawk unit is
 * distinguishable from a bare dev board at a glance down the list. */
.tag.hw { background: rgba(208, 33, 47, .14); border-color: rgba(208, 33, 47, .4);
  color: var(--coral, #f0997b); }
.hwpick { padding-top: 11px; padding-bottom: 11px; }

.rec-head { display: flex; align-items: flex-start; gap: 11px; }
.rec-head > svg { flex: 0 0 auto; margin-top: 1px; }

/* The grab handle at the end of the boresight line. */
.aim-handle {
  width: 30px; height: 30px; border-radius: 50%;
  display: grid; place-items: center; cursor: grab;
  background: rgba(20,12,12,.95); border: 2px solid var(--coral);
  box-shadow: 0 0 0 4px rgba(240,153,123,.16), 0 4px 14px rgba(0,0,0,.5);
  transition: transform .12s, box-shadow .12s;
}
.aim-handle:hover { transform: scale(1.12);
  box-shadow: 0 0 0 6px rgba(240,153,123,.22), 0 4px 14px rgba(0,0,0,.5); }
.aim-handle:active { cursor: grabbing; }
.aim-handle span { font-family: var(--mono); font-size: 9.5px;
  font-weight: 700; color: var(--coral); letter-spacing: -.02em; }

#mast-presets button { font-family: var(--mono); font-size: 11px; }


/* --------------------------------------------------------- account + modal */

.acct {
  padding: 7px 15px; border-radius: 8px; cursor: pointer;
  font: inherit; font-size: 12px; font-weight: 700; letter-spacing: .06em;
  text-transform: uppercase;
  background: rgba(255,255,255,.05); color: var(--text);
  border: 1px solid var(--line);
}
.acct:hover { background: var(--red); border-color: var(--red); }
.acct.in { border-color: rgba(240,153,123,.5); color: var(--coral); }

.modal-backdrop {
  position: absolute; inset: 0; z-index: 1500; display: none;
  background: rgba(10,6,6,.72); backdrop-filter: blur(4px);
  align-items: center; justify-content: center; padding: 20px;
}
.modal-backdrop.show { display: flex; }
.modal { position: relative; width: 100%; max-width: 420px;
  max-height: 86vh; display: flex; flex-direction: column; }
.modal-head { display: flex; align-items: center; padding: 15px 17px 13px;
  border-bottom: 1px solid var(--line-soft); }
.modal-head h3 { margin: 0; font-size: 15px; letter-spacing: .04em; }
.modal-x { margin-left: auto; background: none; border: none; cursor: pointer;
  color: var(--dimmer); font-size: 24px; line-height: 1; padding: 0 4px; }
.modal-x:hover { color: var(--text); }
.modal-body { padding: 16px 17px 18px; overflow-y: auto; }
/* The "why you're seeing this" line above a gated sign-up form. */
.modal-body .au-reason {
  background: rgba(240,153,123,.10); border: 1px solid rgba(240,153,123,.30);
  border-radius: 9px; padding: 11px 13px; margin-bottom: 4px;
  font-size: 13px; line-height: 1.45; color: var(--text);
}
.modal-body .au-reason + label { margin-top: 14px; }
.modal-body label { display: block; font-size: 10px; font-weight: 700;
  text-transform: uppercase; letter-spacing: .14em; color: var(--dimmer);
  margin: 12px 0 6px; }
.modal-body label:first-child { margin-top: 0; }
.modal-body input[type=text], .modal-body input[type=email],
.modal-body input[type=password] {
  width: 100%; padding: 9px 11px; border-radius: 8px; font: inherit;
  font-size: 13px; background: var(--panel-2); color: var(--text);
  border: 1px solid var(--line); outline: none;
}
.modal-body .consent { display: flex; gap: 9px; align-items: flex-start;
  margin: 14px 0 4px; font-size: 12px; color: var(--dim);
  text-transform: none; letter-spacing: 0; font-weight: 400; }
.modal-body .consent input { margin-top: 2px; accent-color: var(--red-bright); }
.modal-body .err { color: var(--bad); font-size: 12px; margin-top: 10px; }
.modal-body .muted { color: var(--dimmer); font-size: 11.5px;
  line-height: 1.55; margin-top: 12px; }
.modal-body .switch { margin-top: 14px; font-size: 12px; color: var(--dim);
  text-align: center; }
.modal-body .switch a { color: var(--coral); cursor: pointer;
  text-decoration: none; }
.modal-body button.act { margin-top: 16px; }

.plan-row { display: flex; align-items: center; gap: 10px; padding: 10px;
  border-radius: 8px; cursor: pointer; border: 1px solid transparent; }
.plan-row:hover { background: var(--panel-2); border-color: var(--line); }
.plan-row .pn { flex: 1; min-width: 0; }
.plan-row .pn b { display: block; font-size: 13.5px; font-weight: 600; }
.plan-row .pn span { font-size: 11px; color: var(--dimmer); }
.plan-row .del { background: none; border: none; color: var(--dimmer);
  cursor: pointer; font-size: 16px; padding: 2px 6px; }
.plan-row .del:hover { color: var(--bad); }

/* ------------------------------------------------------ tabs and panes */

.seg.tabs { margin: 12px 14px 0; }
.seg.tabs button { padding: 9px 4px; font-weight: 600; letter-spacing: .03em; }
.pane { display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0; }
.prospect-note { padding: 0 15px 11px; font-size: 11.5px; color: var(--dimmer);
  line-height: 1.5; }
.linkbtn { margin-left: auto; background: none; border: none; cursor: pointer;
  color: var(--dimmer); font: inherit; font-size: 11px; padding: 0; }
.linkbtn:hover { color: var(--coral); }

.layergrid { display: grid; grid-template-columns: 1fr 1fr; gap: 5px; }
.layergrid label { text-transform: none; letter-spacing: 0; margin: 0;
  font-size: 12px; color: var(--dim); font-weight: 400; }
.layergrid input { accent-color: var(--red-bright); }

/* Dropping mode: make it obvious the map is the input surface. */
#map.dropping { cursor: crosshair; }

.empty .drop-hint {
  width: 42px; height: 42px; margin: 0 auto 12px; border-radius: 50%;
  display: grid; place-items: center; font-size: 24px; font-weight: 300;
  color: var(--coral); border: 2px dashed rgba(240,153,123,.45);
}
.empty b { color: var(--text); font-size: 13.5px; }
.empty a { color: var(--coral); cursor: pointer; }

/* -------------------------------------------------------------- node pin */

.node-pin {
  width: 30px; height: 30px; border-radius: 50% 50% 50% 4px;
  transform: rotate(-45deg);
  background: var(--red); border: 2px solid rgba(255,255,255,.85);
  box-shadow: 0 4px 12px rgba(0,0,0,.55);
  display: grid; place-items: center; cursor: grab;
  transition: transform .12s, box-shadow .12s;
}
.node-pin span { transform: rotate(45deg); font-family: var(--mono);
  font-size: 12px; font-weight: 700; color: #fff; }
.node-pin.sel {
  background: var(--red-bright);
  box-shadow: 0 0 0 5px rgba(240,153,123,.25), 0 4px 14px rgba(0,0,0,.6);
}
.node-pin:active { cursor: grabbing; }

.node-row .del, .cand-row .del { margin-left: auto; background: none;
  border: none; color: var(--dimmer); cursor: pointer; font-size: 17px;
  line-height: 1; padding: 0 3px; }
.node-row .del:hover { color: var(--bad); }
.node-row .elev { font-size: 13.5px; }

.addbtn { margin-top: 9px; padding: 6px; font-size: 11.5px; }
.popbtn { margin-top: 8px; padding: 6px 12px; border-radius: 7px;
  background: var(--red); color: #fff; border: none; cursor: pointer;
  font: inherit; font-size: 12px; font-weight: 600; }
.popbtn:hover { background: var(--red-bright); }

/* --------------------------------------------------------- mesh summary */

.msum { display: grid; grid-template-columns: repeat(3,1fr); gap: 1px;
  background: var(--line-soft); border-top: 1px solid var(--line-soft);
  border-bottom: 1px solid var(--line-soft); }
.msum > div { background: var(--panel); padding: 9px 6px; text-align: center; }
.msum b { display: block; font-family: var(--mono); font-size: 15px; }
.msum span { font-size: 9px; text-transform: uppercase; letter-spacing: .1em;
  color: var(--dimmer); font-weight: 700; }

.warnbox, .okbox { margin: 10px 14px; padding: 9px 11px; border-radius: 8px;
  font-size: 11.5px; line-height: 1.5; }
.warnbox { background: rgba(232,163,60,.13); border: 1px solid rgba(232,163,60,.35);
  color: #f0c07a; }
.okbox { background: rgba(79,201,138,.11); border: 1px solid rgba(79,201,138,.3);
  color: #8fdfb4; }

.node-name { width: 100%; background: none; border: none; padding: 0;
  font: inherit; font-size: 17px; font-weight: 600; color: var(--text);
  outline: none; border-bottom: 1px solid transparent; }
.node-name:hover { border-bottom-color: var(--line); }
.node-name:focus { border-bottom-color: var(--red-bright); }

#sidebar { overflow: hidden; }


/* ------------------------------------------------- reception probe + host */

.reception { background: rgba(255,255,255,.025);
  border-bottom: 1px solid var(--line-soft); }
#probe-toggle.on { background: var(--red); color: #fff;
  border-color: var(--red); }
#map.probing { cursor: help; }

.probe-popup .leaflet-popup-content { margin: 0; width: 288px !important; }
.probe { padding: 13px 15px; }
.probe .phead { font-size: 14px; font-weight: 700; letter-spacing: .02em;
  color: var(--text); }
.probe .pc { font-size: 11px; color: var(--dimmer); margin-top: 3px;
  padding-bottom: 9px; border-bottom: 1px solid var(--line-soft); }
.probe .pb { font-size: 11.5px; color: var(--dim); margin-top: 9px;
  line-height: 1.5; }
.probe .pwarn { color: var(--coral, #f0997b); }

/* One row per carry option: what it is, and whether it works. Deliberately
 * not a signal ramp - the answer is a word, not a colour scale. */
.probe .plist { margin-top: 8px; }
.prow { display: flex; align-items: baseline; gap: 10px; padding: 4px 0;
  font-size: 12px; border-bottom: 1px solid var(--line-soft); }
.prow:last-child { border-bottom: 0; }
.prow .nm { flex: 1; color: var(--dim); overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap; }
.prow .ans { font-weight: 700; font-size: 11.5px; letter-spacing: .03em;
  flex: 0 0 auto; }
.prow.yes    .ans { color: #4fc98a; }
.prow.patchy .ans { color: #e8a33c; }
.prow.no     .ans { color: #8d7f7f; }
.prow.no     .nm  { color: var(--dimmer); }
/* The device currently chosen in the picker, so it is findable in the list. */
.prow.sel .nm { color: var(--text); font-weight: 600; }

.probe .popbtn { width: 100%; margin-top: 11px; }

.hostloc { display: flex; align-items: baseline; gap: 9px; padding: 9px 11px;
  border-radius: 8px; background: var(--panel-2); border: 1px solid var(--line);
  margin-bottom: 4px; }
.hostloc b { font-family: var(--mono); font-size: 12.5px; }
.hostloc span { font-size: 11px; color: var(--dimmer); margin-left: auto; }


/* ------------------------------------------------- sidebar flex hardening */

/* Only the scrolling list may flex. Without this the candidate list demands
   height and squashes the tab bar down to a few pixels. */
#sidebar > .seg.tabs,
#sidebar > .ctl,
.pane > .panel-head,
.pane > .ctl,
.pane > .prospect-note,
.pane > #mesh-summary { flex: 0 0 auto; }
.pane > .panel-body { flex: 1 1 auto; min-height: 60px; }
.seg.tabs { min-height: 38px; }
.seg.tabs button { white-space: nowrap; }

/* ---------------------------------------------- prospecting: collapsibles */

/* #pane-prospect no longer relies on one child flex-growing to fill the
   sidebar (the old single #candlist panel-body) — three <details> sections
   stack instead, so the pane itself scrolls and each section's own result
   area gets a capped, independently-scrolling height. */
/* .hh-body inside the health module is flex:1 with overflow-y:auto, but that
   only resolves to a scrollable box if every ancestor gives it a bounded
   height. Without these the pane just grew and the tab overflowed instead of
   scrolling. */
#pane-health { flex: 1 1 auto; min-height: 0; display: flex;
  flex-direction: column; overflow: hidden; }
#health-root { flex: 1 1 auto; min-height: 0; display: flex;
  flex-direction: column; }

/* Grows to take the room an open section needs. Shrink-to-fit looked tidier
   with everything collapsed, but left the candidate list squeezed into a
   sliver the moment it was opened, which is the failure that actually hurts. */
#pane-prospect { flex: 1 1 auto; min-height: 0; overflow-y: auto; }
#pane-prospect > .dsec { flex: 0 0 auto; }

.dsec { border-bottom: 1px solid var(--line-soft); }
.dsec:last-child { border-bottom: none; }
.dsec[open] > .dsec-summary { border-bottom: 1px solid var(--line-soft); }

.dsec-summary {
  display: flex; align-items: center; gap: 9px; cursor: pointer;
  padding: 12px 14px; list-style: none; user-select: none;
  -webkit-tap-highlight-color: transparent;
}
.dsec-summary::-webkit-details-marker { display: none; }
.dsec-summary:hover { background: var(--panel-2); }

.dsec-chev {
  flex: 0 0 auto; width: 8px; height: 8px;
  border-right: 2px solid var(--coral); border-bottom: 2px solid var(--coral);
  transform: rotate(-45deg); transition: transform .15s ease;
  margin-left: 1px;
}
.dsec[open] > .dsec-summary .dsec-chev { transform: rotate(45deg); }

.dsec-title {
  font-size: 11px; letter-spacing: .14em; text-transform: uppercase;
  font-weight: 700; color: var(--text);
}
.dsec-badge {
  margin-left: auto; font-family: var(--mono); font-size: 11px;
  color: var(--dimmer);
}

.dsec-body { padding: 0; }
.dsec-body > .ctl { border-bottom: none; padding: 0 14px 14px; }
/* A static (non-collapsible) section has no summary row above its body, so it
   keeps the top padding a .ctl normally carries. */
.dsec-static > .ctl { border-bottom: none; padding: 14px; }
.dsec-body > .panel-body { border-top: none; }

.dsec-help {
  font-size: 11px; line-height: 1.5; color: var(--dimmer); margin-top: 7px;
}
/* label.dsec-check, not .dsec-check: the generic `.ctl label` rule is (0,1,1)
   and would otherwise win, rendering this inline checkbox as a heavy uppercase
   section heading. */
label.dsec-check {
  margin-top: 10px; text-transform: none; letter-spacing: 0; font-weight: 400;
  font-size: 12px; line-height: 1.45; color: var(--dim); display: flex;
  gap: 8px; align-items: flex-start;
}
label.dsec-check input { accent-color: var(--red-bright); margin-top: 1px;
  flex: 0 0 auto; }

/* Result panes inside "Link two places" / "Scan an area" can run long
   (multi-hop routes, 12 scan rows) — cap them so one section can't force
   the whole sidebar to scroll past the others. */
#route-result, #scan-result {
  max-height: 46vh; overflow-y: auto; margin-top: 4px;
}

/* Candidate list keeps its own capped, scrolling area rather than flexing
   to fill the sidebar. */
#candlist {
  max-height: 50vh; overflow-y: auto; border-top: 1px solid var(--line-soft);
}

@media (max-width: 820px) {
  /* Narrow single-column layout already lets #sidebar scroll as a whole;
     let each section grow to its content instead of double-scrolling. */
  #pane-prospect { overflow: visible; max-height: none; }
  #route-result, #scan-result, #candlist { max-height: none; overflow: visible; }
}

/* --------------------------------------------- armed-mode banner (shared) */

.arm-banner {
  position: absolute; top: 66px; left: 50%; transform: translateX(-50%);
  z-index: 1100; display: flex; align-items: center; gap: 11px;
  padding: 9px 12px 9px 15px; border-radius: 999px; font-size: 12.5px;
  background: rgba(20,12,12,.96); border: 1px solid rgba(240,153,123,.5);
  box-shadow: 0 8px 28px rgba(0,0,0,.6);
  max-width: calc(100vw - 28px); box-sizing: border-box;
}
.arm-banner button {
  flex: 0 0 auto;
  background: rgba(255,255,255,.07); border: 1px solid var(--line);
  color: var(--dim); border-radius: 999px; padding: 4px 12px;
  font: inherit; font-size: 11.5px; cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.arm-banner button:hover { background: var(--red); color: #fff;
  border-color: var(--red); }
@media (max-width: 820px) {
  /* Sit just under the shorter phone topbar, and give the Cancel button a
     fatter tap target than a mouse needs. */
  .arm-banner { top: 56px; font-size: 12px; padding: 8px 10px 8px 13px; gap: 8px; }
  .arm-banner button { padding: 7px 14px; font-size: 12px; }
}
.dotpulse { width: 9px; height: 9px; border-radius: 50%;
  background: var(--coral); animation: pulse 1.3s ease-in-out infinite; }
@keyframes pulse { 0%,100% { opacity: 1; transform: scale(1); }
                   50% { opacity: .35; transform: scale(.75); } }

/* ------------------------------------------------------------ device art */

.clientpick { display: flex; align-items: center; gap: 12px; }
.devart { flex: 0 0 auto; width: 66px; display: grid; place-items: center; }
.devart img.devphoto { max-height: 100%; max-width: 100%; object-fit: contain; }
#client-art { flex: 0 0 auto; }

/* --------------------------------------------------------------- solar */

.solar { background: rgba(240,153,123,.05); }
#solar-result { margin-top: 12px; }
.sv { padding: 11px 12px; border-radius: 9px; font-size: 12px; line-height: 1.5; }
.sv b { display: block; font-size: 13.5px; margin-bottom: 3px; }
.sv.good { background: rgba(79,201,138,.13); border: 1px solid rgba(79,201,138,.35);
  color: #9fe4bf; }
.sv.ok { background: rgba(163,209,53,.12); border: 1px solid rgba(163,209,53,.3);
  color: #cfe89a; }
.sv.marginal { background: rgba(232,163,60,.13);
  border: 1px solid rgba(232,163,60,.38); color: #f2c684; }
.sv.bad { background: rgba(239,95,107,.13); border: 1px solid rgba(239,95,107,.4);
  color: #f5a3ab; }
.sgrid { display: grid; grid-template-columns: repeat(3,1fr); gap: 1px;
  background: var(--line-soft); margin-top: 10px; border-radius: 8px;
  overflow: hidden; }
.sgrid > div { background: var(--panel); padding: 8px 5px; text-align: center; }
.sgrid b { display: block; font-family: var(--mono); font-size: 13.5px; }
.sgrid span { font-size: 8.5px; text-transform: uppercase; letter-spacing: .09em;
  color: var(--dimmer); font-weight: 700; }

/* ---------------------------------------------------------- area scanning */

#map.scanning { cursor: crosshair; }
#scan-toggle.on { background: var(--red-bright); color: #fff; }

.scan-head { font-size: 11px; color: var(--dimmer); margin: 12px 0 8px;
  padding-bottom: 7px; border-bottom: 1px solid var(--line-soft); }
.scan-row { display: flex; align-items: center; gap: 9px; padding: 7px 6px;
  border-radius: 7px; cursor: pointer; }
.scan-row:hover { background: var(--panel-2); }
.scan-row .rank { font-family: var(--mono); font-size: 11px; font-weight: 700;
  color: var(--hawk); min-width: 24px; }
.sr-main { flex: 1; min-width: 0; }
.sr-main b { font-size: 13px; }
.sr-sub { font-size: 10.5px; color: var(--dimmer); font-family: var(--mono);
  margin-top: 2px; }
.sr-score { font-family: var(--mono); font-size: 12px; color: var(--dim); }
.hi-tag { font-size: 9px; text-transform: uppercase; letter-spacing: .09em;
  color: var(--warn); border: 1px solid rgba(232,163,60,.4); border-radius: 4px;
  padding: 1px 5px; margin-left: 6px; font-weight: 700; }
.scan-empty { font-size: 11.5px; color: var(--dimmer); margin-top: 10px;
  line-height: 1.5; }

/* ------------------------------------------------------------- routing */

#map.routing { cursor: crosshair; }
#route-toggle.on { background: var(--red-bright); color: #fff; }

.route-ok, .route-bad { margin-top: 11px; padding: 10px 11px; border-radius: 8px;
  font-size: 12px; line-height: 1.5; }
.route-ok { background: rgba(79,201,138,.11); border: 1px solid rgba(79,201,138,.3);
  color: #9fe4bf; }
.route-bad { background: rgba(239,95,107,.12); border: 1px solid rgba(239,95,107,.35);
  color: #f5a3ab; }
.route-legs { margin-top: 9px; }
.rleg { display: flex; align-items: center; gap: 10px; padding: 4px 6px;
  font-family: var(--mono); font-size: 11.5px; border-radius: 6px; }
.rleg:hover { background: var(--panel-2); }
.rl-n { width: 18px; height: 18px; border-radius: 50%; display: grid;
  place-items: center; background: var(--panel-3); color: var(--dim);
  font-size: 10px; font-weight: 700; }
.rl-d { flex: 1; color: var(--dim); }

.route-ant-head { margin: 14px 0 8px; font-size: 10px; letter-spacing: .14em;
  font-weight: 700; text-transform: uppercase; color: var(--dimmer);
  padding-top: 10px; border-top: 1px solid var(--line-soft); }
.rant { padding: 8px 9px; border-radius: 7px; margin-bottom: 5px;
  background: var(--panel-2); }
.ra-top { display: flex; align-items: baseline; gap: 8px; font-size: 12px; }
.ra-top b { flex: 1; min-width: 0; font-weight: 600; }
.ra-role { font-size: 8.5px; text-transform: uppercase; letter-spacing: .1em;
  font-weight: 700; padding: 2px 6px; border-radius: 4px; flex: 0 0 auto;
  background: rgba(255,255,255,.07); color: var(--dimmer); }
.ra-role.start, .ra-role.end { background: rgba(240,153,123,.18);
  color: var(--coral); }
.ra-aim { font-family: var(--mono); font-size: 11px; color: var(--dim);
  flex: 0 0 auto; }
.ra-why { font-size: 11px; color: var(--dimmer); line-height: 1.45;
  margin-top: 5px; }
.route-gain { margin-top: 9px; padding: 8px 10px; border-radius: 7px;
  font-size: 11.5px; line-height: 1.45;
  background: rgba(79,201,138,.11); border: 1px solid rgba(79,201,138,.28);
  color: #9fe4bf; }

.mastline { font-size: 11.5px; color: var(--dim); line-height: 1.5;
  margin-bottom: 8px; }
.mrow { display: flex; align-items: baseline; gap: 8px; padding: 5px 7px;
  border-radius: 6px; font-size: 11.5px; }
.mrow.raised { background: rgba(232,163,60,.10);
  border: 1px solid rgba(232,163,60,.25); }
.m-h { font-family: var(--mono); font-size: 13px; font-weight: 700;
  color: var(--text); min-width: 42px; }
.mrow.raised .m-h { color: var(--warn); }
.m-why { flex: 1; color: var(--dimmer); line-height: 1.4; }
/* How hard a proposed site is to reach. Green = drive up, amber = a carry,
 * red = an expedition - the colour is the first-pass answer. */
.m-why.acc-easy   { color: #4fc98a; }
.m-why.acc-medium { color: #e8a33c; }
.m-why.acc-hard   { color: #ef7a4a; }

/* ------------------------------------------------------------ live strip */

.livestrip {
  display: flex; align-items: center; gap: 12px;
  padding: 5px 12px 5px 11px; border-radius: 999px;
  background: rgba(255,255,255,.045); border: 1px solid var(--line);
}
.livestrip[hidden] { display: none; }

.live-dot {
  width: 8px; height: 8px; border-radius: 50%; flex: 0 0 auto;
  background: var(--dimmer);
}
.live-dot.on {
  background: var(--good);
  box-shadow: 0 0 0 3px rgba(79,201,138,.18);
  animation: livepulse 2s ease-in-out infinite;
}
.live-dot.stale { background: var(--warn); box-shadow: 0 0 0 3px rgba(232,163,60,.18); }
@keyframes livepulse {
  0%,100% { opacity: 1; } 50% { opacity: .45; }
}

.live-label {
  font-size: 9.5px; font-weight: 700; letter-spacing: .16em;
  color: var(--dim);
}
.livestrip .live-metrics { display: flex; gap: 14px; }
.lm { text-align: right; line-height: 1.1; }
.lm b { display: block; font-family: var(--mono); font-size: 13px; }
.lm span { font-size: 9px; text-transform: uppercase; letter-spacing: .1em;
  color: var(--dimmer); font-weight: 700; }

.live-toggle {
  background: none; border: 1px solid var(--line); border-radius: 999px;
  color: var(--dim); font: inherit; font-size: 10.5px; font-weight: 700;
  letter-spacing: .08em; text-transform: uppercase; padding: 4px 11px;
  cursor: pointer;
}
.live-toggle:hover, .live-toggle.on {
  background: var(--red); border-color: var(--red); color: #fff;
}

/* ------------------------------------------------------- live map feed */

/* The animation canvas rides inside the map container, above tiles and the
 * overlay SVG, click-through so the map stays fully usable underneath. */
.livecanvas { position: absolute; inset: 0; pointer-events: none; }

/* "Lights up the map": a soft darken so the coloured ripples carry, without
 * hijacking the user's chosen basemap. */
#map.feed-on::after {
  content: ''; position: absolute; inset: 0; z-index: 440;
  pointer-events: none;
  background: radial-gradient(ellipse at center,
    rgba(8,5,5,.04) 0%, rgba(8,5,5,.22) 100%);
  animation: feedfade .5s ease-out;
}
@keyframes feedfade { from { opacity: 0; } }

.feed-legend {
  position: absolute; bottom: 14px; left: 50%; transform: translateX(-50%);
  z-index: 880; display: flex; align-items: center; gap: 14px;
  padding: 8px 15px; font-size: 11px; color: var(--dim);
}
.feed-legend[hidden] { display: none; }
.fl-title { font-size: 10px; font-weight: 700; letter-spacing: .14em;
  text-transform: uppercase; color: var(--coral); }
.fl-item { display: flex; align-items: center; gap: 6px; white-space: nowrap; }
.fl-dot { width: 9px; height: 9px; border-radius: 50%; display: inline-block; }
.fl-sub { margin-left: 4px; font-family: var(--mono); font-size: 10px;
  color: var(--dimmer); }

@media (max-width: 1100px) { .livestrip .live-metrics { display: none; } }
@media (max-width: 820px)  {
  .livestrip { display: none; }
  .feed-legend { flex-wrap: wrap; justify-content: center; max-width: 92vw; }
}
