/* RF Tools - styles.
 *
 * Same dark palette as the gallery so the site hangs together, but the
 * typography is deliberately plain: an 8x8 pixel font is for the header, not
 * for numbers and units you have to read carefully.
 *
 * Two things here exist only because of iOS in standalone mode:
 *   - inputs are 16px, because Safari zooms the page when you focus a field
 *     smaller than that and never zooms back out;
 *   - the safe-area insets, because a pinned app draws under the notch and
 *     the home indicator.
 */

:root {
  --bg: #0e1014;
  --panel: #161920;
  --panel-2: #1b1f28;
  --line: #262b35;
  --text: #e8eaef;
  --muted: #939aa8;
  --accent: #5b9dff;
  --good: #57c98a;
  --warn: #e0a75c;
  --dim: #8e97a8;          /* quietest text; must clear 4.5:1 at 12px */
  --grid: #262b35;
  --grid-major: #333a48;
}

/*
 * Three theme states, and the order matters. Bare :root is the dark palette,
 * because that is what the rest of the site is. The media query supplies light
 * only when no explicit choice has been stored, and the [data-theme] rules
 * override the media query in both directions so the toggle always wins.
 */
@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) {
    --bg: #f6f7f9;
    --panel: #ffffff;
    --panel-2: #eef1f5;
    --line: #d7dbe3;
    --text: #14171c;
    --muted: #565e6b;
    --accent: #1f60d0;
    --good: #17794c;
    --warn: #8a5300;
    --dim: #59616d;
    --grid: #dfe3ea;
    --grid-major: #c6ccd6;
  }
}

:root[data-theme="light"] {
  --bg: #f6f7f9;
  --panel: #ffffff;
  --panel-2: #eef1f5;
  --line: #d7dbe3;
  --text: #14171c;
  --muted: #565e6b;
  --accent: #1f60d0;
  --good: #17794c;
  --warn: #8a5300;
  --dim: #59616d;
  --grid: #dfe3ea;
  --grid-major: #c6ccd6;
}

:root[data-theme="dark"] {
  --bg: #0e1014;
  --panel: #161920;
  --panel-2: #1b1f28;
  --line: #262b35;
  --text: #e8eaef;
  --muted: #939aa8;
  --accent: #5b9dff;
  --good: #57c98a;
  --warn: #e0a75c;
  --dim: #8e97a8;
  --grid: #262b35;
  --grid-major: #333a48;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  background: var(--bg);
  color: var(--text);
  font: 15px/1.45 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
        "Helvetica Neue", Arial, sans-serif;
  -webkit-text-size-adjust: 100%;
}

body {
  padding: max(12px, env(safe-area-inset-top)) max(12px, env(safe-area-inset-right))
           max(20px, env(safe-area-inset-bottom)) max(12px, env(safe-area-inset-left));
  max-width: 780px;
  margin: 0 auto;
}

a { color: var(--accent); }

/* ------------------------------------------------------------------ header */

.top { padding: 6px 2px 4px; }

h1 {
  margin: 0;
  font-size: 22px;
  font-weight: 600;
  display: flex;
  align-items: baseline;
  gap: .34em;
}

/* The pixel font must sit on a whole multiple of its 8px grid or the stems
   land on half pixels; the negative margin drops the glyph's blank baseline
   row so it lines up with ordinary text beside it. */
.msx-svg {
  --msx-h: 24px;
  display: block;
  height: var(--msx-h);
  width: auto;
  margin-bottom: calc(var(--msx-h) / -8);
  shape-rendering: crispEdges;
}

h1 .msx-on { display: inline-block; }

.sub {
  margin: 2px 0 12px;
  color: var(--muted);
  font-size: 13px;
}

.filter {
  width: 100%;
  font-size: 16px;
  padding: 11px 13px;
  border-radius: 10px;
  border: 1px solid var(--line);
  background: var(--panel);
  color: var(--text);
  -webkit-appearance: none;
  appearance: none;
}

.filter:focus { outline: 2px solid var(--accent); outline-offset: -1px; }

/* ------------------------------------------------------------------- groups */

.group-title {
  margin: 22px 2px 8px;
  font-size: 12px;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--muted);
}

/* --------------------------------------------------------------- one card */

details.calc {
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--panel);
  margin-bottom: 8px;
  overflow: hidden;
}

details.calc[open] { background: var(--panel-2); }

