/* ======================================================================
   GENERATED FILE -- do not edit directly.
   Rebuilt from css/_head.css (+ css/_extra.css, where present) and
   apps/_shared/css/app-shell.css by apps/_shared/sync-apps.py.
   Edit one of those source files, then re-run the sync script.
   ====================================================================== */

/*
  Virtual Oscilloscope — standalone PWA
  ------------------------------------------------------------------
  Root design tokens (from the DiMastro site's styles.css) + the
  shared .tbc card styles (tube-bias-calculator.css) + the input-grid
  and result-strip components (bench-calculators.css) + the scope
  widget's own styles (virtual-oscilloscope.css), combined into one
  file, plus an app-shell layer at the bottom.
*/

/* The tick-ring numbers around Champ/Marshall/Vox/AC4 knobs are absolutely
   positioned and can extend past their own column on narrow viewports.
   Without this, that overflow widens the page's scrollable area and
   shifts/clips the app-shell layout. Set here (not in the shared
   app-shell.css) so it's scoped to this app only. */
html, body { overflow-x: hidden; }


:root {
  --tbc-bg:            #1c1712;
  --tbc-panel:         #221b15;
  --tbc-panel-raised:  #2a2119;
  --tbc-well:          #16110d;
  --tbc-border:        #3c2f22;
  --tbc-border-soft:   #2f261c;

  --tbc-ink:           #f3ead9;
  --tbc-ink-muted:     #dfd0bd;
  --tbc-ink-faint:     #cd9c60;

  --tbc-glow:          #ff9142;
  --tbc-glow-dim:      #c96a2c;
  --tbc-glow-soft:     rgba(255, 145, 66, 0.16);

  --tbc-cold:          #4da3ff;
  --tbc-safe:          #7cbf8e;
  --tbc-warn:          #e7b84f;
  --tbc-warn-soft:     rgba(231, 184, 79, 0.14);
  --tbc-danger:        #e0522e;
  --tbc-danger-soft:   rgba(224, 82, 46, 0.14);

  --tbc-font-display: "Space Grotesk", "Segoe UI", sans-serif;
  --tbc-font-body:    "IBM Plex Sans", "Segoe UI", sans-serif;
  --tbc-font-mono:    "IBM Plex Mono", "SFMono-Regular", Consolas, monospace;

  --tbc-radius:    14px;
  --tbc-radius-sm: 8px;
}


.tbc {
  font-family: var(--tbc-font-body);
  color: var(--tbc-ink);
  background:
    radial-gradient(120% 140% at 15% -10%, rgba(44, 33, 23, 0.8) 0%, transparent 55%),
    linear-gradient(175deg, rgba(34, 27, 21, 0.8) 0%, rgba(28, 23, 18, 0.8) 100%);
  border: 1px solid var(--tbc-border);
  border-radius: var(--tbc-radius);
  box-shadow:
    0 1px 0 rgba(255, 255, 255, 0.04) inset,
    0 30px 60px -30px rgba(0, 0, 0, 0.6);
  max-width: 760px;
  margin: 0 auto;
  padding: 28px 28px 24px;
  box-sizing: border-box;
  position: relative;
}

.tbc *, .tbc *::before, .tbc *::after { box-sizing: border-box; }

.tbc :focus-visible {
  outline: 2px solid var(--tbc-glow);
  outline-offset: 2px;
}

/* ---------- header ---------- */
.tbc-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 18px;
}

.tbc-eyebrow {
  font-family: var(--tbc-font-mono);
  font-size: 11px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--tbc-glow);
  margin: 0 0 6px;
}

.tbc-title {
  font-family: var(--tbc-font-display);
  font-size: 26px;
  font-weight: 600;
  line-height: 1.15;
  margin: 0 0 6px;
  color: var(--tbc-ink);
}

.tbc-sub {
  font-size: 13.5px;
  color: var(--tbc-ink-muted);
  margin: 0;
  max-width: 100ch;
}

.tbc-badge {
  flex: none;
  font-family: var(--tbc-font-mono);
  font-size: 10.5px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--tbc-ink-faint);
  border: 1px solid var(--tbc-border);
  border-radius: 999px;
  padding: 5px 10px;
  white-space: nowrap;
}

/* ---------- warning strip ---------- */
.tbc-warning {
  display: flex;
  gap: 10px;
  align-items: flex-start;
  background: var(--tbc-danger-soft);
  border: 1px solid rgba(224, 82, 46, 0.35);
  border-radius: var(--tbc-radius-sm);
  padding: 10px 14px;
  font-size: 12.5px;
  line-height: 1.5;
  color: #f0d3c8;
  margin-bottom: 22px;
}
.tbc-warning[hidden] { display: none; }

.tbc-warning svg { flex: none; margin-top: 2px; color: var(--tbc-danger); }
.tbc-warning strong { color: #fff; }

/* ---------- database-load notice (shown only on the EMBEDDED_TUBES_CSV fallback) ---------- */
.tbc-db-notice {
  display: flex;
  gap: 10px;
  align-items: flex-start;
  background: var(--tbc-warn-soft);
  border: 1px solid rgba(231, 184, 79, 0.35);
  border-radius: var(--tbc-radius-sm);
  padding: 10px 14px;
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--tbc-ink-muted);
  margin-bottom: 22px;
}
.tbc-db-notice[hidden] { display: none; }

.tbc-db-notice svg { flex: none; margin-top: 2px; color: var(--tbc-warn); }
.tbc-db-notice strong { color: var(--tbc-warn); }

/* ---------- setup row (tube + voltage) ---------- */
.tbc-setup {
  display: grid;
  grid-template-columns: 1.3fr 1fr;
  gap: 14px;
  padding: 18px;
  background: rgba(42, 33, 25, 0.8);
  border: 1px solid var(--tbc-border-soft);
  border-radius: var(--tbc-radius-sm);
}

.tbc-field {
  display: flex;
  flex-direction: column;
  gap: 6px;
  font-size: 12.5px;
  color: var(--tbc-ink-muted);
}

.tbc-field-label {
  font-family: var(--tbc-font-mono);
  font-size: 11px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--tbc-ink-faint);
}

.tbc-select,
.tbc-input {
  font-family: var(--tbc-font-body);
  font-size: 15px;
  color: var(--tbc-ink);
  background: var(--tbc-well);
  border: 1px solid var(--tbc-border);
  border-radius: 8px;
  padding: 10px 12px;
  width: 100%;
  appearance: none;
  -webkit-appearance: none;
  transition: border-color 120ms ease, box-shadow 120ms ease;
}

.tbc-select {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1l5 5 5-5' stroke='%23b3a28c' stroke-width='1.6' fill='none' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 12px center;
  padding-right: 32px;
}

.tbc-input:focus, .tbc-select:focus {
  border-color: var(--tbc-glow-dim);
  box-shadow: 0 0 0 3px var(--tbc-glow-soft);
  outline: none;
}

.tbc-input-unit {
  position: relative;
  display: flex;
  align-items: center;
}

.tbc-input-unit .tbc-input { padding-right: 54px; }

.tbc-unit {
  position: absolute;
  right: 12px;
  font-family: var(--tbc-font-mono);
  font-size: 11.5px;
  color: var(--tbc-ink-faint);
  pointer-events: none;
}

.tbc-hint {
  grid-column: 1 / -1;
  margin: 2px 0 0;
  font-size: 12.5px;
  color: var(--tbc-ink-faint);
  min-height: 1.4em;
}

