:root {
  color-scheme: light dark;

  /* Page + surfaces */
  --bg-top: #f6f8fb;
  --bg-bottom: #e9eef6;
  --surface: #ffffff;
  --surface-raised: #f9fbff;
  --surface-muted: #edf1f7;
  --panel: #eef3fb;
  --bar: #dde5f2;
  --debug-bg: #e6edf8;

  /* Text */
  --text: #1f2a3a;
  --muted: #5e6a7f;
  --disabled-text: #7d889a;

  /* Borders */
  --border: #c7cfdb;
  --border-soft: #d6dfeb;
  --disabled-border: #c4cbd8;

  /* Accent */
  --accent: #0d5ea8;
  --accent-strong: #20598d;

  /* Controls (buttons / links) */
  --control-top: #f9fcff;
  --control-bottom: #dce6f4;
  --control-border: #9aa8bf;
  --control-disabled-top: #eef2f8;
  --control-disabled-bottom: #dee5f0;
  --control-active-top: #fefefe;
  --control-active-bottom: #cfe3fb;

  /* Table */
  --table-header: #e3ebf8;
  --selected-bg: #dcecff;
  --focus-bg: #f2f8ff;

  /* Settings / info */
  --info-bg: #eef5fe;
  --info-text: #274466;
  --section-header: #edf3fc;

  /* Warning (amber / orange) */
  --warn-border: #d1a862;
  --warn-bg-top: #fff7e8;
  --warn-bg-bottom: #f6e4bf;
  --warn-text: #5b3810;
  --warn-bg: #fff4e8;
  --warn-border-2: #d97b2f;
  --warn-text-2: #61330f;
  --warn-link: #7b3f14;
  --warn-btn-top: #fff4df;
  --warn-btn-bottom: #f6d7ab;
  --warn-btn-border: #965200;

  /* Error (red) */
  --error-border: #c44a4a;
  --error-bg: #fff1f1;
  --error-bg-strong: #ffdede;
  --error-text: #982b2b;

  /* Pass (green) */
  --ok-text: #1c7c3f;

  /* Shadows / overlays */
  --shadow-color: rgba(20, 37, 61, 0.12);
  --overlay: rgba(12, 23, 40, 0.45);
}

@media (prefers-color-scheme: dark) {
  :root {
    /* Page + surfaces */
    --bg-top: #121821;
    --bg-bottom: #0d1219;
    --surface: #1a212c;
    --surface-raised: #212a37;
    --surface-muted: #161c25;
    --panel: #161d28;
    --bar: #1b2532;
    --debug-bg: #141b25;

    /* Text */
    --text: #e7ecf3;
    --muted: #9aa6b8;
    --disabled-text: #6b7787;

    /* Borders */
    --border: #2d3848;
    --border-soft: #283143;
    --disabled-border: #333d4d;

    /* Accent */
    --accent: #4c9be8;
    --accent-strong: #74b2ef;

    /* Controls (buttons / links) */
    --control-top: #2a3543;
    --control-bottom: #222c39;
    --control-border: #3a4555;
    --control-disabled-top: #1c232e;
    --control-disabled-bottom: #181e27;
    --control-active-top: #284460;
    --control-active-bottom: #1f3650;

    /* Table */
    --table-header: #222e3d;
    --selected-bg: #234061;
    --focus-bg: #243549;

    /* Settings / info */
    --info-bg: #182636;
    --info-text: #a9cbf0;
    --section-header: #1e2937;

    /* Warning (amber / orange) */
    --warn-border: #8a6a2e;
    --warn-bg-top: #2a2113;
    --warn-bg-bottom: #221a0f;
    --warn-text: #e8c98a;
    --warn-bg: #2a2012;
    --warn-border-2: #9a5a28;
    --warn-text-2: #e6b483;
    --warn-link: #e0a26a;
    --warn-btn-top: #3a2b12;
    --warn-btn-bottom: #2e2210;
    --warn-btn-border: #8a5a1e;

    /* Error (red) */
    --error-border: #c0564f;
    --error-bg: #2e1719;
    --error-bg-strong: #3a1c1f;
    --error-text: #f0a0a0;

    /* Pass (green) */
    --ok-text: #7fd6a0;

    /* Shadows / overlays */
    --shadow-color: rgba(0, 0, 0, 0.5);
    --overlay: rgba(0, 0, 0, 0.62);
  }
}

* {
  box-sizing: border-box;
}

/* Form controls do not inherit font-family from an ancestor — without this
   they fall back to the user agent's own default, which is Arial on macOS but
   not everywhere, so the app's buttons, dropdowns and grid cells drifted away
   from the body font by platform. Only the family is inherited: the `font`
   shorthand would also pull in the body font-size and grow every control from
   the UA's ~13px to 16px. #debug-output overrides the family with its
   monospace stack; nothing else should. */
button,
input,
select,
textarea {
  font-family: inherit;
}

