/* NightSeam Web — dark night-planning UI */
:root {
  --bg: #0B1115;
  --bg2: #152027;
  --panel: #10181B;
  --raised: #152027;
  --line: #293840;
  --line-soft: #1E2B31;
  --txt: #E7ECE8;
  --muted: #9CAEB1;
  --accent: #F9C85D;
  --accent-ink: #101316;
  --amber: #E8A948;
  --green: #5BC68D;
  --bad: #C45B52;
  --radius: 6px;
  --mono: ui-monospace, "Cascadia Mono", Consolas, monospace;
}
* { box-sizing: border-box; margin: 0; padding: 0; }
html { height: 100%; }
body {
  font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  color: var(--txt);
  background: var(--bg);
  min-height: 100vh;
  /* Let long panoramas grow the page: a fixed viewport-height body ends the
     sticky header's containing block before the editor has finished scrolling. */
  height: auto;
}
.hidden { display: none !important; }
.visually-hidden { position: absolute; width: 1px; height: 1px;
  margin: -1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0);
  white-space: nowrap; border: 0; }
.mono { font-family: var(--mono); }

:where(button, a, input, select, textarea, [tabindex]):focus-visible {
  outline: 2px solid var(--accent); outline-offset: 2px;
}

/* ---------- topbar / planner chrome ---------- */
.topbar {
  display: flex; flex-wrap: wrap; gap: 10px 18px; align-items: center; justify-content: space-between;
  padding: 14px 22px 10px;
  border-bottom: 1px solid var(--line);
  position: sticky; top: 0; z-index: 45;
  background: var(--bg);
}
.brand { display: flex; gap: 12px; align-items: center; cursor: pointer; }
.brand-ico { width: 34px; height: 34px; border-radius: 6px; }
.brand h1 { font-size: 21px; letter-spacing: .4px; font-weight: 700; }
.brand h1 em { color: var(--accent); font-style: normal; }
.tagline { font-size: 12px; color: var(--muted); margin-top: 2px; }

.planner-controls { display: flex; flex-wrap: wrap; gap: 8px 12px; align-items: center; }
.planner-controls label { font-size: 12px; color: var(--muted); display: inline-flex; align-items: center; gap: 6px; }
.planner-controls select,
.planner-controls input[type="date"] {
  background: var(--panel); border: 1px solid var(--line); color: var(--txt);
  border-radius: 8px; padding: 6px 8px; font-size: 12.5px; font-family: var(--mono);
}
#tb-site { max-width: 150px; }
/* the rig selector sits in the topbar next to Site (it used to hide in the
   hamburger menu) - long preset names must not stretch the bar */
#rigSelect { max-width: 170px; }
.minalt input[type="range"] { width: clamp(130px, 15vw, 180px); accent-color: var(--accent); margin: 0; }
.minalt .mono { min-width: 40px; text-align: right; font-size: 11.5px; color: var(--txt); }
.minalt .note { font-size: 10.5px; color: var(--muted); opacity: .8; }
.scrub { display: inline-flex; align-items: center; gap: 6px; }
.scrub input[type="range"] { width: 108px; accent-color: var(--accent); margin: 0; }
.scrub strong { font-size: 11.5px; color: var(--txt); min-width: 52px; text-align: right; }
.topbar:focus-within input[type="date"]:focus,
.planner-controls select:focus { outline: 1px solid var(--accent); }

.ghost {
  background: var(--panel); border: 1px solid var(--line); color: var(--txt);
  border-radius: 8px; padding: 6px 10px; font-size: 12.5px; cursor: pointer;
  font-family: inherit;
}
.ghost:hover { border-color: var(--accent); color: var(--accent); }

.topbar-right { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; min-width: 0; }
.nightinfo {
  font-size: 12px; color: var(--muted); font-family: var(--mono); white-space: nowrap;
  border: 1px solid var(--line); border-radius: 999px; padding: 5px 12px;
  background: var(--panel);
}
@media (min-width: 1400px) {
  .topbar { flex-wrap: nowrap; gap: 10px; padding: 7px 22px; }
  .brand { flex: 0 0 auto; white-space: nowrap; }
  .brand > div, .brand h1 { white-space: nowrap; }
  .tagline { display: none; }
  .planner-controls { flex-wrap: nowrap; gap: 6px; }
  .planner-controls label { gap: 4px; }
  #tb-site { max-width: 130px; }
  #rigSelect { max-width: 145px; }
  .minalt input[type="range"] { width: 110px; }
  .scrub input[type="range"] { width: 78px; }
  .busy-slot { width: 96px; }
  .topbar-right { flex-wrap: nowrap; gap: 6px; }
  .nightinfo { max-width: 205px; overflow: hidden; text-overflow: ellipsis; padding: 4px 8px; font-size: 10px; }
  .weatherbtn { max-width: 126px; padding: 5px 7px; font-size: 11px; }
  .tabs { padding: 4px 22px 0; }
  .tabs a { padding: 7px 16px 8px; }
  main { padding-top: 14px; }
}
/* Narrow windows (UI-01/UI-08/UI-09, 0.6.32 review): `.topbar-right` could not
   shrink because `.nightinfo` is nowrap, so the whole PAGE was forced to ~548 px
   in the base layout and scrolled sideways on every phone - the weather chip,
   the hamburger (the only route to the menu) and the 4th tab sat off-screen.
   Let the group wrap and the night summary take multiple lines instead. */
@media (max-width: 640px) {
  .topbar-right { flex-wrap: wrap; min-width: 0; }
  .nightinfo { white-space: normal; max-width: 100%; }
  .planner-controls label { white-space: nowrap; }   /* "Min alt" stays one label */
  .weatherbtn { max-width: none; }
  /* UI-01: the tab strip is a nowrap flex row, so "Horizon & Obstacles"
     (98 px of min-content) pushed the PAGE to 372 px - the last 52 px of the
     320 px viewport. Let the strip wrap instead. `flex-wrap` only, never
     `display` (the app toggles #tabs via the .hidden class). */
  .tabs { flex-wrap: wrap; }
  .tabs a { padding: 5px 10px; font-size: 12px; }
}
#busy {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 11.5px; color: var(--muted); font-family: var(--mono);
}
/* Reserved slot (0.6.31): the busy chip is shown and hidden constantly, and as a
   bare flex item it re-wrapped the topbar and pushed the whole app down. The slot
   holds the space permanently (it only eats the flexible gap, so it is invisible
   when idle) and the text ellipsizes instead of growing it. */
.busy-slot { display: inline-flex; justify-content: flex-end; align-items: center;
  flex: none; width: 168px; height: 20px; overflow: hidden; }
.busy-slot #busy { max-width: 100%; }
.busy-slot .busy-txt { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
#busy .busy-dot {
  width: 8px; height: 8px; border-radius: 50%; background: var(--amber);
  animation: busyPulse 1s ease-in-out infinite;
}
@keyframes busyPulse { 0%, 100% { opacity: .35; } 50% { opacity: 1; } }

.menubtn { display: inline-flex; align-items: center; padding: 7px 10px; }
.menubtn svg { display: block; }

/* ---------- hamburger menu (desktop-style popover) ---------- */
.popwrap { position: relative; }
#menuPanel.menu-panel {
  position: absolute; right: 0; top: calc(100% + 8px);
  width: 310px; max-width: min(92vw, 340px);
  max-height: min(72vh, 540px); overflow-y: auto;
  background: var(--panel); border: 1px solid var(--line); border-radius: 6px;
  box-shadow: 0 18px 50px rgba(0,0,0,.5); padding: 14px;
  z-index: 60;
}
.menu-section { border-bottom: 1px dashed rgba(29,49,82,.6); padding: 10px 2px 12px; }
.menu-section:last-child { border-bottom: none; }
.menu-section h4 {
  font-size: 11px; text-transform: uppercase; letter-spacing: 1.4px;
  color: var(--muted); margin-bottom: 8px; font-weight: 600;
}
.menu-section label.inline {
  display: flex; align-items: center; gap: 8px;
  font-size: 12.5px; color: var(--muted); margin: 6px 0;
  cursor: pointer;
}
.menu-section label.inline .mono { color: var(--txt); margin-left: auto; }
.menu-section input[type="range"] { accent-color: var(--accent); margin: 6px 0; }
.menu-section input[type="checkbox"], .menu-section input[type="radio"] { accent-color: var(--accent); }
.menu-section select {
  background: var(--panel); border: 1px solid var(--line); color: var(--txt);
  border-radius: 8px; padding: 6px 8px; font-size: 12.5px; font-family: var(--mono);
}
.hint { font-size: 11px; color: var(--muted); margin-top: 6px; line-height: 1.5; }
.chkrow { display: flex; flex-wrap: wrap; gap: 4px 14px; align-items: center; }