summary {
  padding: 13px 14px;
  cursor: pointer;
  font-weight: 600;
  list-style: none;
  display: flex;
  align-items: center;
  gap: 8px;
}

summary::-webkit-details-marker { display: none; }

summary::after {
  content: '';
  margin-left: auto;
  width: 7px; height: 7px;
  border-right: 2px solid var(--muted);
  border-bottom: 2px solid var(--muted);
  transform: rotate(-45deg);
  transition: transform .15s ease;
  flex-shrink: 0;
}

details.calc[open] summary::after { transform: rotate(45deg); }

.body { padding: 0 14px 14px; }

.source {
  margin: 0 0 12px;
  font-size: 12px;
  color: var(--muted);
  border-left: 2px solid var(--line);
  padding-left: 9px;
}

/*
 * A card with a long provenance note shows a brief and hides the rest behind
 * a "?". The button is the header help's glyph at two thirds the size, inline
 * with the last word of the brief rather than on a line of its own.
 *
 * Three resets earn their place. padding, because the bare summary rule sets
 * 13px 14px for the cards and it lands here too, overflowing a 17px box.
 * line-height, because an inherited line box taller than the circle leaves
 * the flex centring nothing to work with. And ::after, because the card's
 * disclosure chevron is drawn by a DESCENDANT selector, so it would be drawn
 * a second time inside this circle, next to the "?".
 */
.srcmore > summary {
  list-style: none;
  cursor: pointer;
  padding: 0;
  color: inherit;
  font-size: inherit;
}

.srcmore > summary::after { content: none; display: none; }
.srcmore > summary::-webkit-details-marker { display: none; }

.srcmore > summary .q {
  box-sizing: border-box;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  vertical-align: -4px;
  width: 17px;
  height: 17px;
  margin-left: 5px;
  line-height: 1;
  border-radius: 999px;
  border: 1px solid var(--line);
  background: var(--panel);
}

.srcmore > summary .q svg {
  display: block;
  width: 14px;
  height: 14px;
  overflow: visible;
}

.srcmore > summary:hover { color: var(--text); }
.srcmore[open] > summary .q { background: var(--panel-2); color: var(--text); }

.srcbody { margin: 7px 0 0; }

/* --------------------------------------------------------------- the form */

.field { margin-bottom: 11px; }

.field label {
  display: block;
  font-size: 13px;
  color: var(--muted);
  margin-bottom: 4px;
}

.field .hint {
  display: block;
  font-size: 12px;
  color: var(--dim);
  margin-top: 3px;
}

.control { display: flex; align-items: stretch; }

.field input, .field select {
  flex: 1;
  min-width: 0;
  font-size: 16px;          /* iOS zooms below this; do not lower it */
  font-variant-numeric: tabular-nums;
  padding: 10px 12px;
  border-radius: 9px;
  border: 1px solid var(--line);
  background: var(--bg);
  color: var(--text);
  -webkit-appearance: none;
  appearance: none;
}

.field select {
  background-image: none;
  padding-right: 12px;
}

.field input:focus, .field select:focus {
  outline: 2px solid var(--accent);
  outline-offset: -1px;
}

.unit {
  display: flex;
  align-items: center;
  padding: 0 11px;
  margin-left: 7px;
  border-radius: 9px;
  background: var(--panel);
  border: 1px solid var(--line);
  color: var(--muted);
  font-size: 13px;
  white-space: nowrap;
  flex-shrink: 0;
}

/* -------------------------------------------------------------- the output */

.out {
  margin-top: 14px;
  border-top: 1px solid var(--line);
  padding-top: 4px;
}

.out-row {
  display: flex;
  align-items: baseline;
  gap: 10px;
  padding: 7px 0;
  border-bottom: 1px solid var(--grid);
  /* The note below is flex-basis:100%, so without wrapping it competes with
     the label and value for the same line and the three overlap. */
  flex-wrap: wrap;
}

.out-row:last-child { border-bottom: 0; }

/*
 * The Preface tables card lists a whole table when the search box is empty,
 * and the longest of them is 295 rows. That is the point of it, but left to
 * grow the card would bury every calculator underneath. The list scrolls in
 * place instead, and the count stays put at the top of it while you do.
 */
[data-id="ituref"] .out {
  max-height: 60vh;
  overflow-y: auto;
}

[data-id="ituref"] .out-row.first {
  position: sticky;
  top: 0;
  z-index: 1;
  background: var(--panel);
}