body {
  margin: 0;
  background: linear-gradient(180deg, var(--bg-top) 0%, var(--bg-bottom) 100%);
  color: var(--text);
  font-family: Arial, Helvetica, sans-serif;
  height: 100vh;
  height: 100dvh;
  overflow: hidden;
}

.about-page {
  min-height: 100vh;
  height: auto;
  overflow: auto;
  background:
    radial-gradient(circle at top right, rgba(13, 94, 168, 0.16), transparent 45%),
    linear-gradient(180deg, var(--bg-top) 0%, var(--bg-bottom) 100%);
}

.about-shell {
  max-width: 860px;
  margin: 2.2rem auto;
  padding: 0 1rem 2rem;
}

.about-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 12px;
  box-shadow: 0 14px 28px var(--shadow-color);
  padding: 1.5rem 1.6rem;
  line-height: 1.6;
}

.about-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.8rem;
  margin-bottom: 0.9rem;
}

.about-header h1 {
  margin: 0;
  font-size: 1.35rem;
}

.about-signoff {
  margin-top: 1.1rem;
  font-weight: 600;
}

/* Adapter loopback diagnostics (serial-test.html), which reuses the about-page
   shell above for its card and layout. */

.loopback-caveat {
  color: var(--muted);
  font-size: 0.87rem;
}

.loopback-unsupported {
  border: 1px solid var(--warn-border);
  background: linear-gradient(180deg, var(--warn-bg-top) 0%, var(--warn-bg-bottom) 100%);
  border-radius: 6px;
  padding: 0.6rem 0.7rem;
  margin-bottom: 0.9rem;
  font-size: 0.87rem;
}

.loopback-unsupported[hidden] {
  display: none;
}

.loopback-controls {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 0.9rem;
  margin: 1.1rem 0 0.6rem;
  padding: 0.85rem;
  background: var(--surface-raised);
  border: 1px solid var(--border-soft);
  border-radius: 8px;
}

.loopback-field {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  font-size: 0.85rem;
}

.loopback-bauds {
  flex-direction: row;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.6rem;
  border: 1px solid var(--border-soft);
  border-radius: 6px;
  padding: 0.35rem 0.6rem 0.5rem;
  margin: 0;
}

.loopback-bauds legend {
  padding: 0 0.3rem;
  color: var(--muted);
  font-size: 0.78rem;
}

.loopback-bauds label,
.loopback-check {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  font-size: 0.85rem;
}

.loopback-buttons {
  display: flex;
  gap: 0.5rem;
  margin-left: auto;
}

.loopback-adapter {
  margin: 0.4rem 0 0;
  font-size: 0.85rem;
  font-weight: 600;
}

.loopback-status {
  margin: 0.35rem 0 0;
  font-size: 0.85rem;
  color: var(--muted);
}

.loopback-status[hidden] {
  display: none;
}

.loopback-results {
  width: 100%;
  border-collapse: collapse;
  margin-top: 0.9rem;
  font-size: 0.8rem;
}

.loopback-results[hidden] {
  display: none;
}

.loopback-results th {
  background: var(--table-header);
  border: 1px solid var(--border);
  padding: 0.35rem 0.5rem;
  text-align: left;
}

.loopback-results td {
  border: 1px solid var(--border-soft);
  padding: 0.3rem 0.5rem;
  vertical-align: top;
}

.loopback-mark {
  font-weight: 700;
  white-space: nowrap;
}

.loopback-row.is-pass .loopback-mark {
  color: var(--ok-text);
}

.loopback-row.is-fail .loopback-mark {
  color: var(--error-text);
}

.loopback-row.is-skip .loopback-mark {
  color: var(--muted);
}

.loopback-baud {
  white-space: nowrap;
  text-align: right;
}

.loopback-detail {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.74rem;
  word-break: break-word;
}

.loopback-report-wrap[hidden] {
  display: none;
}

.loopback-report-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.8rem;
  margin-top: 1.1rem;
}

.loopback-report-header h2 {
  margin: 0;
  font-size: 1rem;
}

.loopback-report-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}

.loopback-report {
  margin: 0.5rem 0 0;
  padding: 0.6rem;
  background: var(--debug-bg);
  border: 1px solid var(--border);
  border-radius: 6px;
  font-size: 0.74rem;
  line-height: 1.45;
  white-space: pre-wrap;
  word-break: break-word;
  max-height: 320px;
  overflow: auto;
}

.app-shell {
  height: 100vh;
  height: 100dvh;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.toolbar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  border-bottom: 1px solid var(--border);
  background: var(--bar);
  padding: 0.8rem 1rem;
}

.toolbar-title {
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
}

.toolbar h1 {
  margin: 0;
  font-size: 1.1rem;
}

.version-info {
  margin: 0;
  font-size: 0.7rem;
  color: var(--muted);
}