.tbc-hint strong { color: var(--tbc-ink-muted); font-weight: 600; }

/* ---------- Class A / Class AB reference strip ---------- */
.tbc-reference {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1px;
  background: var(--tbc-border-soft);
  border: 1px solid var(--tbc-border-soft);
  border-radius: var(--tbc-radius-sm);
  overflow: hidden;
  margin: 18px 0;
}

.tbc-ref-col {
  background: rgba(34, 27, 21, 0.8);
  padding: 14px 16px;
}

.tbc-ref-col h3 {
  font-family: var(--tbc-font-display);
  font-size: 12.5px;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--tbc-ink-muted);
  margin: 0 0 10px;
}

.tbc-ref-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  padding: 5px 0;
  border-top: 1px dashed var(--tbc-border-soft);
  font-size: 12.5px;
}

.tbc-ref-row:first-of-type { border-top: none; }

.tbc-ref-row dt { color: var(--tbc-ink-muted); font-weight: 400; }
.tbc-ref-row dt span {
  display: inline-block;
  margin-left: 5px;
  font-family: var(--tbc-font-mono);
  font-size: 10.5px;
  color: var(--tbc-ink-faint);
}
.tbc-ref-row dd {
  margin: 0;
  font-family: var(--tbc-font-mono);
  font-size: 13.5px;
  color: var(--tbc-ink);
  white-space: nowrap;
}

/* ---------- gauge class selector ---------- */
.tbc-class-select {
  max-width: 200px;
  margin: 0 0 18px;
}

/* ---------- mode dial ---------- */
.tbc-modes {
  display: flex;
  gap: 6px;
  border-bottom: 1px solid var(--tbc-border-soft);
  margin-bottom: 18px;
  overflow-x: auto;
  scrollbar-width: none;
}
.tbc-modes::-webkit-scrollbar { display: none; }

.tbc-mode-btn {
  flex: none;
  font-family: var(--tbc-font-display);
  font-size: 13px;
  font-weight: 500;
  color: var(--tbc-ink-faint);
  background: transparent;
  border: none;
  border-bottom: 2px solid transparent;
  padding: 10px 6px 12px;
  margin-right: 14px;
  cursor: pointer;
  white-space: nowrap;
  transition: color 120ms ease, border-color 120ms ease;
}

.tbc-mode-btn:hover { color: var(--tbc-ink-muted); }

.tbc-mode-btn.is-active {
  color: var(--tbc-glow);
  border-bottom-color: var(--tbc-glow);
}

/* ---------- calculation panel ---------- */
.tbc-panel {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 22px;
  align-items: start;
}

.tbc-mode-group {
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.tbc-mode-group[hidden] { display: none; }

.tbc-mode-copy {
  font-size: 12.5px;
  color: var(--tbc-ink-faint);
  margin: 0 0 2px;
  line-height: 1.5;
}

/* ---------- readout / gauge ---------- */
.tbc-readout {
  position: relative;
  background: var(--tbc-panel-raised);
  border: 1px solid var(--tbc-border-soft);
  border-radius: var(--tbc-radius-sm);
  padding: 16px 18px 14px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  overflow: hidden;
}

.tbc-tube-frame {
  position: absolute;
  top: 4px;
  left: 50%;
  transform: translateX(-50%);
  width: 92%;
  opacity: 0.3;
  z-index: 0;
  pointer-events: none;
}

.tbc-tube-photo { width: 100%; height: auto; display: block; }

.tbc-gauge-wrap {
  position: relative;
  z-index: 1;
  width: 100%;
  max-width: 240px;
}

.tbc-gauge {
  width: 100%; height: auto; display: block;
  filter: drop-shadow(0 1px 1px rgba(0, 0, 0, 0.9)) drop-shadow(0 0 4px rgba(0, 0, 0, 0.9));
}

.tbc-gauge-figure {
  font-family: var(--tbc-font-mono);
  font-size: 22px;
  fill: #ffffff;
}

.tbc-gauge-label {
  font-family: var(--tbc-font-body);
  font-size: 9.5px;
  fill: var(--tbc-ink);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

.tbc-gauge-tick {
  font-family: var(--tbc-font-mono);
  font-size: 8.5px;
  fill: var(--tbc-ink);
}

.tbc-readout-values {
  position: relative;
  z-index: 1;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px 16px;
  width: 100%;
  margin-top: 2px;
}

.tbc-big-value {
  text-align: center;
  padding-top: 8px;
  border-top: 1px solid var(--tbc-border-soft);
}

.tbc-big-value .tbc-num {
  display: block;
  font-family: var(--tbc-font-mono);
  font-size: 19px;
  color: var(--tbc-glow);
  text-shadow: 0 0 18px var(--tbc-glow-soft), 0 1px 3px rgba(0, 0, 0, 0.9);
  line-height: 1.2;
}

.tbc-big-value small {
  display: block;
  font-size: 10px;
  color: var(--tbc-ink);
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.9);
/*  text-transform: uppercase;*/
  letter-spacing: 0.05em;
  margin-top: 2px;
}

.tbc-steps {
  width: 100%;
  margin: 6px 0 0;
  padding-top: 10px;
  border-top: 1px dashed var(--tbc-border-soft);
  font-size: 11.5px;
  color: var(--tbc-ink);
  text-shadow: 0 1px 4px rgba(0, 0, 0, 0.95), 0 0 6px rgba(0, 0, 0, 0.8);
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.tbc-steps span { color: #ffffff; font-family: var(--tbc-font-mono); }

/* ---------- bench reference table ---------- */
.tbc-bench {
  margin-top: 22px;
  border-top: 1px solid var(--tbc-border-soft);
  padding-top: 14px;
}

.tbc-bench summary {
  cursor: pointer;
  font-family: var(--tbc-font-display);
  font-size: 13px;
  color: var(--tbc-ink-muted);
  list-style: none;
  display: flex;
  align-items: center;
  gap: 6px;
}
.tbc-bench summary::-webkit-details-marker { display: none; }
.tbc-bench summary::before {
  content: "";
  width: 7px;
  height: 7px;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: rotate(-45deg);
  transition: transform 150ms ease;
}
.tbc-bench[open] summary::before { transform: rotate(45deg); }

.tbc-bench-table {
  width: 100%;
  border-collapse: collapse;
  margin-top: 12px;
  font-size: 12.5px;
}
.tbc-bench-table th, .tbc-bench-table td {
  text-align: left;
  padding: 7px 10px;
  border-bottom: 1px solid var(--tbc-border-soft);
}
.tbc-bench-table th {
  font-family: var(--tbc-font-mono);
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--tbc-ink-faint);
  font-weight: 400;
}
.tbc-bench-table td { color: var(--tbc-ink-muted); font-family: var(--tbc-font-mono); }
.tbc-bench-table td:first-child { font-family: var(--tbc-font-body); color: var(--tbc-ink); }

/* ---------- footer ---------- */
.tbc-footer {
  margin-top: 18px;
  font-size: 11.5px;
  color: var(--tbc-ink-faint);
  line-height: 1.6;
}

/* ---------- responsive ---------- */
@media (max-width: 640px) {
  .tbc { padding: 20px 16px; }
  .tbc-setup { grid-template-columns: 1fr; }
  .tbc-reference { grid-template-columns: 1fr; }
  .tbc-panel { grid-template-columns: 1fr; }
  .tbc-title { font-size: 22px; }
  .tbc-tube-frame { width: 90%; }
}

@media (prefers-reduced-motion: reduce) {
  .tbc-select, .tbc-input, .tbc-mode-btn { transition: none; }
  .tbc-gauge * { transition: none !important; }
}

/* ---------- input grids (from bench-calculators.css) ---------- */
.tbc-grid-2,
.tbc-grid-3 {
  display: grid;
  gap: 14px;
  margin-bottom: 18px;
}
.tbc-grid-2 { grid-template-columns: 1fr 1fr; }
.tbc-grid-3 { grid-template-columns: 1fr 1fr 1fr; }

/* ---------- results strip (2 or 3 up) ---------- */
.tbc-results {
  display: grid;
  grid-template-columns: repeat(var(--tbc-results-cols, 2), 1fr);
  gap: 12px;
  margin-top: 18px;
}

.tbc-result-item {
  background: rgba(42, 33, 25, 0.8);
  border: 1px solid var(--tbc-border-soft);
  border-radius: var(--tbc-radius-sm);
  padding: 14px 14px 12px;
  text-align: center;
}

.tbc-result-label {
  font-family: var(--tbc-font-mono);
  font-size: 10.5px;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--tbc-ink-faint);
  margin: 0 0 6px;
}

.tbc-result-value {
  font-family: var(--tbc-font-mono);
  font-size: 20px;
  color: var(--tbc-glow);
  text-shadow: 0 0 18px var(--tbc-glow-soft);
  line-height: 1.2;
}

@media (max-width: 640px) {
  .tbc-grid-2, .tbc-grid-3 { grid-template-columns: 1fr; }
  .tbc-results { grid-template-columns: repeat(2, 1fr); }
}


/* Virtual Oscilloscope
   Scoped classes below (.vs-*, plus the .ts-knob/.ts-ctl widget reused
   from the Tone Stack Calculator's knob component) sit inside the
   shared .tbc card above, same as every other bench tool. */
/*
  DiMastro — Virtual Oscilloscope (staging preview)
  --------------------------------------------------
  Loaded after bench-calculators.css. Adds the two component types that
  page doesn't already have: range sliders and the scope canvas. Everything
  else on this page (fields, result cards, warning note, header) reuses the
  existing .tbc-* classes untouched.
*/

.vs-slider-row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  margin-bottom: 6px;
}
.vs-slider-row .tbc-field-label { margin: 0; }
.vs-slider-val {
  font-family: var(--tbc-font-mono);
  font-size: 12.5px;
  font-weight: 600;
  color: var(--tbc-glow);
}