/*
 * Everywhere else .out-val is a computed number, so it is bold and never
 * wraps -- breaking a figure across two lines would be worse than anything it
 * costs. Here it is prose: a class of station runs to twenty words, and on one
 * unbreakable line it hangs hundreds of pixels off the side of the page. So in
 * this card it wraps and reads as ordinary text. The Matches row keeps its
 * emphasis, being a count like any other.
 */
[data-id="ituref"] .out-row:not(.first) .out-val {
  font-weight: 400;
  white-space: normal;
  overflow-wrap: anywhere;
  min-width: 0;
}

.out-label {
  color: var(--muted);
  font-size: 13px;
  flex: 1;
  min-width: 0;
}

.out-val {
  font-size: 16px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.out-unit { color: var(--muted); font-size: 13px; white-space: nowrap; }

.out-note {
  flex-basis: 100%;
  font-size: 12px;
  color: var(--dim);
  margin-top: -3px;
}

.out-row.first .out-val { color: var(--good); }

/* ------------------------------------------------------------------ footer */

.foot { margin-top: 26px; padding: 0 2px; }

.install {
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--panel);
  padding: 11px 13px;
  font-size: 13px;
  color: var(--text);
}

.note { color: var(--dim); font-size: 12px; }

.empty { color: var(--muted); padding: 30px 4px; }

@media (max-width: 420px) {
  .msx-svg { --msx-h: 16px; }
  h1 { font-size: 19px; }
}

/* --------------------------------------------------------------- solvers */

/* Two card kinds put a radio beside each field: "calculate this one" where
   there is a single unknown, and "hold this one" where there are two. The
   fields that are being derived get dimmed so it is obvious at a glance which
   numbers you own and which the card is filling in. */

.pick {
  display: flex;
  align-items: center;
  padding: 0 4px 0 10px;
  flex-shrink: 0;
}

.pick input[type="radio"] {
  width: 20px;
  height: 20px;
  margin: 0;
  accent-color: var(--accent);
}

.pick-head {
  margin: 0 0 6px;
  text-align: right;
  font-size: 11px;
  letter-spacing: .07em;
  text-transform: uppercase;
  color: var(--muted);
}

.field.derived label { color: var(--dim); }

.field.derived input {
  color: var(--good);
  border-color: var(--grid-major);
  background: var(--bg);
}

.unitsel {
  flex: 0 0 auto;
  width: auto;
  margin-left: 7px;
  font-size: 14px;
  padding: 10px 8px;
  border-radius: 9px;
  border: 1px solid var(--line);
  background: var(--panel);
  color: var(--muted);
  -webkit-appearance: none;
  appearance: none;
}

/* ----------------------------------------------------------- pattern plot */

/* Inline SVG, drawn from the same gainAt() the readout uses. The angle axis
   is logarithmic because that is how antenna patterns are always shown. */

.plot { margin-top: 14px; }

.plot svg.pat {
  width: 100%;
  height: auto;
  display: block;
  overflow: visible;
}

.pat .grid { stroke: var(--grid); stroke-width: .6; }
.pat .grid.major { stroke: var(--grid-major); stroke-width: .9; }

.pat .curve {
  fill: none;
  stroke: var(--accent);
  stroke-width: 1.8;
  stroke-linejoin: round;
  stroke-linecap: round;
}

.pat .mark { stroke: var(--good); stroke-width: .9; stroke-dasharray: 3 3; }
.pat .dot { fill: var(--good); }

.pat .tick { fill: var(--dim); font-size: 8px; font-family: inherit; }
.pat .ty { text-anchor: end; }
.pat .tx { text-anchor: middle; }

.pat .axis {
  fill: var(--dim);
  font-size: 8px;
  font-family: inherit;
  text-anchor: middle;
}

/* The cross-polar curve, where a pattern defines one. Dashed rather than a
   second colour so it stays legible against the accent-coloured co-polar
   trace in both themes. */
.pat .curve.xpol {
  stroke: var(--muted);
  stroke-width: 1.3;
  stroke-dasharray: 4 3;
}

.pat .leg { text-anchor: end; fill: var(--dim); }

/* The build number, so you can tell at a glance whether a reload actually
   picked up a new version. Read from the script URL, not a constant. */
.build {
  margin-left: 8px;
  padding: 1px 6px;
  border-radius: 5px;
  border: 1px solid var(--line);
  color: var(--dim);
  font-variant-numeric: tabular-nums;
}

/* ------------------------------------------------------------ theme toggle */