.version-info a {
  color: inherit;
  text-decoration: underline;
}

.version-info a:hover {
  color: var(--accent);
}

.toolbar-actions {
  display: flex;
  gap: 0.6rem;
}

button {
  border: 1px solid var(--control-border);
  background: linear-gradient(180deg, var(--control-top) 0%, var(--control-bottom) 100%);
  color: var(--text);
  padding: 0.45rem 0.75rem;
  border-radius: 4px;
  cursor: pointer;
}

button:not(:disabled):hover {
  border-color: var(--accent);
}

/* Only scoped disabled styles existed, so a disabled button outside those
   scopes looked identical to a live one — it read as broken rather than as
   not-yet-available. */
button:disabled {
  background: linear-gradient(180deg, var(--control-disabled-top) 0%, var(--control-disabled-bottom) 100%);
  border-color: var(--disabled-border);
  color: var(--disabled-text);
  cursor: default;
}

.toolbar-link {
  display: inline-flex;
  align-items: center;
  border: 1px solid var(--control-border);
  background: linear-gradient(180deg, var(--control-top) 0%, var(--control-bottom) 100%);
  color: var(--text);
  padding: 0.45rem 0.75rem;
  border-radius: 4px;
  text-decoration: none;
  font-size: 0.85rem;
}

.toolbar-link:hover {
  border-color: var(--accent);
}

.facebook-link {
  gap: 0.4rem;
}

.facebook-logo {
  width: 1rem;
  height: 1rem;
  flex: 0 0 auto;
}

.main-layout {
  display: grid;
  grid-template-columns: 280px 1fr;
  flex: 1;
  min-height: 0;
  overflow: hidden;
}

.left-panel {
  border-right: 1px solid var(--border);
  background: var(--panel);
  padding: 1rem;
  display: flex;
  flex-direction: column;
  min-height: 0;
}

.left-panel-main {
  flex: 0 0 auto;
}

.left-panel h2 {
  margin-top: 0;
  font-size: 1rem;
}

/* Serial Bridge is a <details>: a static heading on desktop, a collapsible
   disclosure on mobile (the mobile breakpoint re-enables the toggle/marker). */
.left-panel-summary {
  margin: 0 0 0.6rem;
  font-size: 1rem;
  font-weight: 700;
  list-style: none;
  pointer-events: none;
}

.left-panel-summary::-webkit-details-marker {
  display: none;
}

.sidebar-warning-panel {
  margin: 0.2rem 0 0.9rem;
  padding: 0.75rem 0.8rem;
  border: 1px solid var(--warn-border);
  border-radius: 8px;
  background: linear-gradient(180deg, var(--warn-bg-top) 0%, var(--warn-bg-bottom) 100%);
  color: var(--warn-text);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.35);
  flex-shrink: 0;
}

.sidebar-warning-panel strong {
  display: block;
  margin-bottom: 0.35rem;
  font-size: 0.78rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.sidebar-warning-panel p {
  margin: 0;
  font-size: 0.82rem;
  line-height: 1.45;
}

.serial-support-warning {
  margin: 0.35rem 0 0.8rem;
  padding: 0.55rem 0.6rem;
  border: 1px solid var(--warn-border-2);
  border-radius: 6px;
  background: var(--warn-bg);
  color: var(--warn-text-2);
  font-size: 0.82rem;
  line-height: 1.35;
}

.serial-support-warning a {
  color: var(--warn-link);
  font-weight: 600;
}

.serial-support-warning[hidden] {
  display: none;
}

#radio-search,
#radio-make,
#radio-model {
  width: 100%;
  margin: 0.2rem 0 0.55rem;
  padding: 0.4rem 0.45rem;
  border: 1px solid var(--border);
  border-radius: 4px;
  background: var(--surface);
  color: var(--text);
}

.radio-search-wrap {
  position: relative;
}

.radio-search-results {
  position: absolute;
  top: calc(100% - 0.45rem);
  left: 0;
  right: 0;
  z-index: 40;
  max-height: 16rem;
  overflow-y: auto;
  margin: 0;
  padding: 0.2rem 0;
  list-style: none;
  border: 1px solid var(--border);
  border-radius: 4px;
  background: var(--surface);
  box-shadow: 0 6px 16px rgba(0, 0, 0, 0.18);
}

.radio-search-results[hidden] {
  display: none;
}