.vs-range {
  -webkit-appearance: none;
  appearance: none;
  width: 100%;
  height: 4px;
  border-radius: 999px;
  background: var(--tbc-border);
  outline: none;
  margin: 4px 0 2px;
}
.vs-range::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: var(--tbc-glow);
  border: 2px solid var(--tbc-panel);
  cursor: pointer;
}
.vs-range::-moz-range-thumb {
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: var(--tbc-glow);
  border: 2px solid var(--tbc-panel);
  cursor: pointer;
}

.vs-scope {
  position: relative;
  padding: 0;
  margin-bottom: 18px;
  background: transparent;
  box-shadow: none;
}
.vs-scope-inner {
  background: linear-gradient(155deg, #9a9b9f 0%, #7d7e82 100%);
  border-radius: 10px;
  padding: 10px;
  box-shadow: inset 0 2px 5px rgba(0,0,0,0.5);
}
.vs-scope canvas { display: block; width: 100%; height: auto; border-radius: 3px; }

.vs-compare {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
  margin-top: 10px;
}
.vs-compare-card {
  background: rgba(34, 27, 21, 0.6);
  border: 1px solid var(--tbc-border-soft);
  border-radius: var(--tbc-radius-sm);
  padding: 10px 12px;
}
.vs-compare-card .who {
  font-family: var(--tbc-font-mono);
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--tbc-ink-faint);
  margin: 0 0 4px;
}
.vs-compare-card .num {
  font-family: var(--tbc-font-mono);
  font-size: 15px;
  font-weight: 700;
  color: var(--tbc-ink);
}

@media (max-width: 640px) {
  .vs-compare { grid-template-columns: 1fr; }
}

/* ── scope + pitch knob row, wrapped in a single card ── */
.vs-scope-card {
  background: rgb(69 69 69 / 80%);
  border: 1.5px solid #919191;
  border-radius: var(--tbc-radius-sm);
  padding: 16px;
  margin-bottom: 18px;
}
.vs-scope-row {
  display: flex;
  align-items: flex-start;
  gap: 18px;
}
.vs-scope-row .vs-scope { flex: 1 1 auto; margin-bottom: 0; min-width: 0; }
.vs-pitch-col {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: space-between;
  gap: 18px;
  width: 84px;
}
.vs-pitch-col .ts-ctl-name { color: var(--tbc-ink-muted); }
.vs-pitch-col .ts-ctl-num { color: var(--tbc-glow); text-shadow: none; }
.vs-knob-sm { width: 44px; height: 44px; }

@media (max-width: 640px) {
  .vs-scope-row { flex-direction: column; }
  .vs-pitch-col { flex-direction: row; flex-wrap: wrap; justify-content: center; width: auto; gap: 14px; }
}

/* ── graphical knobs, ported from the Tone Stack Calculator's .ts-knob
   widget: real rotating knob images, per-brand faceplate colors and
   badge, same drag/keyboard/wheel interaction. ── */
.ts-controls { margin-top: 4px; }