/* ---------- weather chip + submenu ---------- */
.weatherwrap { position: relative; }
.weatherbtn { white-space: nowrap; max-width: 230px; }
.weatherbtn #wxChip {
  display: inline-block; max-width: 100%; overflow: hidden;
  text-overflow: ellipsis; vertical-align: bottom; white-space: nowrap;
}
.wx-status-dot { display: inline-block; width: 1em; margin-right: 4px; font-size: 15px; line-height: 1; vertical-align: -1px; }
#weatherPanel.weather-panel {
  position: absolute; right: 0; top: calc(100% + 8px);
  width: 410px; max-width: min(94vw, 460px);
  max-height: min(74vh, 560px); overflow-y: auto;
  background: var(--panel); border: 1px solid var(--line); border-radius: 6px;
  box-shadow: 0 18px 50px rgba(0,0,0,.5); padding: 14px;
  z-index: 60;
}
.wx-now { display: flex; align-items: center; gap: 14px; }
.wx-icon { font-size: 30px; line-height: 1; }
.wx-big { font-size: 28px; font-weight: 700; color: var(--txt); }
.wx-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 3px 16px; margin-top: 12px; }
.wx-grid > div {
  display: flex; justify-content: space-between; gap: 8px;
  font-size: 12px; color: var(--muted);
  border-bottom: 1px dashed rgba(29,49,82,.55); padding: 4px 0;
}
.wx-grid b { color: var(--txt); font-family: var(--mono); font-weight: 600; }
.wx-good { color: var(--green) !important; }
.wx-warn { color: var(--amber) !important; }
.wx-bad { color: var(--bad, #ff8a8a) !important; }
.wx-unknown { color: var(--muted) !important; }
.wx-rating { margin-top: 10px; padding: 8px 10px; border: 1px solid var(--line); border-left: 3px solid var(--muted); background: color-mix(in srgb, var(--panel) 86%, var(--bg2)); }
.wx-rating-good { border-left-color: var(--green); }
.wx-rating-warn { border-left-color: var(--amber); }
.wx-rating-bad { border-left-color: var(--bad, #ff8a8a); }
.wx-rating-head { display: flex; align-items: center; gap: 6px; color: var(--txt); }
.wx-rating-head strong { font-size: 13px; }
.wx-rating-head b { margin-left: auto; font: 600 13px var(--mono); }
.wx-rating-detail { margin-top: 3px; color: var(--muted); font-size: 11px; }
.wx-section-title {
  display: flex; justify-content: space-between; align-items: baseline; gap: 10px;
  margin-top: 14px; padding-bottom: 6px; border-bottom: 1px solid var(--line);
  color: var(--txt); font-size: 12px;
}
.wx-section-title span { color: var(--muted); font: 10px var(--mono); }
.wx-assessment {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 5px 14px; margin-top: 8px;
}
.wx-assessment > div {
  display: flex; justify-content: space-between; gap: 8px; min-width: 0;
  color: var(--muted); font-size: 11px;
}
.wx-assessment b { color: var(--txt); font: 600 11px var(--mono); text-align: right; }
.wx-hourly-head, .wx-hour {
  display: grid; grid-template-columns: 56px repeat(4, minmax(0, 1fr)); gap: 6px;
  align-items: center;
}
.wx-hourly-head {
  margin-top: 12px; padding: 0 7px 4px; color: var(--muted);
  font-size: 9px; text-transform: uppercase; letter-spacing: .07em;
}
.wx-hourly { border-top: 1px solid var(--line); }
.wx-hour {
  min-height: 38px; padding: 4px 7px; border-bottom: 1px solid color-mix(in srgb, var(--line) 70%, transparent);
}
.wx-hour:nth-child(even) { background: color-mix(in srgb, var(--panel) 82%, var(--bg2)); }
.wx-hour-time { display: flex; align-items: center; gap: 4px; color: var(--txt); font: 11px var(--mono); }
.wx-hour-icon { font-size: 14px; line-height: 1; }
.wx-hour-metric { min-width: 0; display: grid; grid-template-columns: auto 1fr; align-items: center; gap: 2px 4px; }
.wx-hour-metric small { grid-column: 1 / -1; color: var(--muted); font-size: 9px; }
.wx-hour-metric b { color: var(--txt); font: 600 10px var(--mono); white-space: nowrap; }
.wx-hour-metric > small:last-child { color: var(--muted); font-size: 9px; text-align: right; }
.wx-meter { display: block; min-width: 12px; height: 4px; overflow: hidden; background: var(--line); border-radius: 2px; }
.wx-meter i { display: block; height: 100%; background: var(--accent); border-radius: inherit; }
.wx-days { display: flex; gap: 8px; margin-top: 12px; }
.wx-day {
  flex: 1; text-align: center; font-size: 11px; color: var(--muted);
  background: var(--panel); border: 1px solid var(--line); border-radius: 10px; padding: 8px 4px;
}
.wx-day .wx-di { font-size: 18px; line-height: 1.3; }
.wx-day .wx-t { color: var(--txt); font-family: var(--mono); font-size: 12px; margin-top: 2px; }
.wx-day .wx-p { margin-top: 2px; }
.wx-err { color: #ffb454; font-size: 12.5px; line-height: 1.5; }
@media (max-width: 1240px) { .weatherbtn { max-width: 160px; font-size: 11.5px; } }
@media (max-width: 900px) {
  .weatherbtn { max-width: 130px; }
  #weatherPanel.weather-panel { width: min(94vw, 410px); right: -8px; }
  .wx-hourly-head, .wx-hour { grid-template-columns: 50px repeat(4, minmax(0, 1fr)); gap: 4px; }
  .wx-hour { padding-left: 4px; padding-right: 4px; }
  .wx-hour-metric b { font-size: 9px; }
}

/* ---------- tabs ---------- */
.tabs { display: flex; gap: 6px; padding: 12px 22px 0; border-bottom: 1px solid var(--line); }
.tabs a {
  color: var(--muted); text-decoration: none; font-size: 14px; padding: 9px 18px 11px;
  border: 1px solid transparent; border-bottom: none; border-radius: 10px 10px 0 0;
  transition: color .15s;
}
.tabs a:hover { color: var(--txt); }
.tabs a.active { color: var(--accent); background: var(--panel); border-color: var(--line); }

/* ---------- content ---------- */
/* "Free space per side" (hamburger menu → Layout) removes that many pixels from
   EACH side of the content on every screen size — the desktop keeps the same
   semantics (content width = viewport - 2 * edge, static/style.css). `100%` can
   never overflow the viewport and 320px is the usable floor.
   A 1500px reading-width cap used to sit in this min() as well. It silently WON
   over the edge term on any viewport wider than 1500 + 2*edge, so the slider was
   inert below edge 210 on a 1920px screen and had NO effect at all from ~2100px
   up (2560/3440 owners: the control did nothing). The cap is gone — the slider
   decides, exactly as on the desktop. */
main {
  max-width: min(100%, max(320px, calc(100% - 2 * var(--edge, 16px))));
  margin: 0 auto;
  padding: 20px 22px 40px;
  position: relative;
}

.grid2 { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
.grid3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px; }
@media (max-width: 860px) { .grid2, .grid3 { grid-template-columns: 1fr; } }

.card {
  background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 16px 18px;
  backdrop-filter: none;
}
.card h3 { font-size: 13px; text-transform: uppercase; letter-spacing: 1.2px; color: var(--muted); margin-bottom: 10px; font-weight: 600; }
.card .big { font-size: 26px; font-weight: 700; color: var(--txt); }
.card .sub { font-size: 12.5px; color: var(--muted); margin-top: 4px; line-height: 1.5; }
.card .row { display: flex; justify-content: space-between; padding: 4px 0; font-size: 13.5px; border-bottom: 1px dashed rgba(29,49,82,.55); }
.card .row:last-child { border-bottom: none; }
.card .row b { font-weight: 600; }

/* ---------- pick lists ---------- */
.pick { list-style: none; min-width: 0; }
.pick li {
  display: flex; gap: 10px; align-items: center; padding: 9px 10px; margin: 6px 0;
  background: rgba(8, 15, 28, .55); border: 1px solid var(--line); border-radius: 10px;
  cursor: pointer; transition: border-color .15s; min-width: 0;
}
.pick li:hover { border-color: var(--accent); }
.dot { width: 10px; height: 10px; border-radius: 50%; flex: none; }
.pick .p-name { font-size: 14px; font-weight: 600; }
.pick .p-tags { color: var(--muted); font-size: 11.5px; margin-left: 6px; font-family: var(--mono); }
.pick .p-right { margin-left: auto; text-align: right; font-size: 12px; color: var(--muted); white-space: nowrap; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.pick .p-right b { color: var(--txt); font-size: 13px; display: block; }
.f-own { color: var(--amber); font-size: 11px; margin-left: 6px; font-family: var(--mono); }

/* ---------- sky view ---------- */
.sky-wrap { display: grid; grid-template-columns: 1fr 260px; gap: 14px; }
@media (max-width: 900px) { .sky-wrap { grid-template-columns: 1fr; } }
.sky-canvas-box { position: relative; }
canvas#sky {
  display: block; width: 100%; max-width: 80vh; aspect-ratio: 1 / 1; margin: 0 auto;
  border-radius: var(--radius); background: var(--viz-sky-surface, #0B1115);
}
.sky-side { display: flex; flex-direction: column; gap: 12px; }
.sky-side label { font-size: 12px; color: var(--muted); display: flex; flex-direction: column; gap: 6px; }
.sky-side input[type="datetime-local"] {
  background: var(--panel); border: 1px solid var(--line); color: var(--txt); border-radius: 8px;
  padding: 8px; font-size: 13px; font-family: var(--mono); width: 100%;
}
.sky-side .btnrow { display: flex; gap: 8px; }
.btn {
  flex: 1; background: var(--panel); border: 1px solid var(--line); color: var(--txt);
  border-radius: 8px; padding: 8px 10px; font-size: 13px; cursor: pointer;
}
.btn:hover { border-color: var(--accent); color: var(--accent); }
.btn.primary { background: rgba(124,196,255,.14); border-color: rgba(124,196,255,.5); color: var(--accent); }
.legend { list-style: none; }
.legend li { display: flex; align-items: center; gap: 8px; font-size: 12.5px; color: var(--muted); padding: 3px 0; }
.legend .dot { width: 9px; height: 9px; }

/* ---------- catalog ---------- */
.cat-bar { display: flex; flex-wrap: wrap; gap: 10px; margin-bottom: 6px; align-items: center; }
/* The count + live status sit on their OWN fixed-height row (0.6.31): inside the
   wrapping bar above, "computing visibility… 42%" appearing/disappearing reflowed
   the bar and pushed the table down. A fixed height + nowrap makes that
   impossible - the text changes, the geometry never does. */
.cat-stats {
  display: flex; justify-content: space-between; align-items: center; gap: 12px;
  height: 20px; margin: 0 0 12px; font-size: 12.5px; color: var(--muted);
  white-space: nowrap; overflow: hidden;
}
.cat-stats .cat-count, #pct-status { font-variant-numeric: tabular-nums; }
/* Progress must never resize the thing it reports on. */
#pct-status { min-width: 150px; text-align: right; }
.cat-bar input[type="search"] {
  flex: 1; min-width: 220px; background: var(--panel); border: 1px solid var(--line); color: var(--txt);
  border-radius: 10px; padding: 10px 14px; font-size: 14px;
}
.cat-bar input[type="search"]:focus { outline: 1px solid var(--accent); }
.chips { display: flex; gap: 6px; flex-wrap: wrap; }
/* Min-visibility slider (0.6.30): a quiet list gate in the catalog bar. */
.cat-bar .minvis { display: flex; align-items: center; gap: 6px; font-size: 12.5px; color: var(--muted); }
.cat-bar .minvis b { font-family: var(--mono); color: var(--txt); min-width: 40px; text-align: right; font-variant-numeric: tabular-nums; }
.cat-bar .minvis input[type="range"] { width: 110px; }
.chip {
  background: var(--panel); border: 1px solid var(--line); color: var(--muted); border-radius: 999px;
  padding: 6px 13px; font-size: 12.5px; cursor: pointer;
}
.chip.on { color: var(--accent); border-color: rgba(124,196,255,.55); background: rgba(124,196,255,.1); }
.cat-count { font-size: 12.5px; color: var(--muted); margin-left: auto; }

table.cat { width: 100%; border-collapse: collapse; font-size: 13.5px;
  /* Stable widths prevent live visibility values from shifting the header. */
  table-layout: fixed; }
table.cat th[data-k="name"] { width: 30%; }
table.cat th[data-k="tier"] { width: 46px; }
table.cat th.num, table.cat th.frame { width: 72px; }
table.cat td { font-variant-numeric: tabular-nums; }
/* The catalog table is 9-10 columns wide: on a narrow viewport it must scroll
   INSIDE its card (the desktop's `.tablewrap` does the same) instead of
   widening the page and giving the whole app a horizontal scrollbar. */
.catwrap { overflow-x: auto; }
table.cat th {
  text-align: left; color: var(--muted); font-size: 12px; text-transform: uppercase; letter-spacing: .8px;
  padding: 8px 10px; border-bottom: 1px solid var(--line); cursor: pointer; user-select: none; white-space: nowrap;
}
table.cat th:hover { color: var(--accent); }
.target-open, .table-sort { border: 0; background: transparent; color: inherit;
  font: inherit; padding: 0; text-align: inherit; cursor: pointer; }
.target-open:hover, .table-sort:hover { color: var(--accent); }
.target-open:focus-visible, .table-sort:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.table-sort { max-width: 100%; text-transform: inherit; letter-spacing: inherit; }
table.cat td { padding: 7px 10px; border-bottom: 1px solid rgba(29,49,82,.4); }
table.cat tr { cursor: pointer; }
table.cat tbody tr:hover { background: rgba(124,196,255,.07); }
td.num, th.num { text-align: right; font-family: var(--mono); }
td.frame, th.frame { text-align: right; font-family: var(--mono); font-size: 11.5px; white-space: nowrap; }
td.frame .fit { color: var(--green); }          /* fits in one frame */
td.frame .over { color: var(--amber); }         /* over 100%: needs a mosaic */
td.tier, th[data-k="tier"] { text-align: center; width: 42px; }
/* Popularity tier letter. Deliberately NOT the score: the ramp is decoration for
   an ordering, so it stays muted and never competes with the frame colours. */
.tier-badge {
  display: inline-block; min-width: 17px; padding: 1px 4px; border-radius: 4px;
  font-family: var(--mono); font-size: 11.5px; font-weight: 600;
  color: #9fb4d8; background: rgba(124,196,255,.07);
}
.tier-badge.t-a { color: var(--green); }
.tier-badge.t-b { color: #b9e8c9; }
.tier-badge.t-c { color: #cfd9ee; }
.tier-badge.t-d { color: #9fb4d8; }
.tier-badge.t-e { color: #8397b8; }
.tier-badge.t-f { color: #6d7f9e; }
.tags { font-family: var(--mono); font-size: 11.5px; color: var(--muted); }
/* one line per name: a wrapped long name would change the row height */
.tname { font-weight: 600; display: inline-block; max-width: 100%; overflow: hidden;
  text-overflow: ellipsis; vertical-align: bottom; white-space: nowrap; }
.pager { display: flex; gap: 8px; align-items: center; justify-content: center; margin-top: 14px; font-size: 13px; color: var(--muted); }

/* ---------- modal / detail ---------- */
.modal-wrap {
  position: fixed; inset: 0; background: rgba(2, 6, 14, .82); backdrop-filter: none;
  display: flex; align-items: flex-start; justify-content: center; overflow-y: auto; padding: 30px 16px; z-index: 70;
}
/* author rule must restore the hidden attribute: display:flex above would otherwise override it */
.modal-wrap[hidden] { display: none; }
.modal {
  width: min(900px, 100%); background: #0b1526; border: 1px solid var(--line); border-radius: 16px;
  padding: 22px 24px; box-shadow: 0 24px 70px rgba(0,0,0,.6);
  margin: auto;  /* safe vertical centering inside the flex wrapper: centers
                    when the modal fits, scrolls from the top when it doesn't */
}
.modal h2 { font-size: 22px; }
.modal .tags { font-size: 12.5px; margin: 6px 0 0; display: block; }
.modal .close {
  float: right; background: none; border: 1px solid var(--line); color: var(--muted); cursor: pointer;
  border-radius: 8px; width: 30px; height: 30px; font-size: 15px;
}
.modal .close:hover { color: var(--txt); border-color: var(--accent); }
.modal-head { display: flex; align-items: center; gap: 12px; padding: 0 0 6px; }
.modal-head h2 { flex: 1; margin: 0; }
.modal-head .close { float: none; flex: none; }
.detail-favorite { display: grid; place-items: center; flex: 0 0 28px; width: 28px; height: 32px; color: var(--muted); font-size: 20px; line-height: 1; }
.detail-favorite.on { color: var(--accent); }
.detail-hero { display: grid; grid-template-columns: 190px minmax(0, 1fr); gap: 16px; margin-top: 10px; align-items: start; }
.detail-hero-copy { min-width: 0; }
.objimg {
  display: block; width: 100%; height: 146px; object-fit: cover; border-radius: 4px; border: 1px solid var(--line);
  background: var(--panel);
}
.objimg-ph { width: 100%; height: 146px; border-radius: 4px; border: 1px dashed var(--line); display: flex; align-items: center; justify-content: center; color: var(--muted); font-size: 13px; text-align: center; padding: 10px; }
.detail-hero-facts, .detail-visibility-facts { display: grid; grid-template-columns: minmax(88px, 112px) minmax(0, 1fr); gap: 5px 10px; margin: 0; font-size: 12px; }
.detail-hero-facts dt, .detail-visibility-facts dt { color: var(--muted); }
.detail-hero-facts dd, .detail-visibility-facts dd { margin: 0; min-width: 0; overflow-wrap: anywhere; color: var(--txt); }
.detail-visibility-facts { margin-top: 10px; padding-top: 8px; border-top: 1px solid var(--line); }
.meta { display: grid; grid-template-columns: 120px 1fr; gap: 4px 12px; font-size: 13.5px; align-content: start; }
.meta dt { color: var(--muted); }
.meta dd { margin: 0; }
.blurb { margin-top: 14px; font-size: 14px; line-height: 1.6; color: #c4d6f2; }
.tonight-box { margin-top: 12px; }
canvas#graph {
  width: 100%; height: 260px; background: var(--viz-graph-surface, var(--panel)); border: 1px solid var(--line); border-radius: 4px; display: block;
  margin-top: 8px;
}
.detail-observable { margin: 7px 0 0; color: var(--txt); font-size: 12px; line-height: 1.45; }
.detail-actions { display: flex; justify-content: flex-end; margin: 10px 0; }
.catalog-details { margin-top: 8px; border-top: 1px solid var(--line); }
.catalog-details > summary { padding: 9px 0; color: var(--muted); font-size: 12px; cursor: pointer; }
.catalog-details[open] > summary { color: var(--txt); }
.catalog-details .meta { margin-top: 8px; }
.catalog-details .blurb { margin-top: 10px; }
@media (max-width: 720px) {
  .modal { padding: 14px; }
  .detail-hero { grid-template-columns: 100px minmax(0, 1fr); gap: 10px; }
  .objimg, .objimg-ph { height: 88px; }
  .detail-hero-facts, .detail-visibility-facts { grid-template-columns: minmax(74px, 88px) minmax(0, 1fr); gap: 4px 7px; font-size: 11px; }
  canvas#graph { height: 220px; }
  .chart-legend { grid-template-columns: minmax(0, 1fr); }
}
.chart-legend { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 14px 22px; margin-top: 10px; color: var(--muted); }
.chart-legend-group { display: grid; gap: 7px; min-width: 0; padding-top: 9px; border-top: 1px solid var(--line); }
.chart-legend-heading { color: var(--txt); font-size: 10px; text-transform: uppercase; letter-spacing: .11em; }
.chart-legend-item { display: flex; align-items: flex-start; gap: 8px; min-width: 0; line-height: 1.2; }
.chart-legend-item b { display: block; color: var(--txt); font-size: 12px; font-weight: 650; }
.chart-legend-item small { display: block; color: var(--muted); font-size: 11px; margin-top: 2px; }
.legend-swatch { width: 32px; height: 8px; flex: 0 0 32px; margin-top: 3px; border-radius: 3px; }
.state-clear { background: var(--viz-good, var(--green)); }
.state-warn { background: var(--viz-warn, var(--amber)); }
.state-blocked { background: var(--viz-bad, #ff6b6b); }
.state-below { background: var(--viz-below, #4a5468); }
.guide-min { background: repeating-linear-gradient(90deg, var(--viz-min-stroke, var(--amber)) 0 8px, transparent 8px 12px); }
.guide-moon { position: relative; overflow: visible; height: 12px; margin-top: 1px; border-radius: 0; background: repeating-linear-gradient(90deg, var(--viz-moon-line, #8fd3ff) 0 4px, transparent 4px 7px, var(--viz-moon-line, #8fd3ff) 7px 8px, transparent 8px 11px); }
.guide-moon::after { content: ""; position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); width: 11px; height: 11px; border-radius: 50%; background: linear-gradient(90deg, var(--viz-moon-marker-shadow, var(--viz-graph-surface, #081022)) 0 50%, var(--viz-moon-marker, #fff) 50% 100%); border: 1px solid var(--viz-moon-marker-outline, #fff); box-sizing: border-box; }
.guide-twilight { height: 12px; margin-top: 1px; background: var(--viz-twilight-3, var(--line)); border: 1px solid var(--line); }
.guide-window { height: 12px; margin-top: 1px; background: var(--viz-good-fill, rgba(53,208,127,.12)); border: 1px solid var(--viz-good, var(--green)); }
.guide-obstruction { height: 3px; border-radius: 0; background: repeating-linear-gradient(90deg, var(--viz-ceiling, #a9aaa2) 0 3px, transparent 3px 7px); }
.win-note { font-size: 13px; color: var(--green); margin-top: 6px; }
a.wiki { color: var(--accent); }

/* ---------- misc ---------- */
.splash {
  position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  z-index: 5; min-height: 300px;
}
.splash-inner { text-align: center; color: var(--muted); font-size: 14px; }
.spinner {
  width: 42px; height: 42px; border-radius: 50%; margin: 0 auto 14px;
  border: 3px solid var(--line); border-top-color: var(--accent);
  animation: spin 1s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

.foot { border-top: 1px solid var(--line); padding: 18px 22px 26px; text-align: center; }
.foot p { font-size: 12px; color: var(--muted); max-width: 760px; margin: 0 auto; line-height: 1.6; }
.foot .foot2 { margin-top: 6px; opacity: .75; }

.tooltip {
  position: fixed; pointer-events: none; z-index: 60; background: rgba(4, 10, 20, .95);
  border: 1px solid var(--line); border-radius: 8px; padding: 6px 10px; font-size: 12px;
  color: var(--txt); max-width: 260px; box-shadow: 0 6px 20px rgba(0,0,0,.5);
}
.tooltip b { color: var(--accent); }

/* ---------- horizon editor ---------- */
/* Action rows: real gaps + wrap. Buttons share width (deliberate) EXCEPT in an
   .action-row, where each action is auto-width - a lone full-width action is
   the bug this prevents. The label rule must NOT match a label used AS a button
   (e.g. "Upload photo" / "Import backup"), or it becomes a full-width flex
   block while its sibling stays content-width. */
.btnrow { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; }
.action-row { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; }
.action-row .btn { flex: 0 0 auto; }
.btnrow label:not(.btn) { font-size: 12px; color: var(--muted); display: flex; align-items: center; gap: 6px; }
.btnrow input[type="text"], .btnrow select, .pref-row select, .pref-row input[type="text"] {
  background: var(--panel); border: 1px solid var(--line); color: var(--txt);
  border-radius: 8px; padding: 6px 8px; font-size: 12.5px; max-width: 100px;
}
.btnrow input[type="range"] { width: 90px; accent-color: var(--accent); }
.btn.small { flex: 0 0 auto; padding: 4px 8px; font-size: 12px; }
.ed-status { font-size: 12px; color: var(--muted); white-space: nowrap; }
.ed-status.failed { color: var(--bad, #ff8a8a); }
.ed-view-overlay {
  position: absolute; top: 0; right: 8px; z-index: 2;
  display: inline-flex; align-items: center; gap: 4px;
  padding: 4px 6px; border-radius: 10px;
  background: var(--panel); border: 1px solid var(--line);
  pointer-events: none;   /* only the buttons catch clicks, not the canvas */
}
.ed-view-overlay .btn { pointer-events: auto; }
.ed-view-overlay #ed-zoom-label { min-width: 34px; text-align: center; font-size: 11px; }
.ed-hint { font-size: 12px; }
.btn:disabled { opacity: .45; cursor: default; }
.ed-confirm {
  position: fixed; inset: 0; z-index: 60; display: flex;
  align-items: center; justify-content: center;
  background: color-mix(in srgb, var(--bg) 70%, transparent);
}
.ed-confirm-box {
  max-width: 420px; margin: 16px; padding: 18px 20px;
  background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--radius, 12px);
}
.ed-confirm-box h4 { margin: 0 0 8px; }
.hz-link-text { display: block; width: 100%; box-sizing: border-box; margin: 0 0 10px; font: 12px var(--mono); overflow-wrap: anywhere; resize: vertical; }
.ed-confirm-box p { margin: 0 0 14px; font-size: 13px; color: var(--muted); }
.ed-confirm-box .btnrow { justify-content: flex-end; }
.ed-confirm-box .btn { flex: 0 0 auto; }
/* Phone pairing: the QR code keeps dark modules on a light plate (main text
   colour) so phone cameras read it on the dark page. */
.pair-box { max-height: calc(100dvh - 32px); overflow-y: auto; box-sizing: border-box; }
.pair-code { display: flex; justify-content: center; margin: 0 0 12px; }
.pair-code:empty { display: none; }
.pair-qr { display: block; width: min(240px, 70vw); height: auto; }
.pair-qr-plate { fill: var(--txt); }
.pair-qr-dark { fill: var(--bg); }
.ed-confirm-box .pair-line { display: flex; flex-wrap: wrap; justify-content: space-between; gap: 4px 12px; color: var(--txt); }
.pair-link { margin: 0 0 12px; font-size: 12px; color: var(--muted); }
.pair-link summary { cursor: pointer; margin-bottom: 6px; }
.hz-pair { margin: 0 0 16px; padding: 0 0 12px; border-bottom: 1px solid var(--line-soft); }
.hz-pair[hidden] { display: none; }
.hz-pair-title { margin: 0 0 6px; font-size: 14px; }
.hz-pair p { margin: 0 0 8px; font-size: 13px; line-height: 1.5; }
.hz-pair .btnrow { justify-content: flex-start; }
.hz-pair .btn { flex: 0 0 auto; min-height: 44px; }
.pref-row { display: flex; justify-content: space-between; align-items: center; font-size: 13px; color: var(--muted); padding: 5px 0; gap: 10px; }
.pref-row input[type="checkbox"] { accent-color: var(--accent); }
.p-blk { color: #ff8a8a; font-size: 11px; margin-left: 6px; }
.p-vis { display: block; font-size: 11.5px; color: var(--muted); margin-top: 2px; }
.top-prefs { display: flex; flex-wrap: wrap; gap: 8px 14px; align-items: center; }
.top-prefs label { font-size: 12px; color: var(--muted); display: flex; align-items: center; gap: 6px; }
.top-prefs input[type="text"] { width: 66px; }
.top-prefs select { width: 58px; }
.top-prefs input[type="text"], .top-prefs select {
  background: var(--panel); border: 1px solid var(--line); color: var(--txt);
  border-radius: 8px; padding: 6px 8px; font-size: 12.5px; font-family: var(--mono);
}
.top-prefs input[type="checkbox"] { accent-color: var(--accent); }
.tn-chk { white-space: nowrap; }
td.pct { font-family: var(--mono); color: var(--green); white-space: nowrap; }
.btn.on { border-color: #ff8a8a; color: #ff8a8a; }
.vhidden { position: fixed; left: -9999px; width: 1px; height: 1px; opacity: 0; pointer-events: none; }

/* ---------- settings (webstore parity) ---------- */
/* ("Free space per side" is handled by the earlier `main` rule) */
.iconbtn {
  background: none; border: 1px solid var(--line); color: var(--muted); cursor: pointer;
  border-radius: 8px; width: 30px; height: 30px; font-size: 15px; line-height: 1;
}
.iconbtn:hover { color: var(--txt); border-color: var(--accent); }
#tb-site { width: auto; max-width: 150px; }
.modal.settings { max-width: 860px; }
.modal.welcome h2 { text-align: center; }

/* setup dialog tabs — the same sections as the desktop's Setup dialog.
   Setup dialog tabs use the compact tab language shared with the planner. */
.modal-tabs {
  display: flex; flex-wrap: wrap; gap: 2px; width: fit-content; max-width: 100%;
  margin: 2px 0 16px; padding: 4px;
  border: 1px solid var(--line); border-radius: 5px; background: var(--panel);
}
.modal-tabs .tab {
  background: none; border: none; border-radius: 4px;
  color: var(--muted); font-family: inherit; font-weight: 600; font-size: 13px;
  padding: 7px 16px; cursor: pointer;
}
.modal-tabs .tab:hover { color: var(--txt); }
.modal-tabs .tab.active { color: #0a0d1a; background: var(--accent); }
.mtabpane > .card + .card { margin-top: 12px; }

.set-form {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 8px 12px; margin-top: 10px; padding: 12px; border: 1px solid var(--line); border-radius: 10px;
}
.set-form label { font-size: 12px; color: var(--muted); display: flex; flex-direction: column; gap: 4px; }
.set-form input, .set-form select {
  background: var(--panel); border: 1px solid var(--line); color: var(--txt);
  border-radius: 8px; padding: 6px 8px; font-size: 13px; font-family: var(--mono);
}
.set-form .btnrow { grid-column: 1 / -1; }
/* The panels hidden with the `hidden` ATTRIBUTE (sites / rigs / custom targets,
   and the Add-rig picker) need this: an author `display` (grid above) beats the
   UA's `[hidden] { display:none }`, so without the rule every one of them shows
   up on render — exactly like `.modal-wrap[hidden]` further up. Elements hidden
   with the `.hidden` CLASS already win via `!important` and are unaffected. */
.set-form[hidden],
#set-rig-picker[hidden] { display: none; }
.chk { font-size: 12px; color: var(--muted); display: inline-flex; align-items: center; gap: 6px; cursor: pointer; white-space: nowrap; }
.chk input { accent-color: var(--accent); }

/* small screens */
@media (max-width: 640px) {
  .tagline { display: none; }
  #busy { position: absolute; right: 70px; top: 8px; }
  .busy-slot { width: 0; overflow: visible; }
}

/* No transitions at all, not short ones: with the default `transition-property:
   all`, a .01ms duration made every style change on every element a transition,
   so layout read the old value until the next frame (BROWSER-CI-003). */
@media (prefers-reduced-motion: reduce) {
  * { animation-duration: .01ms !important; animation-iteration-count: 1 !important;
      transition: none !important; scroll-behavior: auto !important; }
}

@media (prefers-contrast: more) {
  :where(button, a, input, select, textarea) { border-width: 2px; }
  :where(button, a, input, select, textarea, [tabindex]):focus-visible {
    outline: 3px solid var(--accent); outline-offset: 3px;
  }
  .sub, .hint, .tags, .cat-count { color: var(--txt); }
}

/* Direction B working surfaces: keep the planner's shared chrome flat and
   reserve the data density for its three working regions. */
.night-brief { display: grid; grid-template-columns: minmax(180px, .7fr) minmax(0, 2fr); align-items: center; gap: 20px; min-width: 0; margin-bottom: 10px; padding: 9px 0 12px; border-bottom: 1px solid var(--line); }
.night-brief-title h1 { margin: 2px 0; color: var(--txt); font-size: 24px; }
.night-brief-title > span { color: var(--muted); font-size: 12px; }
.night-brief-facts { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 7px 12px; }
.night-brief-facts span { display: grid; gap: 3px; min-width: 0; }
.night-brief-facts small { color: var(--muted); font-size: 10px; text-transform: uppercase; letter-spacing: .07em; }
.night-brief-facts b { overflow: hidden; color: var(--txt); font: 600 12px var(--mono); text-overflow: ellipsis; white-space: nowrap; }
.night-brief-times { grid-column: 1 / -1; display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 8px; padding-top: 7px; border-top: 1px solid var(--line-soft); color: var(--muted); font: 11px var(--mono); }
.night-brief-times span { display: flex; gap: 8px; min-width: 0; }
.night-brief-times b { color: var(--txt); font-weight: 600; }
.sky-canvas-box canvas#sky:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.tonight-ranked { min-width: 0; margin: 0 0 10px; padding: 9px 11px; border: 1px solid var(--line); background: var(--panel); }
.tonight-ranked .panel-heading { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; margin-bottom: 5px; }
.tonight-ranked h2 { margin: 0; font-size: 15px; }
#tonight-rank-table { width: 100%; min-width: 680px; border-collapse: collapse; }
#tonight-rank-table th, #tonight-rank-table td { padding: 6px 8px; border-bottom: 1px solid var(--line); white-space: nowrap; }
#tonight-rank-table th { text-align: left; }
#tonight-rank-table th.num { text-align: right; }
#tonight-rank-table tbody tr { height: 50px; cursor: pointer; }
#tonight-rank-table tbody tr:hover td, #tonight-rank-table tbody tr:focus td { background: var(--hover); }
#tonight-rank-table td:nth-child(2) { min-width: 150px; }
#tonight-rank-table td:nth-child(2) small { display: block; color: var(--muted); font-size: 10px; }
#tonight-rank-table .rank { color: var(--accent); }
.tonight-footnote { margin: 8px 0; text-align: left; }
.pick li:focus-within { border-color: var(--accent); }
.pick-target {
  display: flex; width: 100%; min-width: 0; align-items: center; gap: 10px;
  padding: 0; border: 0; border-radius: 0; color: inherit; background: transparent;
  font: inherit; text-align: left; cursor: pointer;
}
.pick-target:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }

.catalog-layout { display: grid; grid-template-columns: minmax(216px, 236px) minmax(0, 1fr); gap: 14px; }
.cat-filter-rail {
  position: sticky; top: 150px; align-self: start; display: grid; gap: 12px;
  min-width: 0; padding: 14px; border: 1px solid var(--line); background: var(--panel);
}
.cat-filter-rail h2, .cat-results-head h2 { font-size: 14px; letter-spacing: .02em; }
.cat-filter-rail .cat-bar { display: grid; gap: 10px; }
.cat-filter-rail .chips { gap: 6px; }
.cat-filter-rail .chip { white-space: nowrap; }
.cat-filter-rail .cat-bar > select, .cat-filter-rail .cat-bar > input { width: 100%; min-width: 0; }
.cat-types { display: grid; gap: 6px; min-width: 0; margin: 0; padding: 0; border: 0; }
.cat-types legend { color: var(--txt); font-size: 12px; margin-bottom: 6px; }
.cat-types p, .cat-filter-help { color: var(--muted); font-size: 11px; line-height: 1.45; }
.cat-types label { display: flex; align-items: center; gap: 8px; min-height: 26px; color: var(--txt); font-size: 12px; cursor: pointer; }
.cat-types input { margin: 0; accent-color: var(--accent); }
.cat-types .btn { justify-self: start; padding: 4px 0; }
.cat-visibility { display: grid; gap: 5px; margin: 0; padding: 7px 8px; border: 1px solid var(--line); }
.cat-visibility legend { padding: 0 4px; color: var(--muted); font-size: 11px; }
.cat-visibility label, .cat-advanced > label:not(.minvis) { display: flex; align-items: center; gap: 6px; color: var(--txt); font-size: 12px; }
.cat-visibility input, .cat-advanced input[type="checkbox"] { margin: 0; accent-color: var(--accent); }
.cat-more { padding: 7px 8px; border: 1px solid var(--line); }
.cat-more summary { color: var(--txt); cursor: pointer; font-size: 12px; }
.cat-advanced { display: grid; gap: 8px; padding-top: 9px; }
.cat-advanced > select, .cat-advanced > button { width: 100%; min-width: 0; }
.cat-filter-rail .cat-bar input[type="search"] {
  width: 100%; max-width: 100%; min-width: 0; box-sizing: border-box;
}
.cat-results { min-width: 0; }
.cat-results-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 10px; }
.catalog-context { margin: 2px 0 0; color: var(--muted); font-size: 11px; }
.cat-stats { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 6px 14px; }
.cat-stats .cat-count { margin: 0; }
.cat-results .card { padding: 0; overflow: hidden; }
.cat-results .catwrap { min-width: 0; overflow-x: auto; }
.cat-results .catwrap { max-height: max(240px, calc(100dvh - var(--catalog-table-top, 220px) - 80px)); min-height: 0; overflow: auto; }
.cat-results table.cat.catalog-dense { width: 100%; min-width: 0; table-layout: fixed; }
.cat-results table.catalog-dense th, .cat-results table.catalog-dense td { padding: 4px 7px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cat-results table.catalog-dense th { padding-inline: 4px; font-size: 10px; letter-spacing: .04em; }
.cat-results table.catalog-dense th:nth-child(1), .cat-results table.catalog-dense td:nth-child(1) { width: 4%; }
.cat-results table.catalog-dense th:nth-child(2), .cat-results table.catalog-dense td:nth-child(2) { width: 14%; }
.cat-results table.catalog-dense th:nth-child(3), .cat-results table.catalog-dense td:nth-child(3) { width: 19%; }
.cat-results table.catalog-dense th:nth-child(4), .cat-results table.catalog-dense td:nth-child(4) { width: 11%; }
.cat-results table.catalog-dense th:nth-child(5), .cat-results table.catalog-dense td:nth-child(5) { width: 5%; }
.cat-results table.catalog-dense th:nth-child(6), .cat-results table.catalog-dense td:nth-child(6) { width: 9%; }
.cat-results table.catalog-dense th:nth-child(7), .cat-results table.catalog-dense td:nth-child(7) { width: 9%; }
.cat-results table.catalog-dense th:nth-child(8), .cat-results table.catalog-dense td:nth-child(8) { width: 14%; }
.cat-results table.catalog-dense th:nth-child(9), .cat-results table.catalog-dense td:nth-child(9) { width: 15%; }
.cat-results table.catalog-dense td.selected-condition { white-space: normal; line-height: 1.25; }
.cat-results table.catalog-dense tbody tr { height: 30px; }
.cat-results table.catalog-dense tbody tr:hover td, .cat-results table.catalog-dense tbody tr:focus td { background: var(--hover); }
.cat-results table.catalog-dense tbody tr.selected td { box-shadow: inset 0 1px 0 var(--accent), inset 0 -1px 0 var(--accent); background: color-mix(in srgb, var(--accent) 8%, transparent); }
.cat-results table.catalog-dense tbody tr.selected td:first-child { border-left: 1px solid var(--accent); }
.cat-results table.catalog-dense tbody tr.selected td:last-child { border-right: 1px solid var(--accent); }
.cat-results table.catalog-dense td.designation-cell,
.cat-results table.catalog-dense td.common-cell { overflow: hidden; text-overflow: ellipsis; }
.cat-results table.catalog-dense td.designation-cell > span,
.cat-results table.catalog-dense td.common-cell > .tname { overflow: hidden; text-overflow: ellipsis; vertical-align: middle; }
.cat-results table.catalog-dense td.designation-cell > span { display: inline-block; max-width: calc(100% - 28px); }
.cat-results table.catalog-dense td.common-cell > .tname { display: inline-block; max-width: 100%; }
.cat-results table.catalog-dense td.common-cell .f-own { display: inline-block; max-width: 38px; overflow: hidden; text-overflow: ellipsis; vertical-align: middle; white-space: nowrap; margin-left: 3px; font-size: 9px; }
.cat-results table.catalog-dense .rank { color: var(--accent); }
.cat-results table.catalog-dense .rank-cell { color: var(--accent); text-align: right; font-variant-numeric: tabular-nums; }
.cat-save { padding: 0 5px; border: 0; color: var(--muted); background: transparent; font-size: 15px; cursor: pointer; }
.cat-save.on { color: var(--accent); }
.catalog-table-card { padding: 0; overflow: hidden; }

.sky-workspace { grid-template-columns: minmax(0, 1fr) minmax(380px, 440px); align-items: start; gap: 14px; }
.sky-main { display: grid; grid-template-rows: auto minmax(0, 1fr); gap: 16px; min-width: 0; }
.sky-canvas-box { display: grid; place-items: center; min-width: 0; padding: 10px; }
.sky-canvas-box canvas#sky {
  display: block; width: min(100%, calc(100vh - 270px)); max-width: 100%; aspect-ratio: 1;
  margin: 0 auto; border: 1px solid var(--line); background: var(--viz-sky-surface, var(--bg));
}
.sky-time-rail { display: grid; grid-template-columns: max-content minmax(0, 1fr) auto; align-items: center; gap: 8px 16px; padding-bottom: 6px; border-bottom: 1px solid var(--line-soft); }
.sky-time-rail h3, .sky-time-rail p { margin: 0; }
.sky-time-rail label { display: grid; gap: 4px; min-width: 0; color: var(--muted); font-size: 12px; }
.sky-time-rail input[type="range"] { width: 100%; }
.sky-time-rail .btnrow { justify-content: flex-end; }
.sky-scrub { min-width: 0; }
.sky-time-rail .sky-scrub label { display: flex; align-items: baseline; flex-wrap: wrap; gap: 5px 8px; }
.sky-scrub output { color: var(--txt); }
.sky-range-times { display: flex; justify-content: space-between; color: var(--muted); font-size: 10px; }
.night-phase-legend { display: grid; gap: 2px; color: var(--muted); font-size: 11px; line-height: 12px; }
.night-phase-legend span { display: inline-flex; align-items: center; gap: 5px; }
.night-phase-legend i { display: inline-block; width: 12px; height: 5px; border-radius: 2px; }
.phase-civil { background: var(--scrub-civil); }
.phase-nautical { background: var(--scrub-nautical); }
.phase-astronomical { background: var(--scrub-astronomical); }
.phase-night { background: var(--scrub-night); }
input.night-scrub { appearance: none; height: 22px; margin: 0; background: transparent; cursor: pointer; }
input.night-scrub::-webkit-slider-runnable-track { height: 7px; border-radius: 4px; background: var(--night-track, var(--line)); box-shadow: inset 0 0 0 1px var(--line); }
input.night-scrub::-moz-range-track { height: 7px; border-radius: 4px; background: var(--night-track, var(--line)); box-shadow: inset 0 0 0 1px var(--line); }
input.night-scrub::-webkit-slider-thumb { appearance: none; width: 13px; height: 13px; margin-top: -3px; border: 1px solid var(--bg); border-radius: 50%; background: var(--accent); }
input.night-scrub::-moz-range-thumb { width: 13px; height: 13px; border: 1px solid var(--bg); border-radius: 50%; background: var(--accent); }
@media (min-width: 1440px) and (min-height: 900px) {
  .sky-canvas-box canvas#sky { width: min(100%, calc(100vh - 286px)); }
}
.sky-side { display: grid; align-content: start; gap: 12px; min-width: 0; }
.sky-side .card { margin: 0; }
#sky-detail-host:empty { display: none; }
#sky-detail-empty[hidden] { display: none; }
#modal.detail-inline {
  position: static; display: block; padding: 0; background: transparent;
  width: 100%; height: auto; min-width: 0; z-index: auto;
}
#modal.detail-inline[hidden] { display: none; }
#modal.detail-inline > .modal {
  width: 100%; max-width: 100%; height: auto; max-height: none; margin: 0;
  padding: 14px; box-sizing: border-box; overflow: visible;
  box-shadow: none; border-radius: 6px;
}
.sky-controls-tray > summary { cursor: pointer; font-size: 12px; font-weight: 650; }
.sky-controls-tray > * + * { margin-top: 8px; }
.sky-chart-hint { margin-bottom: 0; }

.horizon-layout { display: grid; grid-template-columns: minmax(200px, 230px) minmax(0, 1fr) minmax(250px, 280px); align-items: start; gap: 16px; }
.horizon-layout:not(:has(.horizon-settings-rail)) { grid-template-columns: minmax(210px, 245px) minmax(0, 1fr); }
.horizon-tools-rail { display: grid; align-content: start; gap: 12px; min-width: 0;
  position: sticky; top: 150px; align-self: start;
  max-height: calc(100dvh - 170px); overflow-y: auto; scrollbar-gutter: stable; }
.horizon-tools-rail > .card { width: 100%; min-width: 0; box-sizing: border-box; }
#hz-list { display: grid; }
#hz-list li { display: flex; align-items: center; gap: 8px; min-width: 0; margin: 0; }
#hz-list .p-name { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 13.5px; cursor: pointer; }
#hz-list .p-tags { margin-left: 0; white-space: nowrap; }
#hz-list input[type="radio"] { accent-color: var(--accent); }
#hz-list .hz-empty { color: var(--muted); font-size: 12px; line-height: 1.5; cursor: default; }
.hz-new { display: grid; gap: 8px; margin-top: 12px; }
.hz-new .btn { text-align: center; }
.horizon-stage { min-width: 0; }
.horizon-editor-title { margin: 0 0 12px; }
.hz-head { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 8px 12px; margin-bottom: 8px; }
.hz-name { display: flex; align-items: center; gap: 8px; font-size: 12px; color: var(--muted); }
.hz-name input { width: 220px; max-width: 55vw; padding: 6px 8px; font-size: 13px;
  color: var(--txt); background: var(--panel); border: 1px solid var(--line); border-radius: 8px; }
.horizon-stage > .ed-tools { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 16px;
  padding: 6px 0; margin-bottom: 8px; position: sticky; top: 150px; z-index: 12;
  background: var(--bg); border-bottom: 1px solid var(--line-soft); }
.ed-group { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; min-width: 0; }
.ed-group .btn { flex: 0 0 auto; }
.hz-modes .btn[aria-pressed="true"] { border-color: var(--accent); outline: 1px solid var(--accent); color: var(--txt); }
.horizon-stage > .ed-tools .ed-status { margin-left: auto; }
.hz-canvas-box { position: relative; min-width: 0; padding-top: 34px; }
/* resize() sets a pixel width; max-width keeps the canvas inside its box when
   the box narrows before the resize observer runs (BROWSER-CI-002). */
#hz-canvas { display: block; width: 100%; max-width: 100%; touch-action: none; cursor: crosshair; background: var(--viz-canvas-bg); }
#hz-canvas.panning { cursor: grabbing; }
#hz-canvas:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.horizon-stage .ed-hint { line-height: 1.5; overflow-wrap: anywhere; }
.ed-hint .ed-readout, .ed-hint .ed-help { display: block; }
.ed-hint .ed-readout { min-height: 1.5em; }
.hz-summary { margin-top: 4px; }
.horizon-settings-rail { display: grid; align-content: start; gap: 0; position: sticky; top: 150px; max-height: calc(100dvh - 170px); overflow: auto; min-width: 0; }
.hz-panel { padding: 10px 0; border-bottom: 1px solid var(--line-soft); min-width: 0; font-size: 12px; }
.hz-panel > summary { cursor: pointer; color: var(--muted); }
.hz-panel .btnrow { gap: 6px; margin-top: 8px; }
.hz-fields { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; margin: 8px 0 0; padding: 0; border: 0; min-width: 0; }
.hz-fields legend { padding: 0; margin-bottom: 4px; color: var(--txt); font-size: 12px; }
.hz-fields label { display: flex; flex-direction: column; gap: 4px; min-width: 0; color: var(--muted); }
.hz-fields input { width: 100%; min-width: 0; box-sizing: border-box; }
.hz-fields .btn { grid-column: 1 / -1; justify-self: start; }
.ed-display > label { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-top: 8px; color: var(--muted); }
/* Phone capture (capture.js): a full-screen camera view with a crosshair.
   Panels above and below the video stay readable over any scene. */
/* While the capture is open, no swipe scrolls or refreshes the page under it. */
.cap-open, .cap-open body { overscroll-behavior: none; }
.cap { position: fixed; inset: 0; z-index: 80; display: flex; flex-direction: column; justify-content: space-between; overflow: hidden; background: var(--bg); color: var(--txt); }
.cap-video { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.cap-no-video .cap-video { display: none; }
.cap-ar { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; }
.cap-cross { position: absolute; left: 50%; top: 50%; width: 72px; height: 72px; margin: -36px 0 0 -36px; pointer-events: none; }
.cap-cross::before, .cap-cross::after { content: ""; position: absolute; background: var(--txt); box-shadow: 0 0 0 1px var(--bg); }
.cap-cross::before { left: 35px; top: 0; width: 2px; height: 72px; }
.cap-cross::after { top: 35px; left: 0; width: 72px; height: 2px; }
/* Mobile first: an opaque bar above and below the camera (no translucent
   panels), the readout large at the top, and the controls a thumb reaches
   at the bottom. Nothing grows over the crosshair in the middle. */
.cap-top, .cap-bottom { position: relative; background: var(--panel); box-sizing: border-box; overflow-y: auto; }
.cap-top { padding: max(8px, env(safe-area-inset-top)) 14px 8px; border-bottom: 1px solid var(--line); max-height: 35%; }
.cap-bottom { padding: 8px 14px max(10px, env(safe-area-inset-bottom)); border-top: 1px solid var(--line); max-height: 45%; }
.cap .btn { min-height: 48px; display: inline-flex; align-items: center; justify-content: center; gap: 6px; font-size: 14px; }
.cap .btn[hidden] { display: none; }
.cap-topline { display: flex; align-items: center; gap: 12px; }
.cap-done { flex: 0 0 auto; }
.cap-read { flex: 1 1 auto; margin: 0; min-width: 0; text-align: right; font-size: clamp(15px, 4.6vw, 21px); font-weight: 600; font-variant-numeric: tabular-nums; white-space: pre; overflow: hidden; }
.cap-read.cap-read-msg { font: 13px/1.35 system-ui, sans-serif; text-align: left; color: var(--muted); white-space: normal; }
.cap .cap-north-btn { width: 100%; margin-top: 8px; min-height: 44px; justify-content: space-between; font-size: 13px; color: var(--muted); }
.cap-site, .cap-status { margin: 6px 0 0; font-size: 13px; line-height: 1.35; }
.cap-site { color: var(--amber); }
.cap-site:empty { display: none; }
.cap-status { color: var(--muted); }
/* Turning too fast while tracing: the crosshair and the status line (which
   says so in words) take the warning colour. */
.cap-fast .cap-cross::before, .cap-fast .cap-cross::after { background: var(--amber); }
.cap-fast .cap-status { color: var(--amber); }
.cap-strip { display: block; width: 100%; height: 40px; margin-bottom: 8px; border-radius: 4px; }
.cap-main { display: grid; gap: 8px; }
.cap-row { display: flex; align-items: center; gap: 8px; }
.cap-pair > .btn { flex: 1 1 0; }
.cap-modes { display: flex; flex: 1 1 auto; }
.cap-modes .btn { flex: 1 1 0; border-radius: 0; }
.cap-modes .btn:first-child { border-radius: 6px 0 0 6px; }
.cap-modes .btn:last-child { border-radius: 0 6px 6px 0; border-left: 0; }
.cap-modes .btn[aria-pressed="true"], .cap-chip[aria-pressed="true"] { border-color: var(--accent); color: var(--accent); box-shadow: inset 0 -2px 0 var(--accent); }
.cap-chip { flex: 0 0 auto; }
.cap-thumb { display: grid; grid-template-columns: 1fr 1.5fr 1fr; gap: 8px; align-items: stretch; }
.cap .cap-trace { min-height: 64px; font-size: 17px; font-weight: 600; touch-action: manipulation; user-select: none; -webkit-user-select: none; -webkit-touch-callout: none; }
.cap-trace[aria-pressed="true"] { outline: 2px solid var(--accent); outline-offset: 2px; }
.cap-panel { margin: 0 0 8px; padding: 10px 12px; border: 1px solid var(--line); border-radius: 6px; background: var(--raised); }
.cap-panel[hidden] { display: none; }
.cap-panel p { margin: 0 0 8px; }
.cap-panel .cap-row + .cap-row, .cap-panel .cap-row + p { margin-top: 8px; }
.cap-small { font-size: 12.5px; color: var(--muted); }
.cap-small:empty { display: none; }
/* The north panel's diagnostics (compass, camera) wait behind Details. */
.cap-details { margin-top: 8px; }
.cap-details > summary { padding: 13px 0; font-size: 13px; line-height: 18px; color: var(--muted); cursor: pointer; }
.cap-details[open] > summary { margin-bottom: 4px; }
.cap-asking .cap-main, .cap-asking .cap-strip { display: none; }
.cap-ref-az { flex: 0 1 110px; min-width: 0; min-height: 48px; box-sizing: border-box; }
.cap-row > #cap-ref-landmark { flex: 1 1 auto; }
/* Short screens (a phone held sideways): drop the overview strip. */
@media (max-height: 560px) {
  .cap-strip { display: none; }
  .cap-top { max-height: 40%; }
  .cap-read { font-size: 18px; }
}
@media (max-width: 640px) {
  .horizon-stage > .ed-tools { top: 8px; max-height: min(240px, 40dvh); overflow-y: auto; }
}

/* A target detail becomes a reserved inspector rail on wide planning surfaces;
   at narrow sizes the same accessible detail remains a modal dialog. */
#modal.detail-docked {
  position: fixed; inset: var(--detail-top, 130px) 0 0 auto; z-index: 40;
  display: flex; width: var(--detail-width, min(420px, 32vw)); padding: 0;
  overflow: hidden; background: transparent; pointer-events: none;
}
#modal.detail-docked > .modal {
  width: 100%; max-width: none; height: 100%; max-height: none; margin: 0;
  padding: 18px; overflow: auto; border-width: 0 0 0 1px; border-radius: 0;
  pointer-events: auto;
}
body.detail-open { --detail-width: clamp(340px, 26vw, 420px); }
body.detail-open[data-primary-view="catalog"] { --detail-width: min(34vw, 560px); }
body.detail-open main { max-width: none; margin-left: var(--edge, 16px); margin-right: var(--detail-width); }
#m-selected-position, #m-selected-separation { font-family: var(--mono); }

@media (max-width: 1240px) {
  .cat-filter-rail { position: static; }
  .cat-results table.cat.catalog-dense { min-width: 930px; }
  .sky-workspace { grid-template-columns: minmax(0, 1fr) minmax(360px, 400px); }
  .sky-time-rail { gap: 8px 12px; }
  .sky-time-rail .btnrow { flex-direction: column; gap: 2px; align-items: flex-end; }
  .horizon-layout { grid-template-columns: minmax(200px, 230px) minmax(0, 1fr); }
  .horizon-tools-rail { position: static; max-height: none; overflow: visible; }
  .horizon-settings-rail { position: static; grid-column: 2; max-height: none; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0 16px; }
}
@media (max-width: 1099px) {
  body.detail-open main { max-width: min(100%, max(320px, calc(100% - 2 * var(--edge, 16px)))); margin: 0 auto; }
}
@media (max-width: 900px) {
  .night-brief { grid-template-columns: minmax(0, 1fr); gap: 10px; }
  .night-brief-facts { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .night-brief-times { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  #tonight-rank-table { width: 100%; min-width: 0; table-layout: fixed; }
  #tonight-rank-table th, #tonight-rank-table td {
    overflow: hidden; text-overflow: ellipsis; padding: 6px 5px;
  }
  #tonight-rank-table th:nth-child(1) { width: 5%; }
  #tonight-rank-table th:nth-child(2) { width: 28%; }
  #tonight-rank-table th:nth-child(3) { width: 17%; }
  #tonight-rank-table th:nth-child(4) { width: 16%; }
  #tonight-rank-table th:nth-child(5) { width: 34%; }
  .catalog-layout { display: grid; grid-template-columns: minmax(0, 1fr); }
  .cat-filter-rail { position: static; }
  .cat-filter-rail .chips { display: flex; flex-wrap: wrap; }
  .cat-results .catwrap { max-height: 65dvh; }
  .sky-workspace { grid-template-columns: minmax(0, 1fr); }
  .sky-canvas-box canvas#sky { width: min(100%, calc(100vh - 230px)); }
  .sky-side { grid-template-columns: minmax(0, 1fr); }
  .horizon-layout { grid-template-columns: minmax(0, 1fr); }
  .horizon-tools-rail > .card { position: static; }
  .hz-new { grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); }
  .horizon-settings-rail { grid-column: 1; grid-template-columns: minmax(0, 1fr); }
  .horizon-settings-rail { position: static; max-height: none; }
}
@media (max-width: 640px) {
  .cat-results-head { align-items: flex-start; flex-direction: column; }
  /* Phones: the count may wrap with wider system fonts (Linux, large text)
     instead of widening the page, and the status gets its own reserved line,
     so progress text still never moves the table. */
  .cat-stats { justify-content: flex-start; flex-direction: column; align-items: flex-start;
    gap: 2px; width: 100%; height: auto; white-space: normal; line-height: 18px; }
  #pct-status { min-width: 0; min-height: 18px; text-align: left; }
  .sky-canvas-box { padding: 5px; }
  .sky-canvas-box canvas#sky { width: 100%; }
  .sky-time-rail { grid-template-columns: minmax(0, 1fr) auto; }
  .sky-time-rail .sky-scrub { grid-column: 1 / -1; grid-row: 1; }
  .night-phase-legend { grid-template-columns: repeat(2, max-content); gap: 3px 10px; }
  .sky-time-rail .btnrow { grid-column: 2; }
  .sky-side { grid-template-columns: minmax(0, 1fr); }
  #modal.detail-docked { display: none; }
}

/* Tonight's session facts and booked-night track use the shared Workbench
   layout. */
.session-head {
  display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 18px;
  align-items: end; min-width: 0; margin-bottom: 12px; padding-bottom: 4px;
  border-bottom: 1px solid var(--line);
}
.session-head h1 {
  margin: 2px 0 3px; color: var(--txt); font-size: 25px;
  font-weight: 650; letter-spacing: -.02em;
}
.eyebrow {
  margin: 0; color: var(--accent); font-size: 10px; text-transform: uppercase;
  letter-spacing: 1.4px; font-weight: 700;
}
.session-context, .session-facts { color: var(--muted); font-size: 12px; }
.session-facts {
  display: grid; grid-template-columns: auto auto; gap: 3px 10px;
  text-align: right; font-family: var(--mono);
}
.session-facts b { color: var(--txt); font-weight: 600; }
.night-track {
  min-width: 0; margin: 12px 0; padding: 11px 13px 10px;
  background: var(--panel); border: 1px solid var(--line); border-radius: 5px;
}
.track-head, .track-scale {
  display: flex; justify-content: space-between; gap: 10px;
  color: var(--muted); font-size: 11px;
}
.track-head strong { color: var(--txt); font-weight: 600; }
.track-bar {
  position: relative; height: 8px; margin: 9px 0 6px;
  background: var(--raised); border: 1px solid var(--line); border-radius: 2px;
}
.track-window { position: absolute; inset: 1px; background: var(--accent); opacity: .78; border-radius: 1px; }
.track-marker {
  position: absolute; top: -5px; width: 2px; height: 16px;
  background: var(--accent); box-shadow: 0 0 0 1px var(--bg);
}
@media (max-width: 900px) {
  .session-head { display: block; }
  .session-facts { margin-top: 8px; text-align: left; }
}

/* The docked inspector fits its metadata and chart in the reserved rail. */
#modal.detail-docked > .modal {
  overflow-x: hidden; overflow-y: auto;
}
#modal:is(.detail-docked, .detail-inline) .detail-hero { grid-template-columns: 108px minmax(0, 1fr); gap: 10px; min-width: 0; }
#modal:is(.detail-docked, .detail-inline) #objimg-wrap,
#modal:is(.detail-docked, .detail-inline) .detail-hero-copy,
#modal:is(.detail-docked, .detail-inline) .tonight-box { min-width: 0; }
#modal:is(.detail-docked, .detail-inline) .objimg,
#modal:is(.detail-docked, .detail-inline) .objimg-ph {
  display: block; width: 100%; height: 90px; object-fit: cover;
}
#modal:is(.detail-docked, .detail-inline) .objimg-ph { display: none; }
#modal:is(.detail-docked, .detail-inline) .meta { grid-template-columns: minmax(0, 120px) minmax(0, 1fr); width: 100%; }
#modal:is(.detail-docked, .detail-inline) .detail-hero-facts,
#modal:is(.detail-docked, .detail-inline) .detail-visibility-facts { grid-template-columns: minmax(76px, 94px) minmax(0, 1fr); font-size: 11px; gap: 4px 6px; }
#modal:is(.detail-docked, .detail-inline) canvas#graph { height: 220px; }
#modal:is(.detail-docked, .detail-inline) .chart-legend { grid-template-columns: minmax(0, 1fr); }
#modal:is(.detail-docked, .detail-inline) .meta dt,
#modal:is(.detail-docked, .detail-inline) .meta dd { min-width: 0; overflow-wrap: anywhere; }
#modal:is(.detail-docked, .detail-inline) canvas#graph { width: 100%; max-width: 100%; }

/* Phase 4: wrap useful control groups instead of shrinking their text. */
.topbar {
  display: grid; grid-template-columns: auto minmax(0, 1fr) auto;
  gap: 8px 16px; padding: 8px 16px; align-items: center;
}
.brand { gap: 8px; min-width: 0; }
.brand-ico { width: 26px; height: 26px; }
.brand h1 { font-size: 18px; }
.tagline { display: none; }
.planner-controls { grid-column: 1 / -1; grid-row: 2; gap: 12px 24px; min-width: 0; }
.context-controls, .time-controls { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; min-width: 0; }
.context-picker { display: flex; align-items: center; gap: 5px; min-width: 0; }
.context-settings { padding: 2px 0; font-size: 13px; }
.context-settings:hover { text-decoration: underline; }
.planner-controls label, .control-label { font-size: 13px; color: var(--muted); }
.planner-controls select, .planner-controls input[type="date"] { font-size: 14px; border-radius: 5px; min-height: 34px; min-width: 0; }
#tb-site { max-width: 180px; }
#rigSelect { max-width: 190px; }
.minalt input[type="range"] { width: 110px; min-height: 30px; }
.minalt .mono, .minalt .note { font-size: 12px; }
.scrub { gap: 8px; }
.scrub input[type="range"] { width: 120px; min-height: 30px; }
.scrub strong { display: inline; font-size: 14px; min-width: 48px; }
.topbar-right { grid-column: 3; grid-row: 1; flex-wrap: nowrap; gap: 8px; }
.weatherbtn { font-size: 13px; max-width: 230px; min-height: 34px; }
.menubtn { min-width: 36px; min-height: 34px; justify-content: center; }
.nightinfo { font-size: 12px; white-space: normal; padding: 0; border: 0; border-radius: 0; background: none; max-width: none; overflow: visible; }
.busy-slot { grid-column: 2; grid-row: 1; justify-self: end; width: 130px; }
#menuPanel.menu-panel, #weatherPanel.weather-panel { max-height: min(72vh, 560px); }
.modal.settings .set-form { grid-template-columns: repeat(auto-fit, minmax(min(150px, 100%), 1fr)); }
.modal.settings .pick li { flex-wrap: wrap; min-width: 0; }
.modal.settings .p-tags { overflow-wrap: anywhere; }
.modal.welcome .sub + .sub { margin-top: 10px; }
.modal.welcome #w-status { margin-top: 10px; }
.tonight-ranked, .tonight-ranked .tablewrap { min-width: 0; max-width: 100%; }
.tablewrap { overflow-x: auto; max-width: 100%; }
@media (max-width: 900px) {
  .nightinfo { flex-basis: 100%; }
  .horizon-layout, .horizon-layout:not(:has(.horizon-settings-rail)) { grid-template-columns: minmax(0, 1fr); }
  .context-controls, .time-controls { flex: 1 1 100%; }
  #tonight-rank-table { min-width: 680px; table-layout: auto; }
  #tonight-rank-table th, #tonight-rank-table td { overflow: visible; text-overflow: clip; padding: 6px 8px; }
  #tonight-rank-table th:nth-child(n) { width: auto; }
}
@media (max-width: 640px) {
  .topbar { position: static; gap: 8px; padding: 8px 12px; }
  .brand-ico { display: none; }
  .brand h1 { font-size: 16px; }
  .topbar-right { gap: 6px; }
  .weatherbtn { max-width: 120px; }
  .busy-slot { width: 0; height: 0; overflow: hidden; }
  #busy { position: static; }
  .planner-controls { gap: 10px; }
  .context-controls { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
  .context-controls > label, .context-picker { display: grid; gap: 4px; min-width: 0; }
  .context-settings { justify-self: start; }
  .context-controls .minalt { grid-column: 1 / -1; display: flex; flex-wrap: wrap; }
  #tb-site, #rigSelect { width: 100%; max-width: 100%; }
  .minalt input[type="range"] { flex: 1; min-width: 80px; }
  .time-controls { display: grid; grid-template-columns: minmax(0, 1fr); }
  .nightof { justify-content: space-between; }
  .scrub input[type="range"] { flex: 1; min-width: 60px; }
  .scrub strong { display: inline; }
  #menuPanel.menu-panel, #weatherPanel.weather-panel {
    position: fixed; top: 50px; right: 12px; width: calc(100vw - 24px);
    max-width: none; max-height: calc(100dvh - 64px);
  }
  .nightinfo { font-size: 12px; }
  .modal.settings .modal-tabs { width: 100%; }
  .modal-tabs .tab { flex: 1; padding: 8px; }
}

/* ---------- night vision ----------
   A red display keeps the observer's eyes dark-adapted at the telescope:
   every colour, chart and photo is mapped to its brightness in red only. The
   filter sits on the root element, which (unlike any other element) does not
   become the containing block of fixed-position content. */
html.night-red { filter: url(#ns-night-red); }
.night-filter-defs { position: absolute; width: 0; height: 0; overflow: hidden; }
.redbtn { display: inline-flex; align-items: center; justify-content: center; min-width: 36px; min-height: 34px; padding: 6px 8px; }
.redbtn svg { display: block; }
html[data-theme] .redbtn[aria-pressed="true"] { color: var(--accent); }
.redbtn[aria-pressed="true"] svg { fill: currentColor; fill-opacity: .3; }

/* Headings that only receive focus from script (dialog openings) are not
   controls: no focus ring that would read as a selected field. */
h2[tabindex="-1"]:focus { outline: none; }

/* Sky map zoom buttons: the map can zoom without a mouse wheel. */
.sky-zoom { display: inline-flex; gap: 4px; }
html[data-theme] .sky-zoom .btn {
  display: grid; place-items: center; width: 34px; height: 34px; padding: 0;
  border: 1px solid var(--line); border-radius: 5px; color: var(--txt); font: 600 18px/1 system-ui, sans-serif;
}

/* Phone-only pieces, hidden on wider screens. */
.ctx-summary, .ctx-sheet-head, .cat-filters-toggle, .row-meta, .tabs .tab-ico { display: none; }

/* ---------- phone layout ----------
   Phones (and phones held sideways) get a layout of their own instead of the
   desktop one stacked: the answer comes first, and the controls used most sit
   at the bottom where the thumb reaches.
   - The header is the brand row plus one summary line ("Berlin · min 25° ·
     Tue 20 Oct"); it opens the observing setup as a sheet from the bottom.
   - The four views are a bottom tab bar with a pinned time slider above it,
     so the selected time stays in reach on every view.
   - Lists are two-line rows instead of tables that scroll sideways.
   - Every control is at least 44 px, form fields use 16 px text (smaller text
     makes iOS zoom the page on focus) and no text is below 12 px. */
@media (max-width: 640px), (max-height: 500px) and (max-width: 1000px) and (pointer: coarse) {
  :root { --tabbar-h: 58px; --timebar-h: 52px; }
  html[data-theme] body {
    padding-bottom: calc(var(--tabbar-h) + var(--timebar-h) + env(safe-area-inset-bottom));
  }

  /* header: brand row + summary line */
  html[data-theme] .topbar {
    position: relative; display: grid; grid-template-columns: minmax(0, 1fr) auto;
    gap: 8px; padding: max(8px, env(safe-area-inset-top)) 16px 10px;
    z-index: 60; /* its menus and the setup sheet open over the bottom bars */
  }
  .brand { grid-column: 1; grid-row: 1; }
  .brand h1 { font-size: 18px; }
  .busy-slot { position: absolute; width: 0; height: 0; overflow: hidden; }
  .topbar-right { grid-column: 2; grid-row: 1; gap: 2px; }
  .weatherbtn { max-width: 112px; }
  html[data-theme] :is(.redbtn, .menubtn, .weatherbtn) { min-width: 44px; min-height: 44px; }
  .ctx-summary {
    grid-column: 1 / -1; grid-row: 2; display: flex; align-items: center; justify-content: space-between;
    gap: 8px; width: 100%; min-height: 44px; padding: 0 12px;
    border: 1px solid var(--line); border-radius: 6px; background: var(--panel);
    color: var(--txt); font: 15px/1.25 system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
    text-align: left; cursor: pointer;
  }
  .ctx-summary-text { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .ctx-summary svg { flex: none; color: var(--muted); transition: transform .15s; }
  .ctx-summary[aria-expanded="true"] svg { transform: rotate(180deg); }

  /* observing setup sheet (the top-bar controls themselves) */
  html[data-theme] .planner-controls {
    position: fixed; left: 0; right: 0; z-index: 65;
    bottom: calc(var(--tabbar-h) + var(--timebar-h) + env(safe-area-inset-bottom));
    display: flex; flex-direction: column; align-items: stretch; gap: 14px;
    max-height: calc(100dvh - var(--tabbar-h) - var(--timebar-h) - 32px); overflow-y: auto;
    padding: 14px 16px 18px; border-top: 1px solid var(--line); border-radius: 10px 10px 0 0;
    background: var(--panel); visibility: hidden;
  }
  html[data-theme] .topbar.ctx-open .planner-controls {
    visibility: visible; box-shadow: 0 0 0 100vmax rgba(0, 0, 0, .55);
  }
  .ctx-sheet-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
  .ctx-sheet-head h2 { margin: 0; font-size: 17px; }
  html[data-theme] .ctx-sheet-head .ghost { color: var(--accent); font-weight: 650; }
  .context-controls { display: grid; grid-template-columns: minmax(0, 1fr); gap: 12px; }
  .context-controls > label, .context-picker { display: grid; grid-template-columns: 64px minmax(0, 1fr); align-items: center; gap: 8px; min-width: 0; }
  .context-settings { justify-self: start; }
  .context-controls .minalt { grid-column: 1 / -1; display: flex; flex-wrap: wrap; align-items: center; }
  #tb-site, #rigSelect { width: 100%; max-width: 100%; }
  .minalt input[type="range"] { flex: 1; min-width: 80px; }
  .time-controls { display: grid; grid-template-columns: minmax(0, 1fr); gap: 12px; }
  .nightof { justify-content: space-between; }
  .nightinfo { flex-basis: auto; font-size: 13px; }

  /* pinned time slider, above the tab bar */
  html[data-theme] .scrub {
    position: fixed; left: 0; right: 0; z-index: 56; visibility: visible;
    bottom: calc(var(--tabbar-h) + env(safe-area-inset-bottom)); height: var(--timebar-h);
    display: flex; align-items: center; gap: 12px; padding: 0 16px;
    border-top: 1px solid var(--line-soft); background: var(--bg);
  }
  html[data-theme] .scrub input[type="range"] { flex: 1; width: auto; min-width: 0; height: 44px; }
  .scrub strong { font-size: 16px; min-width: 52px; }
  .scrub .control-label { font-size: 13px; }

  /* bottom tab bar */
  html[data-theme] .tabs {
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 56;
    display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 0;
    padding: 0 0 env(safe-area-inset-bottom); border-top: 1px solid var(--line); border-bottom: 0;
    background: var(--panel);
  }
  html[data-theme] .tabs a {
    display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 3px;
    height: var(--tabbar-h); padding: 4px 2px 6px; border-top: 2px solid transparent; border-bottom: 0;
    font-size: 12px; line-height: 1.1; text-align: center;
  }
  html[data-theme] .tabs a.active { border-top-color: var(--accent); border-bottom-color: transparent; }
  .tabs .tab-ico { display: block; }
  .cap-open .tabs, .cap-open .scrub { display: none !important; }

  html[data-theme] main { padding: 14px 16px 24px; }
  /* menus end above the bottom bars instead of running under them */
  html[data-theme] :is(#menuPanel.menu-panel, #weatherPanel.weather-panel) {
    max-height: calc(100dvh - 64px - var(--tabbar-h) - var(--timebar-h) - env(safe-area-inset-bottom));
  }

  /* minimum text size (touch sizes: the block after this one) */
  html[data-theme] :is(.hint, .sub, small, .tags, .note, .eyebrow, .cat-count, .catalog-context,
    .night-brief-facts small, .chart-legend-heading, .cat-filter-help, #cat-type-help) { font-size: 12px; }
  .night-brief-times { font-size: 12px; }
  .night-brief-facts b { font-size: 13px; }
  html[data-theme] .brand { min-height: 44px; }
  html[data-theme] :is(.night-phase-legend span, .p-tags, #ed-zoom-label) { font-size: 12px; }
  html[data-theme] .cat-results table.catalog-dense td.common-cell .f-own { max-width: none; font-size: 12px; }
  html[data-theme] :is(.ed-view-overlay .btn, .pick .btn.small, [data-del]) { min-width: 44px; }
  .foot a { display: inline-block; padding: 13px 2px; }

  /* Tonight: rank, then the target with its best interval underneath. The
     list order is the ranking; the selected time is in the pinned bar. */
  #tonight-rank-table { min-width: 0; table-layout: auto; }
  #tonight-rank-table th:nth-child(n+3), #tonight-rank-table td:nth-child(n+3) { display: none; }
  #tonight-rank-table :is(th, td):first-child { width: 40px; }
  .night-brief { gap: 10px; padding: 0 0 10px; }
  .night-brief-title h1 { font-size: 20px; }
  .night-brief-facts { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .night-brief-facts > span:first-child { display: none; }
  #tonight-rank-table th { font-size: 12px; white-space: normal; }
  #tonight-rank-table td { padding: 10px 6px; }
  #tonight-rank-table td:nth-child(2) { min-width: 0; white-space: normal; }
  #tonight-rank-table td:nth-child(2) small { font-size: 12px; }
  #tonight-rank-table .target-open { min-height: 0; padding: 0; text-align: left; }
  .row-meta { display: block; margin-top: 3px; color: var(--muted); font-size: 12px; line-height: 1.35; white-space: normal; }
  #tonight-rank-table .row-meta { color: var(--txt); font-size: 13px; }
  .tonight-ranked .panel-heading { flex-direction: column; align-items: flex-start; gap: 2px; }

  /* Catalog: filters behind a button, rows as name + facts */
  html[data-theme] .cat-results .catwrap { max-height: none; overflow: visible; }
  html[data-theme] .cat-results table.catalog-dense { table-layout: auto; width: 100%; min-width: 0; }
  html[data-theme] .cat-results table.catalog-dense :is(th, td):nth-child(n+4) { display: none; }
  html[data-theme] .cat-results table.catalog-dense :is(th, td):nth-child(1) { width: 32px; }
  html[data-theme] .cat-results table.catalog-dense :is(th, td):nth-child(2) { width: 48px; }
  html[data-theme] .cat-results table.catalog-dense :is(th, td):nth-child(3) { width: auto; }
  html[data-theme] .cat-results table.catalog-dense th { font-size: 12px; }
  html[data-theme] .cat-results table.catalog-dense th:nth-child(2) { font-size: 0; }
  html[data-theme] .cat-results table.catalog-dense td.designation-cell > span { display: none; }
  html[data-theme] .cat-results table.catalog-dense td { padding-block: 8px; }
  html[data-theme] .cat-results table.catalog-dense tbody tr { height: auto; }
  html[data-theme] .cat-results table.catalog-dense td.common-cell { overflow: visible; white-space: normal; }
  html[data-theme] .cat-results table.catalog-dense td.common-cell > .tname { max-width: 100%; min-height: 0; text-align: left; white-space: normal; }
  html[data-theme] .cat-save { min-width: 44px; font-size: 20px; }
  .pager { justify-content: space-between; }

  /* Sky View: the pinned slider sets the time; the rail keeps phase, Now and Reset */
  html[data-theme] .sky-time-rail .sky-scrub input,
  html[data-theme] .sky-time-rail .sky-range-times { display: none; }
  html[data-theme] .sky-time-rail .btnrow {
    grid-column: 1 / -1; flex-direction: row; flex-wrap: wrap; align-items: center; justify-content: flex-start; gap: 8px;
  }
  html[data-theme] .sky-time-rail .sky-zoom { margin-left: auto; }

  /* target details and dialogs: a sheet from the bottom with its head pinned */
  #modal.modal-wrap:not(.detail-docked):not(.detail-inline) { padding: 24px 0 0; }
  #modal.modal-wrap:not(.detail-docked):not(.detail-inline) > .modal {
    width: 100%; max-width: none; margin: auto 0 0; border-bottom: 0;
    border-radius: 12px 12px 0 0; padding: 0 16px calc(16px + env(safe-area-inset-bottom));
  }
  #modal.modal-wrap:not(.detail-docked):not(.detail-inline) .modal-head {
    position: sticky; top: -24px; z-index: 3; padding: 14px 0 8px; background: var(--panel);
  }
  html[data-theme] .modal .close { width: 44px; height: 44px; }
  html[data-theme] .sky-zoom .btn { width: 44px; height: 44px; }
  html[data-theme] .detail-favorite { width: 44px; height: 44px; flex-basis: 44px; }
}
/* Where the filter rail would stack above the results on a phone or a touch
   tablet in portrait, it folds behind a Filters button instead. A narrowed
   desktop window keeps the open rail and its search box. */
@media (max-width: 640px), (max-width: 900px) and (pointer: coarse) {
  html[data-theme] .catalog-layout { grid-template-columns: minmax(0, 1fr); gap: 12px; }
  html[data-theme] .catalog-layout .cat-filters-toggle {
    display: inline-flex; align-items: center; justify-self: start; min-height: 44px; padding: 0 14px;
    border: 1px solid var(--line); border-radius: 6px; color: var(--txt);
  }
  html[data-theme] .catalog-layout:not(.filters-open) .cat-filter-rail { display: none; }
  .cat-filter-rail > h2 { display: none; }
  html[data-theme] .cat-filter-rail { position: static; padding: 0 0 12px; border-bottom: 1px solid var(--line-soft); }
}
/* Touch sizes for phones and for every touch screen, tablets included:
   44 px controls and 16 px form text (smaller makes iOS zoom on focus). */
@media (max-width: 640px), (pointer: coarse) {
  html[data-theme] :is(input:not([type="checkbox"]):not([type="radio"]):not([type="range"]), select, textarea) {
    min-height: 44px; font-size: 16px;
  }
  html[data-theme] .planner-controls :is(select, input[type="date"]) { font-size: 16px; min-height: 44px; }
  html[data-theme] :is(button, .btn, .ghost, .chip, label.btn, .table-sort) { min-height: 44px; }
  html[data-theme] .context-settings { min-width: 44px; min-height: 44px; padding: 0 2px; text-align: left; font-size: 14px; }
  html[data-theme] input[type="range"] { min-height: 44px; }
  html[data-theme] summary { display: list-item; min-height: 44px; padding-block: 12px; }
  html[data-theme] label:has(> input:is([type="checkbox"], [type="radio"])) { display: flex; align-items: center; gap: 10px; min-height: 44px; }
  html[data-theme] input:is([type="checkbox"], [type="radio"]) { width: 20px; height: 20px; }
}
/* The Horizon editor does not use the selected time: give its grid the room. */
@media (max-width: 640px), (max-height: 500px) and (max-width: 1000px) and (pointer: coarse) {
  html[data-theme] body[data-primary-view="horizon"] .scrub { display: none; }
  html[data-theme] body[data-primary-view="horizon"] { padding-bottom: calc(var(--tabbar-h) + env(safe-area-inset-bottom)); }
}
/* Phones held sideways: little height, so slimmer bars, the summary beside the
   brand, and a sky map no taller than the space between them. */
@media (max-height: 500px) and (max-width: 1000px) and (pointer: coarse) {
  :root { --tabbar-h: 46px; --timebar-h: 46px; }
  html[data-theme] .topbar { grid-template-columns: auto minmax(0, 1fr) auto; }
  .ctx-summary { grid-column: 2; grid-row: 1; }
  .topbar-right { grid-column: 3; }
  html[data-theme] .tabs a { flex-direction: row; gap: 8px; font-size: 13px; }
  .sky-canvas-box { max-width: calc(100dvh - var(--tabbar-h) - var(--timebar-h) - 16px); margin-inline: auto; }
}

/* ---------- desktop layout ----------
   Header: the control groups wrap as whole groups, never squeezed into two
   rows each; the time slider, the control used most, takes the free width
   (a 13-hour night on 120 px was about 7 minutes per pixel); the moon summary
   stays on one line instead of breaking inside a time. */
@media (min-width: 1001px), (min-width: 901px) and (min-height: 501px) {
  html[data-theme] .planner-controls { flex-wrap: wrap; }
  html[data-theme] .context-controls { flex: 0 1 auto; flex-wrap: wrap; min-width: 0; }
  html[data-theme] .time-controls { flex: 1 1 460px; flex-wrap: wrap; min-width: 0; }
  html[data-theme] .time-controls .scrub { flex: 1 1 auto; min-width: 0; }
  html[data-theme] .time-controls .scrub input[type="range"] { flex: 1 1 auto; width: auto; min-width: 140px; max-width: 520px; }
  html[data-theme] .nightinfo {
    flex: 0 0 auto; max-width: none; overflow: visible; padding: 0; border: 0;
    background: none; font-size: 12px; white-space: nowrap;
  }
  /* Tonight reads as a list: on wide screens it keeps a reading width, so a
     target's numbers stay near its name instead of 800 px away. */
  html[data-theme] :is(.night-brief, .tonight-ranked) { max-width: 1080px; }
  /* short views (an empty Horizon) keep the footer at the bottom of the window */
  html[data-theme] main { min-height: calc(100dvh - 260px); }
  #tonight-rank-table th:nth-child(1) { width: 56px; }
  #tonight-rank-table th:nth-child(3), #tonight-rank-table th:nth-child(4) { width: 130px; }
  #tonight-rank-table th:nth-child(5) { width: 230px; }
  /* Docked details: the photo sits above the facts, so the facts get the
     rail's full width and values never break inside a word. */
  #modal.detail-docked .detail-hero { grid-template-columns: minmax(0, 1fr); }
  #modal.detail-docked .objimg { height: 150px; }
  #modal.detail-docked .objimg-ph { height: auto; min-height: 0; padding: 6px 8px; font-size: 12px; }
  #modal.detail-docked :is(.detail-hero-facts, .detail-visibility-facts) { grid-template-columns: 112px minmax(0, 1fr); font-size: 12px; }
}
/* Empty Horizon editor: the start actions sit in the stage, as the call to
   action, not only in the narrow list rail. */
/* one shared width, so the label used as a button matches its siblings */
html[data-theme] .hz-new.hz-start { display: grid; grid-template-columns: repeat(auto-fill, minmax(190px, 220px)); gap: 10px; margin-top: 18px; }
html[data-theme] .hz-start .btn { display: grid; place-items: center; min-height: 44px; padding: 0 16px; border: 1px solid var(--line); border-radius: 6px; }
html[data-theme] .hz-start .btn.primary { border-color: var(--accent); }
html[data-theme] .tonight-ranked .sub a { color: var(--accent); }
/* Sky View rail without an open target: what the selected time offers. */
.sky-now { margin-top: 14px; padding-top: 12px; border-top: 1px solid var(--line-soft); }
.sky-now h3 { margin: 0 0 4px; font-size: 13px; color: var(--txt); }
.sky-now h4 { margin: 12px 0 4px; color: var(--muted); font-size: 11px; font-weight: 600; letter-spacing: .06em; text-transform: uppercase; }
.sky-now-list { list-style: none; margin: 0; padding: 0; }
.sky-now-list li { border-bottom: 1px solid var(--line-soft); }
.sky-now-list .pick-target { justify-content: space-between; min-height: 36px; padding: 4px 0; }
.sky-now-list .pick-target:hover { color: var(--accent); }
/* Very wide screens, no inspector open: the night brief becomes a column
   beside the ranked list, so the list starts at the top of the page and the
   width beside the reading column is used. */
@media (min-width: 1600px) {
  html[data-theme] body[data-primary-view="tonight"]:not(.detail-open) #view:has(> .night-brief) {
    display: grid; grid-template-columns: minmax(0, 1080px) minmax(280px, 360px);
    column-gap: 48px; justify-content: start; align-items: start;
  }
  body[data-primary-view="tonight"]:not(.detail-open) #view > .tonight-ranked { grid-column: 1; grid-row: 1; }
  body[data-primary-view="tonight"]:not(.detail-open) #view > .tonight-footnote { grid-column: 1; }
  html[data-theme] body[data-primary-view="tonight"]:not(.detail-open) #view > .night-brief {
    grid-column: 2; grid-row: 1 / span 2; grid-template-columns: minmax(0, 1fr); gap: 14px;
    margin: 0; padding: 0 0 0 24px; border-bottom: 0; border-left: 1px solid var(--line-soft);
  }
  body[data-primary-view="tonight"]:not(.detail-open) .night-brief-facts { grid-template-columns: minmax(0, 1fr); gap: 12px; }
  body[data-primary-view="tonight"]:not(.detail-open) .night-brief-times { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