.radio-search-results li {
  padding: 0.32rem 0.5rem;
  font-size: 0.85rem;
  color: var(--text);
  cursor: pointer;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.radio-search-results li:hover,
.radio-search-results li.is-active {
  background: var(--selected-bg);
}

.radio-search-results li.radio-search-empty,
.radio-search-results li.radio-search-more {
  color: var(--muted);
  cursor: default;
  font-style: italic;
}

.radio-search-results li.radio-search-empty:hover,
.radio-search-results li.radio-search-more:hover {
  background: transparent;
}

.left-panel button:disabled,
.left-panel input:disabled,
.left-panel select:disabled {
  color: var(--disabled-text);
  border-color: var(--disabled-border);
  background: linear-gradient(180deg, var(--control-disabled-top) 0%, var(--control-disabled-bottom) 100%);
  cursor: not-allowed;
}

.serial-actions {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0.5rem;
  margin: 0.3rem 0 0.6rem;
}

.serial-actions > :only-child {
  grid-column: 1 / -1;
}

.clone-progress {
  margin: 0.1rem 0 0.6rem;
}

.clone-progress-text {
  display: flex;
  justify-content: space-between;
  gap: 0.5rem;
  margin-bottom: 0.25rem;
  font-size: 0.8rem;
  color: var(--muted);
}

.clone-progress progress {
  display: block;
  width: 100%;
  height: 0.6rem;
  accent-color: var(--accent);
}

/* App-wide progress strip, rendered as the first row inside the Debug Output
   panel. It deliberately carries no border or background of its own: the panel
   already supplies both, and a second rule here would read as a divider
   splitting the panel in two. */
.app-progress {
  margin-bottom: 0.6rem;
}

.app-progress[hidden] {
  display: none;
}

.app-progress-text {
  display: flex;
  justify-content: space-between;
  gap: 0.5rem;
  margin-bottom: 0.3rem;
  font-size: 0.8rem;
  color: var(--muted);
}

.app-progress-label {
  color: var(--text);
}

.app-progress progress {
  display: block;
  width: 100%;
  height: 0.6rem;
  accent-color: var(--accent);
}

.serial-log {
  margin: 0.6rem 0 0;
  min-height: 92px;
  max-height: 180px;
  overflow: auto;
  background: var(--surface-raised);
  border: 1px solid var(--border);
  padding: 0.45rem;
  font-size: 0.74rem;
  line-height: 1.4;
}

.editor-panel {
  padding: 1rem;
  min-height: 0;
  overflow: hidden;
  display: flex;
  flex-direction: column;
}

.editor-view-toggle {
  display: inline-flex;
  gap: 0.3rem;
  margin-bottom: 0.75rem;
}

.editor-view-toggle button {
  min-width: 8.5rem;
}

.editor-view-toggle button:disabled {
  color: var(--disabled-text);
  border-color: var(--disabled-border);
  background: linear-gradient(180deg, var(--control-disabled-top) 0%, var(--control-disabled-bottom) 100%);
  box-shadow: none;
  cursor: not-allowed;
}

.editor-view-toggle button.is-active {
  border-color: var(--accent-strong);
  background: linear-gradient(180deg, var(--control-active-top) 0%, var(--control-active-bottom) 100%);
  box-shadow: inset 0 0 0 1px rgba(32, 89, 141, 0.1);
}

.editor-view {
  min-height: 0;
  flex: 1 1 auto;
  display: none;
  flex-direction: column;
}

.editor-view.is-active {
  display: flex;
}

.channel-toolbar {
  display: flex;
  align-items: center;
  gap: 0.45rem;
  margin-bottom: 0.6rem;
  flex: 0 0 auto;
  position: relative;
}

/* Uniform height for all toolbar buttons (+, -, up, down, Actions). */
.channel-toolbar > button,
#channel-menu-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 2.3rem;
  padding: 0.3rem 0.5rem;
  line-height: 1;
}

/* The icon buttons are squares matching the toolbar height. */
.channel-toolbar > button {
  width: 2.3rem;
  padding: 0;
}

/* Holds the grid and the empty-state notice, only one of which is ever shown. */
.channel-grid {
  min-height: 0;
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
}

.mem-table-scroll {
  min-height: 0;
  overflow: auto;
  flex: 1 1 auto;
}

.channel-empty-state {
  min-height: 0;
  flex: 1 1 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1.5rem;
}

.channel-empty-state[hidden] {
  display: none;
}

.channel-empty-card {
  max-width: 34rem;
  padding: 1.6rem 1.9rem;
  text-align: center;
  color: var(--muted);
  background: var(--surface);
  border: 1px dashed var(--border);
  border-radius: 10px;
  box-shadow: 0 1px 2px var(--shadow-color);
}

.channel-empty-icon {
  display: block;
  font-size: 2rem;
  line-height: 1;
  margin-bottom: 0.7rem;
}

.channel-empty-card h2 {
  margin: 0 0 0.45rem;
  font-size: 1.05rem;
  color: var(--text);
}

.channel-empty-card p {
  margin: 0;
  font-size: 0.92rem;
  line-height: 1.5;
}

.channel-empty-card .channel-empty-hint {
  margin-top: 0.55rem;
  font-size: 0.83rem;
  opacity: 0.8;
}

.settings-layout {
  min-height: 0;
  flex: 1 1 auto;
  display: grid;
  grid-template-columns: 220px minmax(0, 1fr);
  gap: 0.8rem;
}