.ts-knobs-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: nowrap;
  gap: 18px 30px;
  padding: 16px 20px;
  background:
    linear-gradient(180deg, var(--face-hi, #d2d5df) 0%, var(--face-mid, #bfbfc5) 45%, var(--face-lo, #898885) 100%);
  border: 1.5px solid var(--face-outline, #498aa5);
  border-radius: var(--tbc-radius-sm);
  outline: 1.5px solid var(--face-outline, #498aa5);
  outline-offset: 4px;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .5), inset 0 -1px 0 rgba(0, 0, 0, .15);
  transition: background .2s ease, border-color .2s ease, outline-color .2s ease;
}

/* Champ / Marshall / Vox / AC4: the tick ring's top-of-scale number
   overhangs above the knob's own box on every screen size -- extra top
   padding keeps it clear of the card edge instead of touching it. */
.ts-knobs-row--ticked { padding-top: 38px; }
/* All profiles: Volume + tone knobs as equal siblings, centered in the
   space to the right of the badge with even spacing between each knob. */
.ts-knobs-pair {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 28px;
  flex: 1 1 auto;
  min-width: 0;
}
/* 2-knob chrome-plate profiles (Champ, Tweed Deluxe): narrower plate,
   centered in the space beside the badge. Knob gap/size unchanged --
   only the plate's own width and position shrink to fit its content. */
/* Two-layer centering fix. A single element can't both (a) claim the
   real leftover width beside the badge, via flex-grow, AND (b) have a
   narrower visual width with margin:auto centering -- once flex-grow
   fills the item's box to its grown size, margin:auto has no leftover
   space left within that box to center against; it only centers the
   box itself within the row, which flex-grow already made full-width.
   So: outer = plain, invisible, flex:1 1 auto (claims the real leftover
   width, row-level justify-content:flex-start stops it being eaten by
   space-between); inner .ts-knobs-pair--narrow = the actual visually
   narrow plate, centered via the outer's own justify-content:center. */
.ts-knobs-row--narrow-plate {
  justify-content: flex-start;
}
.ts-knobs-pair--narrow-outer {
  display: flex;
  justify-content: center;
  flex: 1 1 auto;
  min-width: 0;
}
.ts-knobs-pair--narrow {
  flex: 0 1 auto;
  max-width: 100%;
}

/* Champ / Marshall / Vox / AC4: small chrome plate under Volume + Tone
   knobs and their numbers only — tweed faceplate remains the background
   of the whole row. Brushed chrome: bright horizontal band through the
   middle, slightly darker top/bottom, soft edge highlight like real
   stamped metal. */
.ts-knobs-row--ticked .ts-knobs-pair--chrome {
  gap: 36px; /* wider than the 28px default -- extra breathing room so
                tick-ring numbers on adjacent knobs (Bassman's 4-knob
                row) can't crowd each other on narrower/lower-DPI displays. */
}
.ts-knobs-pair--chrome {
  position: relative;
  padding: 28px 36px 18px;
  margin: 4px 8px;
  border-radius: 10px;
  background:
    /* lengthwise brushed highlight (bright middle) */
    linear-gradient(90deg,
      rgba(0, 0, 0, .14) 0%,
      rgba(255, 255, 255, .08) 18%,
      rgba(255, 255, 255, .38) 50%,
      rgba(255, 255, 255, .08) 82%,
      rgba(0, 0, 0, .14) 100%),
    /* vertical shade: darker top & bottom, bright mid */
    linear-gradient(180deg,
      #8a909a 0%,
      #c4cad4 20%,
      #f0f3f8 48%,
      #c0c6d0 80%,
      #7e848e 100%);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, .85),
    inset 0 -1px 0 rgba(0, 0, 0, .28),
    inset 1px 0 0 rgba(255, 255, 255, .25),
    inset -1px 0 0 rgba(0, 0, 0, .12),
    0 0 0 1px rgba(60, 70, 85, .35),
    0 2px 5px rgba(0, 0, 0, .28),
    0 1px 0 rgba(255, 255, 255, .15);
}
/* Bassman desktop: tighter padding than the standard chrome plate --
   frees up room for its 4 knobs beside the (now shorter) badge. */
.ts-knobs-pair--compact {
  padding: 24px 20px 16px !important;
}
/* Tighter than the general 36px chrome-plate gap -- with knobs locked
   to a 66px column at 0.68 scale, this much space is no longer needed
   to keep tick labels from crowding, and the extra gap just looked
   sparse. Scoped to Bassman only, not Champ/Tweed Deluxe. */
.ts-knobs-row--ticked .ts-knobs-pair--compact {
  gap: 22px;
}
/* Bassman desktop: slightly smaller knobs (with their tick rings) so
   all 4 comfortably fit the compact plate without crowding the edges.
   Mobile is unaffected -- its own more specific rule already wins. */
.ts-knobs-pair--compact > .ts-ctl {
  width: 66px;
  flex: 0 0 66px;
}
.ts-knobs-pair--compact > .ts-ctl .ts-knob-wrap {
  transform: scale(0.68);
  transform-origin: center center;
}
.ts-knobs-pair--compact > .ts-ctl .ts-knob-wrap + .ts-ctl-name {
  margin-top: 10px;
}
.ts-knobs-pair--chrome .ts-ctl-name,
.ts-knobs-pair--chrome .ts-ctl-num,
.ts-knobs-pair--chrome .ts-ctl-db,
.ts-knobs-pair--chrome .ts-knob-tick-num {
  color: #1a1e24 !important;
  text-shadow: 0 1px 0 rgba(255, 255, 255, .5) !important;
}
.ts-knobs-pair--chrome .ts-knob-tick-mark {
  background: #1a1e24 !important;
}

/* Vox profiles: same plate shape and 3-tone illumination (dark top/
   bottom, lit middle) as the light chrome plate above, but a dark
   brown/maroon tone matching the real AC30/AC15 panel surround, with
   light cream text instead of dark for contrast. */
.ts-knobs-pair--chrome-dark {
  position: relative;
  padding: 28px 36px 18px;
  margin: 4px 8px;
  border-radius: 10px;
  border: 2.5px solid #c8b99e;
  outline: 2.5px solid #c8b99e;
  outline-offset: -8px;
  flex: 0 1 50%;
  max-width: 50%;
  margin-left: auto;
  margin-right: auto;
  background:
    linear-gradient(90deg,
      rgba(0, 0, 0, .12) 0%,
      rgba(255, 255, 255, .02) 18%,
      rgba(255, 255, 255, .05) 50%,
      rgba(255, 255, 255, .02) 82%,
      rgba(0, 0, 0, .12) 100%),
    linear-gradient(180deg,
      #363232 0%,
      #423e3d 20%,
      #524e4c 48%,
      #423e3d 80%,
      #363232 100%);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, .08),
    inset 0 -1px 0 rgba(0, 0, 0, .5),
    inset 1px 0 0 rgba(255, 255, 255, .05),
    inset -1px 0 0 rgba(0, 0, 0, .3),
    0 2px 5px rgba(0, 0, 0, .35),
    0 1px 0 rgba(255, 255, 255, .05);
}
/* AC30: same shape/plate as above, but a red plate and white double
   border instead of the neutral dark plate + cream border. */
.ts-knobs-pair--chrome-red {
  position: relative;
  padding: 28px 36px 18px;
  margin: 4px 8px;
  border-radius: 10px;
  border: 2.5px solid #ffffff;
  outline: 2.5px solid #ffffff;
  outline-offset: -8px;
  flex: 0 1 50%;
  max-width: 50%;
  margin-left: auto;
  margin-right: auto;
  background:
    linear-gradient(90deg,
      rgba(0, 0, 0, .22) 0%,
      rgba(255, 255, 255, .02) 18%,
      rgba(255, 255, 255, .06) 50%,
      rgba(255, 255, 255, .02) 82%,
      rgba(0, 0, 0, .22) 100%),
    linear-gradient(180deg,
      #3a0f11 0%,
      #571519 20%,
      #7a1d22 48%,
      #571519 80%,
      #3a0f11 100%);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, .08),
    inset 0 -1px 0 rgba(0, 0, 0, .5),
    inset 1px 0 0 rgba(255, 255, 255, .05),
    inset -1px 0 0 rgba(0, 0, 0, .3),
    0 2px 5px rgba(0, 0, 0, .35),
    0 1px 0 rgba(255, 255, 255, .05);
}
.ts-knobs-pair--chrome-red .ts-ctl-name,
.ts-knobs-pair--chrome-red .ts-ctl-num,
.ts-knobs-pair--chrome-red .ts-ctl-db,
.ts-knobs-pair--chrome-red .ts-knob-tick-num {
  color: #f4ece9 !important;
  text-shadow: 0 1px 1px rgba(0, 0, 0, .6) !important;
}
.ts-knobs-pair--chrome-red .ts-knob-tick-mark {
  background: #f4ece9 !important;
}
.ts-knobs-pair--chrome-dark .ts-ctl-name,
.ts-knobs-pair--chrome-dark .ts-ctl-num,
.ts-knobs-pair--chrome-dark .ts-ctl-db,
.ts-knobs-pair--chrome-dark .ts-knob-tick-num {
  color: #f4ece9 !important;
  text-shadow: 0 1px 1px rgba(0, 0, 0, .6) !important;
}
.ts-knobs-pair--chrome-dark .ts-knob-tick-mark {
  background: #f4ece9 !important;
}

/* Champ (and any profile with panelBg): tweed / fabric faceplate.
   Background image is applied inline from JS. */
.ts-knobs-row--textured {
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), inset 0 -1px 0 rgba(0, 0, 0, .35);
}
.ts-knobs-row--textured .ts-ctl-name,
.ts-knobs-row--textured .ts-ctl-num {
  color: var(--face-text, #2a2210);
  text-shadow: 0 1px 0 rgba(255,255,255,0.25), 0 1px 2px rgba(0,0,0,0.35);
}

/* Blackface faceplate: dark panel, light legends, silver edge */
.ts-knobs-row--blackface {
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, .12),
    inset 0 -1px 0 rgba(0, 0, 0, .55),
    0 0 0 1px rgba(255, 255, 255, .06);
}
.ts-knobs-row--blackface .ts-ctl-name,
.ts-knobs-row--blackface .ts-ctl-num {
  color: var(--face-text, #f0efe9);
  text-shadow: 0 1px 1px rgba(0, 0, 0, .85);
}

/* Silverface faceplate: brushed aluminum, dark legends, teal edge.
   (Inner section frame and pointer arrows removed — clean panel.) */
.ts-knobs-row--silverface {
  background:
    linear-gradient(90deg,
      rgba(0, 0, 0, .14) 0%,
      rgba(255, 255, 255, .08) 18%,
      rgba(255, 255, 255, .38) 50%,
      rgba(255, 255, 255, .08) 82%,
      rgba(0, 0, 0, .14) 100%),
    linear-gradient(180deg,
      #8a909a 0%,
      #c4cad4 20%,
      #f0f3f8 48%,
      #c0c6d0 80%,
      #7e848e 100%);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, .85),
    inset 0 -1px 0 rgba(0, 0, 0, .28),
    inset 1px 0 0 rgba(255, 255, 255, .25),
    inset -1px 0 0 rgba(0, 0, 0, .12),
    0 0 0 1px rgba(60, 70, 85, .35),
    0 2px 5px rgba(0, 0, 0, .28),
    0 1px 0 rgba(255, 255, 255, .15);
}
.ts-knobs-row--silverface .ts-ctl-name,
.ts-knobs-row--silverface .ts-ctl-num {
  color: var(--face-text, #1a1e24);
  text-shadow: 0 1px 0 rgba(255, 255, 255, .5);
}

.ts-badge-wrap { flex: 0 0 auto; display: flex; justify-content: flex-start; align-items: center; min-width: 40px; }
.ts-badge-wrap--name { flex: 0 1 auto; min-width: 0; max-width: 46%; }
/* All badge photos share the same width; height follows each image's
   own aspect ratio rather than a fixed height per style. Keeps every
   amp's nameplate visually the same "size" on the panel regardless of
   whether it's a wide riveted plate or a squarish two-line badge. */
.ts-badge { width: 150px; height: auto; max-width: 100%; display: block; object-fit: contain; }
/* Tweed Deluxe / Bassman: same badge height as Champ instead of the
   uniform-width system, per explicit request -- each badge's own width
   now follows its own aspect ratio at that fixed height. */
.ts-badge--champ-height { width: auto !important; height: 33px !important; max-width: 220px !important; }
/* Bassman desktop: slightly shorter than champ-height, and a tighter
   max-width -- frees up horizontal room for the 4-knob plate beside it.
   Mobile is unaffected (handled separately by mobile-row scaling). */
.ts-badge--bassman { width: auto !important; height: 27px !important; max-width: 185px !important; }
.ts-badge-wrap--sm { flex: 0 0 auto; justify-content: flex-start; min-width: 0; }
.ts-badge-wrap--script { flex: 0 0 auto; justify-content: flex-start; min-width: 0; }

/* Faceplate model lettering — era style match (not official logo art) */
.ts-panel-name {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: center;
  gap: 2px;
  line-height: 1.05;
  user-select: none;
  pointer-events: none;
}
.ts-panel-name-brand {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.22em;
  text-transform: uppercase;
}
.ts-panel-name-model {
  font-size: 15px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

/* Blackface: cream silk-screen on black */
.ts-panel-name--blackface .ts-panel-name-brand {
  font-family: "Palatino Linotype", Palatino, "Book Antiqua", Georgia, serif;
  font-style: italic;
  font-weight: 600;
  font-size: 13px;
  letter-spacing: 0.04em;
  text-transform: none;
  color: #f4f1e6;
  text-shadow: 0 1px 1px rgba(0,0,0,.75);
}
.ts-panel-name--blackface .ts-panel-name-model {
  font-family: "Gill Sans", "Gill Sans MT", "Trebuchet MS", "Segoe UI", sans-serif;
  font-size: 14px;
  font-weight: 600;
  letter-spacing: 0.14em;
  color: #f4f1e6;
  text-shadow: 0 1px 1px rgba(0,0,0,.75);
}

/* Silverface: dark print on aluminum */
.ts-panel-name--silverface .ts-panel-name-brand {
  font-family: "Palatino Linotype", Palatino, "Book Antiqua", Georgia, serif;
  font-style: italic;
  font-weight: 600;
  font-size: 13px;
  letter-spacing: 0.04em;
  text-transform: none;
  color: #1a1e24;
  text-shadow: 0 1px 0 rgba(255,255,255,.4);
}
.ts-panel-name--silverface .ts-panel-name-model {
  font-family: "Gill Sans", "Gill Sans MT", "Trebuchet MS", "Segoe UI", sans-serif;
  font-size: 14px;
  font-weight: 600;
  letter-spacing: 0.14em;
  color: #1a1e24;
  text-shadow: 0 1px 0 rgba(255,255,255,.35);
}

/* Tweed Champ */
.ts-panel-name--tweed .ts-panel-name-brand {
  font-family: "Palatino Linotype", Palatino, "Book Antiqua", Georgia, serif;
  font-style: italic;
  font-weight: 600;
  font-size: 12px;
  letter-spacing: 0.04em;
  text-transform: none;
  color: #2a2210;
  text-shadow: 0 1px 0 rgba(255,255,255,.25);
}
.ts-panel-name--tweed .ts-panel-name-model {
  font-family: "Gill Sans", "Gill Sans MT", "Trebuchet MS", "Segoe UI", sans-serif;
  font-size: 15px;
  font-weight: 700;
  letter-spacing: 0.18em;
  color: #2a2210;
  text-shadow: 0 1px 0 rgba(255,255,255,.2);
}

/* Vox */
.ts-panel-name--vox .ts-panel-name-brand {
  font-family: "Gill Sans", "Gill Sans MT", "Trebuchet MS", "Segoe UI", sans-serif;
  font-size: 24px;
  font-weight: 700;
  letter-spacing: 0.28em;
  color: #f4ece9;
  text-shadow: 0 1px 1px rgba(0,0,0,.55);
}
.ts-panel-name--vox .ts-panel-name-model {
  font-family: "Gill Sans", "Gill Sans MT", "Trebuchet MS", "Segoe UI", sans-serif;
  font-size: 36px;
  font-weight: 700;
  letter-spacing: 0.12em;
  color: #f4ece9;
  text-shadow: 0 1px 1px rgba(0,0,0,.55);
}

/* AC4: cream tolex background needs dark lettering, not the light
   lettering the red/black tolex variants use. */
.ts-panel-name--vox-cream .ts-panel-name-brand {
  font-family: "Gill Sans", "Gill Sans MT", "Trebuchet MS", "Segoe UI", sans-serif;
  font-size: 24px;
  font-weight: 700;
  letter-spacing: 0.28em;
  color: #3a2f1f;
  text-shadow: 0 1px 0 rgba(255,255,255,.25);
}
.ts-panel-name--vox-cream .ts-panel-name-model {
  font-family: "Gill Sans", "Gill Sans MT", "Trebuchet MS", "Segoe UI", sans-serif;
  font-size: 36px;
  font-weight: 700;
  letter-spacing: 0.12em;
  color: #3a2f1f;
  text-shadow: 0 1px 0 rgba(255,255,255,.25);
}

/* Marshall */
.ts-panel-name--marshall .ts-panel-name-brand {
  font-family: "Gill Sans", "Gill Sans MT", "Trebuchet MS", "Segoe UI", sans-serif;
  font-size: 22px;
  font-weight: 700;
  letter-spacing: 0.2em;
  color: #241a0e;
  text-shadow: 0 1px 0 rgba(255,255,255,.25);
}
.ts-panel-name--marshall .ts-panel-name-model {
  font-family: "Gill Sans", "Gill Sans MT", "Trebuchet MS", "Segoe UI", sans-serif;
  font-size: 32px;
  font-weight: 700;
  letter-spacing: 0.1em;
  color: #241a0e;
  text-shadow: 0 1px 0 rgba(255,255,255,.2);
}

.ts-knobs-group { display: flex; flex-wrap: nowrap; justify-content: center; gap: 18px 26px; flex-shrink: 0; }

@media (max-width: 640px) {
  /* Column: badge on top, knobs group fills and centers below */
  .ts-knobs-row {
    flex-direction: column;
    flex-wrap: nowrap;
    align-items: center;
    justify-content: flex-start;
    gap: 20px;
  }
  .ts-badge-wrap,
  .ts-badge-wrap--sm,
  .ts-badge-wrap--name {
    flex: 0 0 auto;
    width: 100%;
    max-width: 100%;
    justify-content: center;
  }
  .ts-badge,
  .ts-badge--sm {
    margin-left: auto;
    margin-right: auto;
  }
  .ts-panel-name { align-items: center; text-align: center; }

  /* Extra side padding so tick numbers clear the card edge */
  .ts-knobs-row--ticked {
    padding-left: 20px;
    padding-right: 20px;
    padding-top: 28px;
  }

  /* Volume on its own row; all tone knobs share one row below.
     Equal size for every knob; even vertical/horizontal gaps.
     Group centers under the badge. */
  .ts-knobs-pair {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    align-content: center;
    align-items: flex-start;
    gap: 28px 14px;
    width: 100%;
    flex: 1 1 auto;
  }
  /* Same size for Volume and every tone knob */
  .ts-knobs-pair > .ts-ctl {
    width: 78px;
    flex: 0 0 78px;
  }
  /* Volume alone on the first row (full width, content centered) --
     except mobileSingleRow profiles (Bassman), which keep all knobs
     together in one row instead. */
  .ts-knobs-pair:not(.ts-knobs-pair--mobile-row) > .ts-ctl:first-child {
    flex: 1 0 100%;
    width: auto;
    display: flex;
    flex-direction: column;
    align-items: center;
  }
  /* Ticked profiles: uniform scale so 3 tone knobs fit one row */
  .ts-knobs-row--ticked .ts-knobs-pair > .ts-ctl .ts-knob-wrap {
    transform: scale(0.82);
    transform-origin: center center;
  }
  .ts-knobs-row--ticked .ts-knobs-pair > .ts-ctl .ts-knob-wrap + .ts-ctl-name {
    margin-top: 8px;
  }
  /* The 36px desktop gap (Bassman tick-safety) and the compact plate
     padding are both desktop-oriented fixes -- reset to mobile-sized
     values here, or Bassman's tone-trio row doesn't fit and Bass wraps
     to its own third row. */
  .ts-knobs-row--ticked .ts-knobs-pair--chrome {
    gap: 14px 8px;
  }
  .ts-knobs-pair--compact {
    padding: 24px 10px 12px !important;
  }
  /* mobileSingleRow (Bassman): all 4 knobs in one row needs smaller
     knobs, a tighter column width, and reduced plate padding than the
     3-knob-row default above -- the plate's own 36px side padding alone
     would otherwise eat most of the available mobile width. */
  .ts-knobs-row--ticked .ts-knobs-pair--mobile-row {
    flex-wrap: nowrap;
    gap: 18px;
    padding-left: 10px !important;
    padding-right: 10px !important;
  }
  .ts-knobs-pair--mobile-row > .ts-ctl {
    width: 44px;
    flex: 0 0 44px;
  }
  .ts-knobs-pair--mobile-row > .ts-ctl .ts-knob-wrap {
    transform: scale(0.46);
    transform-origin: center center;
  }
  .ts-knobs-pair--mobile-row > .ts-ctl .ts-knob-wrap + .ts-ctl-name {
    margin-top: -8px;
  }
  .ts-knobs-pair--mobile-row > .ts-ctl .ts-ctl-name,
  .ts-knobs-pair--mobile-row > .ts-ctl .ts-ctl-num {
    font-size: 9px;
  }
  /* Chrome-plate amps (Champ/AC4/AC30): keep plate centered */
  .ts-knobs-pair--chrome,
  .ts-knobs-pair--chrome-dark,
  .ts-knobs-pair--chrome-red,
  .ts-knobs-pair--narrow-outer,
  .ts-knobs-pair--narrow {
    width: auto;
    max-width: 100%;
    margin-left: auto;
    margin-right: auto;
  }
}

.ts-ctl { display: flex; flex-direction: column; align-items: center; gap: 6px; width: 84px; }
.ts-ctl[data-disabled="true"] { opacity: .45; }

.ts-knobs-row .ts-ctl-name {
  font-family: var(--tbc-font-display); font-size: 12px; font-weight: 600;
  letter-spacing: .06em; text-transform: uppercase; color: var(--face-text, #232427);
}

.ts-knob { position: relative; width: 64px; height: 64px; cursor: ns-resize; touch-action: none; border-radius: 50%; }

/* Static numbered dial ring -- Champ, Marshall, Vox/AC4. The ring sits
   behind the knob and never rotates; only the knob face does, same as a
   real chicken-head knob against a printed panel scale. */
.ts-knob-wrap { position: relative; width: 64px; height: 64px; }
.ts-knob-ticks { position: absolute; left: 50%; top: 50%; width: 0; height: 0; pointer-events: none; }
.ts-knob-tick-mark {
  position: absolute;
  width: 2px; height: 5px;
  border-radius: 1px;
  opacity: .95;
  box-shadow: 0 0 1.5px rgba(0, 0, 0, .7);
}
.ts-knob-tick-num {
  position: absolute;
  transform: translate(-50%, -50%);
  font: 700 8px var(--tbc-font-mono, monospace);
  line-height: 1;
  white-space: nowrap;
  text-shadow: 0 1px 2px rgba(0, 0, 0, .35);
}
/* The 0/10 tick labels sit at the bottom-left/bottom-right of the ring and
   overhang below the knob's own box -- push the name down clear of them
   (only when a tick ring is present; untouched otherwise). */
.ts-knob-wrap + .ts-ctl-name { margin-top: 16px; }
.ts-knob-face { display: block; width: 100%; height: 100%; pointer-events: none; user-select: none; -webkit-user-drag: none; }
.ts-knob:focus-visible { outline: 2px solid var(--tbc-glow); outline-offset: 3px; }
.ts-knob[aria-disabled="true"] { cursor: default; }

.ts-ctl-num { font: 700 12.5px var(--tbc-font-mono); color: var(--face-text, #232427); text-shadow: 0 1px 2px rgba(0,0,0,0.25); }

/* ── signal generator: same card treatment as the scope, wrapping the
   frequency-preset dropdown + the 7-segment LED readout ── */
.vs-siggen-card {
  background: rgb(69 69 69 / 80%);
  border: 1.5px solid #919191;
  border-radius: var(--tbc-radius-sm);
  padding: 16px;
  margin-bottom: 18px;
}
.vs-siggen-row {
  display: flex;
  align-items: flex-end;
  gap: 14px;
  margin-bottom: 0;
}
.vs-siggen-select { flex: 1 1 auto; min-width: 0; margin-bottom: 0; }

.vs-seg-card {
  flex: 0 0 auto;
  background: rgba(42, 33, 25, 0.8);
  border: 1px solid var(--tbc-border-soft);
  border-radius: var(--tbc-radius-sm);
  padding: 8px;
}
.vs-seg-frame {
  padding: 3px;
  border-radius: 5px;
  background: linear-gradient(155deg, #6b6d72 0%, #38393c 55%, #232427 100%);
  box-shadow: inset 0 1px 1px rgba(255,255,255,0.25), inset 0 -1px 1px rgba(0,0,0,0.5);
}
.vs-seg-panel {
  background: #0a0806;
  border-radius: 3px;
  padding: 7px 10px;
  display: flex;
  justify-content: center;
}
.vs-seg-display { display: flex; gap: 3px; }
.vs-seg-digit-svg { display: block; flex: none; }

@media (max-width: 640px) {
  .vs-siggen-row { flex-direction: column; align-items: stretch; }
  .vs-seg-card { align-self: center; }
}

@media (prefers-reduced-motion: reduce) {
  .vs-range, .ts-knob { transition: none !important; }
}

/* ==================================================================
   APP SHELL — standalone PWA layer
   ================================================================== */

/* ======================================================================
   Shared PWA app-shell layer — canonical source
   ----------------------------------------------------------------------
   Generic standalone-app chrome shared by every DiMastro GTA PWA
   (safe-area insets, .install-gate, .tbc-db-notice, and related
   install/offline UI). Written against the --tbc-* custom properties;
   each app's own :root block (in its own css/_head.css) either
   declares --tbc-* directly, or aliases its own token names to them.

   DO NOT EDIT apps/<name>/css/styles.css directly for anything in this
   section — edit this file instead, then run:
     python3 apps/_shared/sync-apps.py
   to regenerate every app's actual served styles.css. Edits made
   straight to a generated styles.css will be overwritten on next sync.

   Tool-specific widget CSS (the calculator itself) lives in each app's
   own css/_head.css and is untouched by this file or the sync script.
   ====================================================================== */

*, *::before, *::after { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  background: var(--tbc-bg);
  color: var(--tbc-ink);
  min-height: 100%;
  -webkit-tap-highlight-color: transparent;
  overscroll-behavior-y: none;
}

body {
  font-family: var(--tbc-font-body);
  /* Safe-area padding so content clears the iPhone notch / home
     indicator when running standalone (added to home screen). */
  padding-top: env(safe-area-inset-top);
  padding-bottom: env(safe-area-inset-bottom);
  padding-left: env(safe-area-inset-left);
  padding-right: env(safe-area-inset-right);
}

.app-header {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: calc(env(safe-area-inset-top) + 14px) 18px 14px;
  background: linear-gradient(180deg, rgba(28, 23, 18, 1) 0%, rgba(28, 23, 18, 0.94) 100%);
  border-bottom: 1px solid var(--tbc-border-soft);
  position: sticky;
  top: 0;
  z-index: 20;
}

.app-header img {
  width: 26px;
  height: 26px;
  border-radius: 6px;
}

.app-header h1 {
  font-family: var(--tbc-font-display);
  font-size: 16px;
  font-weight: 600;
  color: var(--tbc-ink);
  margin: 0;
  letter-spacing: 0.01em;
}

.app-header-brand {
  font-family: var(--tbc-font-display);
  font-size: 20px;
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--tbc-ink);
  margin-left: auto;
  white-space: nowrap;
}

.app-header-brand-gta {
  font-size: 20px;
  font-weight: 600;
  letter-spacing: 0.06em;
  color: var(--tbc-ink-faint);
}

main.app-main {
  padding: 20px 14px calc(40px + env(safe-area-inset-bottom));
}

/* the .tbc widget already caps at 760px and centers itself, this just
   removes its normal page-embedded spacing assumptions */
/* Tools with their own content wrapper (not .tbc) already set their
   own width in the section above — this rule only matters on tools
   that actually use .tbc for their widget. */

.app-footer {
  max-width: 960px;
  margin: 18px auto 0;
  padding: 0 4px;
  font-size: 11.5px;
  color: var(--tbc-ink-faint);
  text-align: center;
  line-height: 1.6;
}

.app-footer a { color: var(--tbc-glow-dim); }

/* Offline / update banners */
.app-banner {
  position: fixed;
  left: 14px;
  right: 14px;
  bottom: calc(14px + env(safe-area-inset-bottom));
  z-index: 50;
  display: none;
  align-items: center;
  gap: 10px;
  background: var(--tbc-panel-raised);
  border: 1px solid var(--tbc-border);
  border-radius: var(--tbc-radius-sm);
  padding: 12px 14px;
  font-size: 13px;
  color: var(--tbc-ink-muted);
  box-shadow: 0 12px 30px -12px rgba(0,0,0,0.6);
}

.app-banner.is-visible { display: flex; }

.app-banner button {
  margin-left: auto;
  background: var(--tbc-glow);
  color: #241a0f;
  border: none;
  border-radius: 999px;
  padding: 7px 14px;
  font-family: var(--tbc-font-display);
  font-weight: 600;
  font-size: 12.5px;
  cursor: pointer;
}

.app-banner .app-banner-dismiss {
  background: transparent;
  color: var(--tbc-ink-faint);
  padding: 7px 8px;
}

@media (max-width: 420px) {
  .app-header h1 { font-size: 14.5px; }
  .app-header-brand,
  .app-header-brand-gta { font-size: 16px; }
}

/* ==================================================================
   INSTALL GATE
   ================================================================== */

.install-gate {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  padding-top: calc(24px + env(safe-area-inset-top));
  padding-bottom: calc(24px + env(safe-area-inset-bottom));
  background:
    radial-gradient(120% 140% at 50% -10%, rgba(255, 145, 66, 0.10) 0%, transparent 55%),
    var(--tbc-bg);
}

.install-gate.is-hidden { display: none; }

.install-gate-card {
  max-width: 380px;
  width: 100%;
  text-align: center;
  background: var(--tbc-panel);
  border: 1px solid var(--tbc-border);
  border-radius: var(--tbc-radius);
  padding: 34px 26px 26px;
  box-shadow: 0 30px 60px -30px rgba(0, 0, 0, 0.7);
}

.install-gate-icon {
  width: 72px;
  height: 72px;
  border-radius: 16px;
  margin-bottom: 18px;
}

.install-gate-card h2 {
  font-family: var(--tbc-font-display);
  font-size: 20px;
  font-weight: 700;
  color: var(--tbc-ink);
  margin: 0 0 10px;
}

.install-gate-sub {
  font-size: 13.5px;
  color: var(--tbc-ink-muted);
  line-height: 1.6;
  margin: 0 0 24px;
}

.install-gate-btn {
  width: 100%;
  background: var(--tbc-glow);
  color: #241a0f;
  border: none;
  border-radius: 999px;
  padding: 13px 18px;
  font-family: var(--tbc-font-display);
  font-weight: 700;
  font-size: 15px;
  cursor: pointer;
  margin-bottom: 16px;
  transition: background-color 140ms ease;
}
.install-gate-btn:hover { background: var(--tbc-glow-dim); }

.install-gate-ios-hint {
  font-size: 13px;
  color: var(--tbc-ink-muted);
  background: rgba(34, 27, 21, 0.8);
  border: 1px solid var(--tbc-border-soft);
  border-radius: var(--tbc-radius);
  padding: 12px 14px;
  margin: 0 0 16px;
  line-height: 1.6;
}
.install-gate-ios-hint svg { vertical-align: -3px; margin: 0 2px; color: var(--tbc-glow); }
.install-gate-ios-hint strong { color: var(--tbc-ink); }

.install-gate.is-ios .install-gate-btn,
.install-gate.is-ios #installGateAndroidNotice,
.install-gate.is-ios .install-gate-ios-hint,
.install-gate.is-ios #dmPlatformRow {
  display: none !important;
}
.install-gate-ios-panel {
  text-align: left;
  background: rgba(34, 27, 21, 0.88);
  border: 1px solid var(--tbc-border-soft);
  border-radius: var(--tbc-radius);
  padding: 14px 16px 12px;
  margin: 0 0 18px;
  color: var(--tbc-ink-muted);
}
.install-gate-ios-lead {
  margin: 0 0 10px;
  font-size: 13.5px;
  line-height: 1.55;
  color: var(--tbc-ink);
}
.install-gate-ios-steps {
  margin: 0 0 10px;
  padding-left: 20px;
  font-size: 13.5px;
  line-height: 1.65;
  color: var(--tbc-ink-muted);
}
.install-gate-ios-steps li { margin: 0 0 8px; }
.install-gate-ios-steps li:last-child { margin-bottom: 0; }
.install-gate-ios-steps strong { color: var(--tbc-ink); }
.install-gate-ios-steps svg { vertical-align: -3px; margin: 0 2px; color: var(--tbc-glow); }
.install-gate-ios-note {
  margin: 0;
  font-size: 12px;
  line-height: 1.5;
  color: var(--tbc-ink-faint, var(--tbc-ink-muted));
  opacity: 0.9;
}




.install-gate-link {
  display: block;
  font-size: 13px;
  color: var(--tbc-glow-dim);
  text-decoration: underline;
  margin-bottom: 12px;
}
.install-gate-link:hover { color: var(--tbc-glow); }

.install-gate-back-btn {
  display: inline-block;
  margin-top: 6px;
  padding: 5px 12px;
  font-size: 11.5px;
  color: var(--tbc-ink-faint);
  background: rgba(205, 156, 96, 0.14);
  border: 1px solid rgba(205, 156, 96, 0.35);
  border-radius: 999px;
  text-decoration: none;
}
.install-gate-back-btn:hover {
  background: rgba(205, 156, 96, 0.22);
  color: var(--tbc-ink);
}

.install-gate-skip {
  display: inline-block;
  background: rgba(77, 163, 255, 0.14);
  border: 1px solid rgba(77, 163, 255, 0.35);
  color: var(--tbc-cold);
  font-size: 12px;
  cursor: pointer;
  text-decoration: none;
  border-radius: 999px;
  padding: 6px 14px;
  margin-bottom: 10px;
}
.install-gate-skip:hover { background: rgba(77, 163, 255, 0.22); color: var(--tbc-ink); }

.tbc-db-notice {
  display: flex;
  gap: 10px;
  align-items: flex-start;
  background: var(--tbc-warn-soft);
  border: 1px solid rgba(231, 184, 79, 0.35);
  border-radius: var(--tbc-radius-sm);
  padding: 10px 14px;
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--tbc-ink-muted);
  margin-bottom: 22px;
}
.tbc-db-notice[hidden] { display: none; }
.tbc-db-notice svg { flex: none; margin-top: 2px; color: var(--tbc-warn); }
.tbc-db-notice strong { color: var(--tbc-warn); }


/* Export CSV / PNG */
.tbc-export-row {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 12px 0 10px;
  justify-content: flex-end;
}
.tbc-export-btn {
  appearance: none;
  border: 1px solid var(--tbc-border);
  background: var(--tbc-panel-raised);
  color: var(--tbc-ink);
  font-family: var(--tbc-font-body);
  font-size: 13px;
  font-weight: 600;
  padding: 8px 14px;
  border-radius: 999px;
  cursor: pointer;
}
.tbc-export-btn:hover {
  border-color: var(--tbc-glow);
  color: var(--tbc-glow);
}
.tbc-export-btn:active { transform: scale(0.98); }

/* Title on its own full-width row so it does not wrap beside the badge */
#virtual-oscilloscope > .tbc-header {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 8px;
}
#virtual-oscilloscope .tbc-header-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}
#virtual-oscilloscope .tbc-title {
  width: 100%;
  max-width: none;
  white-space: nowrap;
  font-size: clamp(18px, 5.8vw, 26px);
  line-height: 1.2;
  margin: 0 0 2px;
}
#virtual-oscilloscope .tbc-sub {
  max-width: none;
  width: 100%;
}

/* Brand badges — same chrome pills as Tone Stack Simulator */
.vo-amp-pick { display: flex; flex-direction: column; gap: 12px; }
.vo-brand-tabs {
  display: flex;
  flex-wrap: nowrap;
  gap: 6px;
}
.vo-brand-tabs button {
  flex: 1 1 0;
  min-width: 0;
  font-family: var(--tbc-font-display);
  color: var(--tbc-ink-faint);
  background: linear-gradient(180deg, #2a2a2c 0%, #161616 55%, #0a0a0a 100%);
  border: 1px solid #000;
  border-radius: 10px;
  padding: 8px 8px;
  min-height: 44px;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  box-shadow: 0 2px 5px rgba(0, 0, 0, .5), inset 0 1px 0 rgba(255, 255, 255, .1), inset 0 -3px 4px rgba(0, 0, 0, .55);
}
.vo-brand-tabs button[aria-selected="true"] {
  background: linear-gradient(180deg, var(--tab-hi, #d2d5df) 0%, var(--tab-mid, #bfbfc5) 55%, var(--tab-lo, #898885) 100%);
  border-color: var(--tab-outline, #498aa5);
  box-shadow: 0 2px 6px rgba(0, 0, 0, .45), inset 0 1px 0 rgba(255, 255, 255, .4), inset 0 -2px 3px rgba(0, 0, 0, .2);
}
.vo-brand-badge {
  height: 22px;
  width: auto;
  max-width: 100%;
  object-fit: contain;
  display: block;
  filter: brightness(1.25) contrast(1.05) drop-shadow(0 1px 1px rgba(0, 0, 0, .6));
}
.vo-brand-tabs button[data-key="fender"] .vo-brand-badge {
  filter: brightness(1.7) contrast(1.05) drop-shadow(0 1px 1px rgba(0, 0, 0, .6));
}
.vo-brand-tabs button[data-key="vox"] .vo-brand-badge,
.vo-brand-tabs button[aria-selected="true"][data-key="vox"] .vo-brand-badge {
  filter: brightness(.82) contrast(1.05) drop-shadow(0 1px 1px rgba(0, 0, 0, .6));
}