.head-row {
  display: flex;
  align-items: flex-start;
  gap: 10px;
}

.head-row h1 { flex: 1; min-width: 0; }

.theme {
  flex-shrink: 0;
  font: inherit;
  font-size: 12px;
  padding: 6px 11px;
  border-radius: 999px;
  border: 1px solid var(--line);
  background: var(--panel);
  color: var(--muted);
  cursor: pointer;
  -webkit-appearance: none;
  appearance: none;
}

.theme:hover { color: var(--text); }
.theme:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }

/* ------------------------------------------------------------- help panel */

/* A "?" that opens an explanation of the install-and-run model, since a page
   that behaves like an app is not self-explanatory. A <details> rather than
   scripted state, so it still opens with JavaScript off. */

.help { flex-shrink: 0; position: relative; }

/*
 * The help button. padding is reset explicitly because the bare summary rule
 * above sets 13px 14px for the calculator cards, and it lands here too: with
 * border-box and a 26px width, 28px of horizontal padding overflows the box
 * completely, so the circle rendered 29x27 and the glyph sat 8px left of
 * centre, hard against the edge.
 *
 * line-height 1 for the same reason -- an inherited 18.85px line box in a 26px
 * circle leaves the flex centring nothing honest to work with.
 */
.help > summary {
  list-style: none;
  cursor: pointer;
  box-sizing: border-box;
  width: 26px;
  height: 26px;
  padding: 0;
  border-radius: 999px;
  border: 1px solid var(--line);
  background: var(--panel);
  color: var(--muted);
  display: flex;
  align-items: center;
  justify-content: center;
}

/* The glyph is geometry now, so it centres on its ink rather than on a line
   box that reserves descender space the "?" never uses. */
.help > summary svg {
  display: block;
  width: 21px;
  height: 21px;
  overflow: visible;
}

.help > summary svg path,
.srcmore .q svg path {
  fill: none;
  stroke: currentColor;
  stroke-width: 2.1;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.help > summary svg circle,
.srcmore .q svg circle { fill: currentColor; stroke: none; }

/*
 * And no disclosure chevron. The generic summary::after draws one for the
 * calculator cards, and it was being drawn INSIDE this 26px circle as well --
 * a second mark next to the "?", with margin-left:auto pushing the "?" hard
 * against the left edge. Two glyphs in a circle sized for one.
 */
.help > summary::after { content: none; display: none; }

.help > summary::-webkit-details-marker { display: none; }
.help > summary:hover { color: var(--text); }
.help[open] > summary { background: var(--panel-2); color: var(--text); }

.help-body {
  position: absolute;
  right: 0;
  top: 32px;
  z-index: 60;
  width: min(340px, calc(100vw - 32px));
  max-height: 70vh;
  overflow-y: auto;
  padding: 4px 15px 14px;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--panel);
  box-shadow: 0 10px 30px rgba(0, 0, 0, .35);
  font-size: 13px;
  line-height: 1.5;
}

.help-body h2 {
  font-size: 12px;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--muted);
  margin: 14px 0 4px;
}

.help-body p { margin: 0 0 8px; color: var(--text); }
.help-body strong { font-weight: 600; }

/*
 * The note under a variant selector. Reads as a hint rather than as content,
 * because it explains the control above it.
 */
.calc .vnote {
  font-size: 12px;
  line-height: 1.45;
  color: var(--dim);
  margin: -6px 0 12px;
  max-width: 62ch;
}

/*
 * Derived fields. The button sits in the control row beside the value; the
 * sub-form expands beneath it. A derived value is marked because a number you
 * did not type should not look like one you did.
 */
.derivebtn {
  flex: 0 0 auto;
  font: inherit;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: .01em;
  padding: 5px 11px;
  border: 1px solid var(--accent);
  border-radius: 7px;
  background: transparent;
  color: var(--accent);
  cursor: pointer;
  white-space: nowrap;
}
.derivebtn::before { content: 'f(x) '; opacity: .75; }
.derivebtn:hover { background: var(--panel-2); }
.derivebtn.active {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--panel);
}
/* No marker when active: the label already reads "typed value". */
.derivebtn.active::before { content: none; }
.field.isderived input { color: var(--accent); font-style: italic; }
.derive {
  margin: 8px 0 4px 12px;
  padding: 10px 0 2px 12px;
  border-left: 2px solid var(--line);
}
.derive .field { margin-bottom: 10px; }
.derive .field:last-child { margin-bottom: 2px; }