.settings-tabs {
  min-height: 0;
  overflow: auto;
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  padding-right: 0.2rem;
}

.settings-tab {
  width: 100%;
  text-align: left;
}

.settings-tab.is-active {
  border-color: var(--accent-strong);
  background: linear-gradient(180deg, var(--control-active-top) 0%, var(--control-active-bottom) 100%);
}

.settings-tab.has-invalid {
  border-color: var(--error-border);
  background: linear-gradient(180deg, var(--error-bg) 0%, var(--error-bg-strong) 100%);
}

.settings-panel {
  min-width: 0;
  min-height: 0;
  display: flex;
  flex-direction: column;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--surface);
  box-shadow: 0 10px 22px var(--shadow-color);
}

.settings-summary {
  border-bottom: 1px solid var(--border);
  background: var(--info-bg);
  color: var(--info-text);
  padding: 0.7rem 0.9rem;
  font-size: 0.84rem;
}

.settings-summary.has-invalid {
  background: var(--error-bg);
  color: var(--error-text);
}

.settings-empty {
  margin: auto;
  max-width: 36rem;
  padding: 1rem;
  color: var(--muted);
  text-align: center;
  line-height: 1.45;
}

.settings-content {
  min-height: 0;
  overflow: auto;
  padding: 0.9rem;
}

.settings-group {
  margin-bottom: 1rem;
  border: 1px solid var(--border-soft);
  border-radius: 8px;
  background: var(--surface-raised);
  overflow: hidden;
}

.settings-group > h3,
.settings-subgroup > h4 {
  margin: 0;
  padding: 0.65rem 0.8rem;
  background: var(--section-header);
  font-size: 0.88rem;
}

.settings-subgroup {
  border-top: 1px solid var(--border-soft);
}

.settings-fields {
  display: grid;
  grid-template-columns: minmax(180px, 240px) minmax(0, 1fr);
  gap: 0.45rem 0.8rem;
  align-items: start;
  padding: 0.8rem;
}

.settings-field-label {
  font-size: 0.84rem;
  line-height: 1.35;
  color: var(--text);
}

.settings-field-label strong {
  display: block;
  margin-bottom: 0.1rem;
  font-size: 0.86rem;
}

.settings-field-doc {
  color: var(--muted);
}

.settings-field-control {
  min-width: 0;
}

.settings-field-control input[type="text"],
.settings-field-control input[type="number"],
.settings-field-control select {
  width: 100%;
  border: 1px solid var(--border);
  border-radius: 4px;
  background: var(--surface);
  color: var(--text);
  padding: 0.45rem 0.55rem;
}

.settings-field-control input[type="checkbox"] {
  width: 1rem;
  height: 1rem;
  margin-top: 0.4rem;
}

.settings-field-control.is-invalid input,
.settings-field-control.is-invalid select {
  border-color: var(--error-border);
  background: var(--error-bg);
}

.settings-field-control.is-immutable input,
.settings-field-control.is-immutable select,
.settings-field-control.is-immutable label {
  color: var(--disabled-text);
}

.settings-field-control.is-immutable input,
.settings-field-control.is-immutable select {
  background: var(--surface-muted);
}

.settings-field-error {
  margin-top: 0.25rem;
  color: var(--error-text);
  font-size: 0.78rem;
  line-height: 1.3;
}

.settings-field-warning {
  margin-top: 0.25rem;
  color: var(--warn-text-2);
  font-size: 0.78rem;
  line-height: 1.3;
}

#channel-insert,
#channel-remove {
  min-width: 2.1rem;
  padding: 0.3rem 0.45rem;
  font-size: 1rem;
  line-height: 1;
}

.channel-menu {
  position: relative;
}

.channel-menu-popup {
  position: absolute;
  top: calc(100% + 0.25rem);
  left: 0;
  z-index: 20;
  min-width: 24rem;
  padding: 0.25rem;
  border: 1px solid var(--border);
  border-radius: 4px;
  background: var(--surface);
  box-shadow: 0 6px 16px var(--shadow-color);
}

.channel-menu-popup.hidden {
  display: none;
}

.channel-menu-popup button {
  width: 100%;
  text-align: left;
}

.channel-menu-popup .channel-menu-separator {
  border: none;
  border-top: 1px solid var(--border);
  margin: 0.25rem 0.2rem;
}

/* Drag-and-drop file loading (web/js/ui/codeplug-io.8954911190.js). The whole page is the
   drop target, so this only signals that a dragged file will be accepted.
   pointer-events stay off so the overlay appearing under the cursor cannot
   become the drag target and cancel the drag it is announcing. */
.drop-overlay {
  position: fixed;
  inset: 0;
  z-index: 80;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--overlay);
  padding: 1rem;
  pointer-events: none;
}

.drop-overlay.hidden {
  display: none;
}

.drop-overlay-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.3rem;
  border: 2px dashed var(--accent);
  border-radius: 10px;
  background: var(--surface);
  box-shadow: 0 16px 36px var(--shadow-color);
  padding: 1.4rem 2rem;
  text-align: center;
}

.drop-overlay-title {
  font-size: 1.05rem;
  font-weight: 600;
}

.drop-overlay-hint {
  font-size: 0.85rem;
  color: var(--muted);
}

.modal-overlay {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--overlay);
  padding: 1rem;
}

.modal-overlay.hidden {
  display: none;
}

.modal-card {
  width: min(560px, 100%);
  margin: 0;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--surface);
  box-shadow: 0 16px 36px var(--shadow-color);
  padding: 1rem;
}

.modal-card h2 {
  margin: 0 0 0.8rem;
  font-size: 1rem;
}

/*
  Browser-capability overlay. The grayscale lives on #app-shell (toggled
  together with the overlay) rather than on a backdrop-filter so it works in
  exactly the older browsers the overlay exists for. The filter creates a
  containing block, which is safe only because every fixed-position overlay is
  a sibling of #app-shell, not a descendant — keep it that way.
*/
.app-shell.browser-unsupported {
  filter: grayscale(1);
}

.unsupported-browser-overlay {
  /* Above the regular modals (60); below the drag-feedback overlay (80). */
  z-index: 70;
}

.unsupported-browser-card {
  /* A third of the screen, with floors so it stays readable on phones. */
  width: max(33vw, 340px);
  max-width: 92vw;
  min-height: 33vh;
  display: flex;
  flex-direction: column;
}

.unsupported-browser-card p {
  margin: 0 0 0.9rem;
  font-size: 0.9rem;
  line-height: 1.45;
}

.unsupported-browser-card a {
  color: var(--warn-link);
  font-weight: 600;
}

.unsupported-browser-card .modal-actions {
  margin-top: auto;
}

.import-choice-message {
  margin: 0 0 0.9rem;
  font-size: 0.9rem;
  line-height: 1.45;
}

.modal-grid {
  display: grid;
  grid-template-columns: 160px 1fr;
  gap: 0.45rem 0.7rem;
  align-items: center;
}

.modal-grid input[type="text"],
.modal-grid input[type="number"],
.modal-grid select {
  width: 100%;
  border: 1px solid var(--border);
  border-radius: 4px;
  background: var(--surface);
  color: var(--text);
  padding: 0.35rem 0.45rem;
}

.modal-grid input[type="checkbox"] {
  width: 1rem;
  height: 1rem;
  margin: 0;
}

/* The query modal stacks two multi-row checkbox lists, which the shared
   0.45rem row gap runs together into one block — Band and Mode need to read as
   separate groups. */
#repeater-query-modal .modal-grid {
  row-gap: 1.1rem;
}

/* A value the modal reports rather than asks for: the fixed RSGB country.
   Styled to read as text, not as a disabled input the user might try to
   edit. */
.modal-fixed-value {
  font-size: 0.9rem;
  color: var(--muted);
}

.modal-geo-row {
  display: grid;
  grid-template-columns: 1fr auto auto;
  gap: 0.4rem;
  align-items: center;
}

.modal-geo-button {
  min-width: 2rem;
  padding: 0.35rem 0.45rem;
  line-height: 1;
}

.modal-modes {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(130px, 1fr));
  gap: 0.35rem 0.55rem;
}

.modal-mode-option {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  font-size: 0.85rem;
}

.modal-actions {
  margin-top: 0.9rem;
  display: flex;
  justify-content: flex-end;
  gap: 0.5rem;
}

.debug-output-panel {
  border-top: 1px solid var(--border);
  background: var(--debug-bg);
  padding: 0.7rem 0.9rem 0.9rem;
}

.debug-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
}

.debug-actions {
  display: inline-flex;
  gap: 0.5rem;
}

.debug-actions[hidden],
.debug-output-content[hidden] {
  display: none;
}

.debug-header h2 {
  flex: 1;
  margin: 0;
  font-size: 0.9rem;
}

.debug-toggle {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  width: 100%;
  border: 0;
  background: none;
  color: inherit;
  padding: 0.15rem 0;
  font: inherit;
  text-align: left;
}

.debug-toggle:not(:disabled):hover {
  color: var(--accent);
}

.debug-toggle-icon {
  display: inline-block;
  font-size: 1rem;
  line-height: 1;
  transition: transform 120ms ease;
}

.debug-toggle[aria-expanded="true"] .debug-toggle-icon {
  transform: rotate(90deg);
}

.debug-output-content {
  margin-top: 0.4rem;
}

#report-issue {
  border-color: var(--warn-btn-border);
  background: linear-gradient(180deg, var(--warn-btn-top) 0%, var(--warn-btn-bottom) 100%);
}

#debug-output {
  width: 100%;
  min-height: 180px;
  resize: vertical;
  border: 1px solid var(--border);
  background: var(--surface-raised);
  color: var(--text);
  padding: 0.5rem;
  font-size: 0.78rem;
  line-height: 1.35;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}

/* Let the table take its natural width so all 17 column headers stay
   readable; it scrolls horizontally inside .mem-table-scroll when the
   window is narrower (previously table-layout: fixed compressed every
   column to fit, overlapping the header text). */
#mem-table {
  width: max-content;
  min-width: 100%;
  border-collapse: collapse;
  background: var(--surface);
  border: 1px solid var(--border);
}

#mem-table th,
#mem-table td {
  border: 1px solid var(--border);
  padding: 0.35rem;
  font-size: 0.85rem;
  white-space: nowrap;
}

#mem-table th {
  background: var(--table-header);
  text-align: left;
}

#mem-table td input {
  width: 100%;
  border: none;
  background: transparent;
  color: var(--text);
  font-size: 0.85rem;
}

#mem-table td select {
  width: 100%;
  border: none;
  background: transparent;
  color: var(--text);
  font-size: 0.85rem;
}

/* Read-only columns for the selected radio: grey text (cells and header)
   instead of the browser's default disabled rendering, with a title tooltip
   set in createCellEditor/renderTable. */
#mem-table td .readonly-cell,
#mem-table th.readonly-cell {
  color: var(--muted);
  -webkit-text-fill-color: var(--muted);
  opacity: 1;
}

/* With natural table sizing, editors set the column width floor; keep the
   auto-indexed Location column compact. */
#mem-table td input,
#mem-table td select {
  min-width: 6rem;
}

#mem-table td:first-child,
#mem-table th:first-child {
  min-width: 2.75rem;
}

#mem-table td:first-child input,
#mem-table td:first-child select,
#mem-table .channel-location-button {
  min-width: 2.75rem;
}

#mem-table .channel-location-button {
  width: 100%;
  border: none;
  border-radius: 0;
  padding: 0;
  background: transparent;
  color: var(--text);
  font-size: 0.85rem;
  text-align: left;
  cursor: pointer;
}

#mem-table .channel-location-button:hover {
  color: var(--accent-strong);
  text-decoration: underline;
}

#mem-table .channel-location-button:focus-visible {
  outline: 1px solid var(--accent);
  background: var(--focus-bg);
}

/* Static OSM context map for imported repeater channels (issue #57): rows
   with coordinates mark their Location cell, hover shows the tooltip map on
   desktop, tap opens the modal map on touch devices (ui/repeater-map.js). */
#mem-table .channel-location-button.has-geo {
  text-decoration: underline dotted;
  text-underline-offset: 2px;
}

.repeater-map-tooltip {
  position: fixed;
  z-index: 70;
  /* Matches the sidebar's 280px column (issue #57: "no bigger than"). */
  width: 280px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--surface);
  box-shadow: 0 16px 36px var(--shadow-color);
  overflow: hidden;
  /* Hoverable on purpose: the attribution link at its foot has to be
     clickable, so repeater-map.js keeps the tooltip up while the pointer is
     inside it rather than hiding on the cell's mouseout. */
}

.repeater-map-tooltip.hidden {
  display: none;
}

.repeater-map-coords {
  display: block;
  padding: 0.4rem 0.5rem;
  text-align: center;
  font-size: 0.85rem;
  font-variant-numeric: tabular-nums;
  color: var(--text);
}

.repeater-map-canvas {
  position: relative;
  overflow: hidden;
  background: var(--border);
}

.repeater-map-tile {
  position: absolute;
  width: 256px;
  height: 256px;
  max-width: none;
  user-select: none;
}

.repeater-map-marker {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 12px;
  height: 12px;
  transform: translate(-50%, -50%);
  border-radius: 50%;
  background: #e01b24;
  border: 2px solid #fff;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.5);
}

/* Attribution strip along the bottom of the widget, below the map: the OSM
   tile policy wants the credit visible on every map and reachable through to
   the licence, which the link inside it provides. */
.repeater-map-attribution {
  padding: 3px 6px;
  border-top: 1px solid var(--border);
  text-align: right;
  font-size: 0.65rem;
  line-height: 1.3;
  color: var(--muted);
}

.repeater-map-attribution a {
  color: inherit;
}

.repeater-map-card {
  width: min(90vw, 340px);
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--surface);
  box-shadow: 0 16px 36px var(--shadow-color);
  overflow: hidden;
}

.repeater-map-header {
  position: relative;
}

.repeater-map-header .repeater-map-coords {
  /* Keep the coordinates centered on the card, clear of the close button. */
  padding-left: 2rem;
  padding-right: 2rem;
}

.repeater-map-close {
  position: absolute;
  top: 50%;
  right: 0.35rem;
  transform: translateY(-50%);
  border: none;
  background: transparent;
  color: var(--text);
  font-size: 1rem;
  line-height: 1;
  padding: 0.3rem 0.45rem;
  cursor: pointer;
}

/* Square map before the script sizes it in pixels, so the first open can
   measure a laid-out width. */
.repeater-map-card .repeater-map-canvas {
  width: 100%;
  aspect-ratio: 1 / 1;
}

/* Stand-ins for the rows the grid keeps out of the DOM (see channel-table.js):
   pure height, no box of their own. */
#mem-table tbody tr.mem-row-spacer td {
  padding: 0;
  border: 0;
  font-size: 0;
  line-height: 0;
}

#mem-table tbody tr.is-selected td {
  background: var(--selected-bg);
}

#mem-table td.is-invalid {
  background: var(--error-bg);
}

#mem-table td input:focus {
  outline: 1px solid var(--accent);
  background: var(--focus-bg);
}

#mem-table td select:focus {
  outline: 1px solid var(--accent);
  background: var(--focus-bg);
}

@media (max-width: 900px) {
  /* Let the page flow and scroll vertically instead of locking to the viewport,
     so the stacked panels are all reachable on a phone. */
  body {
    height: auto;
    min-height: 100dvh;
    overflow: auto;
  }

  .app-shell {
    height: auto;
    min-height: 100dvh;
    overflow: visible;
  }

  .toolbar {
    flex-wrap: wrap;
    gap: 0.5rem;
  }

  .toolbar-actions {
    flex-wrap: wrap;
  }

  /* Stack sidebar above the editor; let both size to content and the page scroll. */
  .main-layout {
    display: block;
    overflow: visible;
  }

  .left-panel {
    display: block;
    border-right: none;
    border-bottom: 1px solid var(--border);
  }

  .editor-panel {
    display: block;
    overflow: visible;
  }

  .editor-view.is-active {
    display: block;
  }

  /* Bound the wide channel table so it scrolls internally while the page can
     still scroll past it to the debug panel. */
  .mem-table-scroll {
    max-height: 60dvh;
    -webkit-overflow-scrolling: touch;
  }

  /* Serial Bridge disclosure becomes collapsible on mobile so the channel list
     isn't pushed down the page. */
  .left-panel-summary {
    pointer-events: auto;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
    margin-bottom: 0.4rem;
    min-height: 2.75rem;
  }

  .left-panel-summary::after {
    content: "\25BE";
    color: var(--muted);
  }

  .serial-bridge:not([open]) .left-panel-summary::after {
    content: "\25B8";
  }

  /* The natural-width, horizontally-scrolling table now applies at all
     viewports (see the base #mem-table rules); mobile only adds taller,
     tappable cell editors. */
  #mem-table td input,
  #mem-table td select {
    min-height: 2.25rem;
  }

  /* Comfortable touch targets for primary controls (table cells excluded). */
  .toolbar-actions button,
  .toolbar-link,
  .editor-view-toggle button,
  .left-panel button,
  .left-panel select,
  .serial-actions button,
  .channel-toolbar > button,
  #channel-menu-toggle,
  .channel-menu-popup button,
  .modal-actions button,
  .debug-actions button {
    min-height: 2.75rem;
  }

  /* Keep the icon buttons square at the larger touch-target height. */
  .channel-toolbar > button {
    min-width: 2.75rem;
  }

  /* The actions popup is fixed-width on desktop; keep it on-screen on phones. */
  .channel-menu-popup {
    min-width: 0;
    width: max-content;
    max-width: calc(100vw - 2rem);
  }

  #debug-output {
    min-height: 120px;
  }

  .modal-grid {
    grid-template-columns: 1fr;
  }

  .settings-layout {
    grid-template-columns: 1fr;
  }

  .settings-tabs {
    flex-direction: row;
    overflow: auto;
    padding-right: 0;
    padding-bottom: 0.2rem;
  }

  .settings-tab {
    width: auto;
    white-space: nowrap;
  }

  .settings-fields {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 560px) {
  /* Single-column serial actions and full-width view toggle on narrow phones. */
  .serial-actions {
    grid-template-columns: 1fr;
  }

  .editor-view-toggle {
    display: flex;
  }

  .editor-view-toggle button {
    flex: 1 1 0;
    min-width: 0;
  }

  .toolbar h1 {
    flex: 1 1 100%;
  }
}

/* Custom tooltip bubble (web/js/tooltip.87e6a49023.js): replaces native title tooltips
   so every tooltip appears after the same 400ms delay. Sits above modals. */
.app-tooltip {
  position: fixed;
  z-index: 100;
  max-width: 320px;
  padding: 4px 8px;
  border: 1px solid var(--border);
  border-radius: 4px;
  background: var(--surface);
  color: var(--text);
  font-size: 0.78rem;
  line-height: 1.35;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.18);
  pointer-events: none;
  white-space: pre-line;
}
