/*
 * ToneLogs design tokens and project styles.
 *
 * This file is the maintained source. There is no Sass, Node, or frontend
 * build pipeline. Token values are owned by docs/design/visual-system.md;
 * change them there first. See ADR 0071.
 *
 * Load order matters: this file follows Bootstrap, so the retheme block
 * below can remap Bootstrap's own custom properties onto these tokens.
 */

:root {
  /* Surfaces */
  --tl-canvas: #ffffff;
  --tl-surface-sunken: #f5f7f8;
  --tl-surface-navbar: #e9ecef;

  /* Text */
  --tl-ink: #172126;
  --tl-ink-muted: #52616a;

  /* Action */
  --tl-primary: #0b6170;
  --tl-primary-hover: #084c58;
  --tl-primary-tint: #e4f1f3;

  /* Status */
  --tl-info-ink: #1d5f8a;
  --tl-info-tint: #e9f2f8;
  --tl-success-ink: #216e49;
  --tl-success-tint: #e7f3ec;
  --tl-warning-ink: #765000;
  --tl-warning-tint: #fff3d6;
  --tl-danger-ink: #a12a2a;
  --tl-danger-tint: #fbeaea;
  --tl-neutral-ink: #3f4d55;
  --tl-neutral-tint: #edf1f3;

  /*
   * Filled-control hover states, derived by darkening the matching ink so a
   * filled button has a hover step. Kept as literals because CSS has no
   * build-time color function in this stack.
   */
  --tl-success-hover: #1a5839;
  --tl-danger-hover: #832222;

  /* Boundaries */
  --tl-focus: #08788c;
  --tl-border-control: #788991;
  --tl-border-subtle: #c9d2d7;

  /* Plots */
  --tl-plot-axis: #45545d;
  --tl-plot-grid: #e3e8ea;

  /*
   * Plot selection overlay, applied by Plotly through JavaScript. Kept as an
   * rgb triple so alpha variants stay in one place.
   */
  --tl-selection-rgb: 11, 97, 112;
  --tl-selection-fill: rgba(var(--tl-selection-rgb), 0.18);
  --tl-selection-line: rgba(var(--tl-selection-rgb), 0.95);

  /* Typography */
  --tl-font-sans: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue",
    "Noto Sans", "Liberation Sans", Arial, sans-serif, "Apple Color Emoji",
    "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
  --tl-font-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas,
    "Liberation Mono", monospace;
  --tl-text-2xs: 0.75rem;
  --tl-text-xs: 0.8125rem;
  --tl-text-sm: 0.875rem;
  --tl-text-md: 1rem;
  --tl-text-lg: 1.125rem;
  --tl-text-xl: 1.25rem;
  --tl-text-2xl: 1.5rem;
  --tl-text-3xl: 1.875rem;
  --tl-text-display: 3rem;

  /* Spacing */
  --tl-space-1: 4px;
  --tl-space-2: 8px;
  --tl-space-3: 16px;
  --tl-space-4: 24px;
  --tl-space-5: 32px;
  --tl-space-6: 48px;

  /* Radii, borders, elevation */
  --tl-radius-sm: 0.25rem;
  --tl-radius-md: 0.5rem;
  --tl-radius-lg: 0.75rem;
  --tl-border-width: 1px;
  --tl-border-accent-width: 4px;
  --tl-shadow-1: 0 1px 2px rgba(23, 33, 38, 0.08);
  --tl-shadow-2: 0 0.5rem 1.25rem rgba(23, 33, 38, 0.15);

  /* Motion */
  --tl-motion-fast: 120ms;
  --tl-motion-base: 200ms;
  --tl-motion-ease: ease-out;
}

/* ==========================================================================
 * Bootstrap retheme
 *
 * Bootstrap 5.2 bakes its palette into component rules, so tokens only take
 * effect where its custom properties are remapped. Class names stay unchanged
 * because templates, JavaScript, and browser tests depend on them.
 * ========================================================================== */

:root {
  --bs-body-bg: var(--tl-canvas);
  --bs-body-color: var(--tl-ink);
  --bs-body-font-family: var(--tl-font-sans);
  --bs-font-sans-serif: var(--tl-font-sans);
  --bs-font-monospace: var(--tl-font-mono);
  --bs-border-color: var(--tl-border-subtle);
  --bs-link-color: var(--tl-primary);
  --bs-link-hover-color: var(--tl-primary-hover);
  --bs-border-radius: var(--tl-radius-sm);
  --bs-border-radius-sm: var(--tl-radius-sm);
  --bs-border-radius-lg: var(--tl-radius-md);
}

.text-muted {
  color: var(--tl-ink-muted) !important;
}

.text-primary {
  color: var(--tl-primary) !important;
}

.btn-primary {
  --bs-btn-color: var(--tl-canvas);
  --bs-btn-bg: var(--tl-primary);
  --bs-btn-border-color: var(--tl-primary);
  --bs-btn-hover-color: var(--tl-canvas);
  --bs-btn-hover-bg: var(--tl-primary-hover);
  --bs-btn-hover-border-color: var(--tl-primary-hover);
  --bs-btn-active-color: var(--tl-canvas);
  --bs-btn-active-bg: var(--tl-primary-hover);
  --bs-btn-active-border-color: var(--tl-primary-hover);
  --bs-btn-disabled-color: var(--tl-canvas);
  --bs-btn-disabled-bg: var(--tl-primary);
  --bs-btn-disabled-border-color: var(--tl-primary);
}

.btn-outline-primary {
  --bs-btn-color: var(--tl-primary);
  --bs-btn-border-color: var(--tl-primary);
  --bs-btn-hover-color: var(--tl-canvas);
  --bs-btn-hover-bg: var(--tl-primary);
  --bs-btn-hover-border-color: var(--tl-primary);
  --bs-btn-active-color: var(--tl-canvas);
  --bs-btn-active-bg: var(--tl-primary-hover);
  --bs-btn-active-border-color: var(--tl-primary-hover);
  --bs-btn-disabled-color: var(--tl-primary);
  --bs-btn-disabled-border-color: var(--tl-primary);
}

.btn-secondary,
.btn-outline-secondary {
  --bs-btn-color: var(--tl-ink);
  --bs-btn-bg: transparent;
  --bs-btn-border-color: var(--tl-border-control);
  --bs-btn-hover-color: var(--tl-ink);
  --bs-btn-hover-bg: var(--tl-surface-sunken);
  --bs-btn-hover-border-color: var(--tl-ink-muted);
  --bs-btn-active-color: var(--tl-ink);
  --bs-btn-active-bg: var(--tl-neutral-tint);
  --bs-btn-active-border-color: var(--tl-ink-muted);
  --bs-btn-disabled-color: var(--tl-ink-muted);
  --bs-btn-disabled-bg: transparent;
  --bs-btn-disabled-border-color: var(--tl-border-control);
}

/*
 * Amber never carries white text, so the warning action is an amber-tinted
 * control with amber ink and an amber boundary. See visual-system.md.
 */
.btn-warning {
  --bs-btn-color: var(--tl-warning-ink);
  --bs-btn-bg: var(--tl-warning-tint);
  --bs-btn-border-color: var(--tl-warning-ink);
  --bs-btn-hover-color: var(--tl-warning-ink);
  --bs-btn-hover-bg: var(--tl-warning-tint);
  --bs-btn-hover-border-color: var(--tl-warning-ink);
  --bs-btn-active-color: var(--tl-warning-ink);
  --bs-btn-active-bg: var(--tl-warning-tint);
  --bs-btn-active-border-color: var(--tl-warning-ink);
  --bs-btn-disabled-color: var(--tl-warning-ink);
  --bs-btn-disabled-bg: var(--tl-warning-tint);
  --bs-btn-disabled-border-color: var(--tl-warning-ink);
}

/*
 * Filled danger means capture in the recorder and destructive elsewhere.
 * Outline danger always means discard or delete. See ADR 0072.
 */
.btn-danger {
  --bs-btn-color: var(--tl-canvas);
  --bs-btn-bg: var(--tl-danger-ink);
  --bs-btn-border-color: var(--tl-danger-ink);
  --bs-btn-hover-color: var(--tl-canvas);
  --bs-btn-hover-bg: var(--tl-danger-hover);
  --bs-btn-hover-border-color: var(--tl-danger-hover);
  --bs-btn-active-color: var(--tl-canvas);
  --bs-btn-active-bg: var(--tl-danger-hover);
  --bs-btn-active-border-color: var(--tl-danger-hover);
  --bs-btn-disabled-color: var(--tl-canvas);
  --bs-btn-disabled-bg: var(--tl-danger-ink);
  --bs-btn-disabled-border-color: var(--tl-danger-ink);
}

.btn-outline-danger {
  --bs-btn-color: var(--tl-danger-ink);
  --bs-btn-border-color: var(--tl-danger-ink);
  --bs-btn-hover-color: var(--tl-canvas);
  --bs-btn-hover-bg: var(--tl-danger-ink);
  --bs-btn-hover-border-color: var(--tl-danger-ink);
  --bs-btn-active-color: var(--tl-canvas);
  --bs-btn-active-bg: var(--tl-danger-hover);
  --bs-btn-active-border-color: var(--tl-danger-hover);
  --bs-btn-disabled-color: var(--tl-danger-ink);
  --bs-btn-disabled-border-color: var(--tl-danger-ink);
}

.btn-success {
  --bs-btn-color: var(--tl-canvas);
  --bs-btn-bg: var(--tl-success-ink);
  --bs-btn-border-color: var(--tl-success-ink);
  --bs-btn-hover-color: var(--tl-canvas);
  --bs-btn-hover-bg: var(--tl-success-hover);
  --bs-btn-hover-border-color: var(--tl-success-hover);
  --bs-btn-active-color: var(--tl-canvas);
  --bs-btn-active-bg: var(--tl-success-hover);
  --bs-btn-active-border-color: var(--tl-success-hover);
}

/* Status pairs: severity ink on severity tint, never white on amber. */
.text-bg-primary {
  color: var(--tl-primary) !important;
  background-color: var(--tl-primary-tint) !important;
}

.text-bg-info {
  color: var(--tl-info-ink) !important;
  background-color: var(--tl-info-tint) !important;
}

.text-bg-success {
  color: var(--tl-success-ink) !important;
  background-color: var(--tl-success-tint) !important;
}

.text-bg-warning {
  color: var(--tl-warning-ink) !important;
  background-color: var(--tl-warning-tint) !important;
}

.text-bg-danger {
  color: var(--tl-danger-ink) !important;
  background-color: var(--tl-danger-tint) !important;
}

.text-bg-light,
.text-bg-secondary {
  color: var(--tl-neutral-ink) !important;
  background-color: var(--tl-neutral-tint) !important;
}

/*
 * Badges absorb longer German and French labels by wrapping. Bootstrap keeps
 * them on one line, which truncated the Calibration state at 320px even though
 * that column must survive every width.
 */
.badge {
  white-space: normal;
}

.alert-primary {
  --bs-alert-color: var(--tl-primary);
  --bs-alert-bg: var(--tl-primary-tint);
  --bs-alert-border-color: var(--tl-primary);
}

.alert-info {
  --bs-alert-color: var(--tl-info-ink);
  --bs-alert-bg: var(--tl-info-tint);
  --bs-alert-border-color: var(--tl-info-ink);
}

.alert-success {
  --bs-alert-color: var(--tl-success-ink);
  --bs-alert-bg: var(--tl-success-tint);
  --bs-alert-border-color: var(--tl-success-ink);
}

.alert-warning {
  --bs-alert-color: var(--tl-warning-ink);
  --bs-alert-bg: var(--tl-warning-tint);
  --bs-alert-border-color: var(--tl-warning-ink);
}

.alert-danger,
.alert-error {
  --bs-alert-color: var(--tl-danger-ink);
  --bs-alert-bg: var(--tl-danger-tint);
  --bs-alert-border-color: var(--tl-danger-ink);
  color: var(--tl-danger-ink);
  background-color: var(--tl-danger-tint);
  border-color: var(--tl-danger-ink);
}

/* Django emits an `error` message tag, which Bootstrap does not define. */
.alert-debug {
  --bs-alert-color: var(--tl-neutral-ink);
  --bs-alert-bg: var(--tl-neutral-tint);
  --bs-alert-border-color: var(--tl-neutral-ink);
  color: var(--tl-neutral-ink);
  background-color: var(--tl-neutral-tint);
  border-color: var(--tl-neutral-ink);
}

.form-control,
.form-select {
  border-color: var(--tl-border-control);
}

/* ==========================================================================
 * Focus
 *
 * One global ring. Bootstrap's own focus shadows are removed so a focused
 * control never shows two competing rings.
 * ========================================================================== */

:focus-visible {
  outline: 2px solid var(--tl-focus);
  outline-offset: 2px;
}

.form-control:focus,
.form-select:focus,
.form-check-input:focus {
  border-color: var(--tl-focus);
  outline: 2px solid var(--tl-focus);
  outline-offset: 2px;
}

.btn:focus-visible,
.btn-close:focus,
.form-control:focus,
.form-select:focus,
.form-check-input:focus,
.btn-check:focus + .btn {
  box-shadow: none;
}

/* ==========================================================================
 * Project styles
 * ========================================================================== */

body {
  background-color: var(--tl-canvas);
}

/*
 * Icons are sized in em so each one matches its adjacent text size and color,
 * and never shrink inside a flex action group.
 */
.tl-icon {
  width: 1em;
  height: 1em;
  flex: none;
  vertical-align: -0.125em;
}

.app-navbar {
  background-color: var(--tl-surface-navbar);
}

/* ==========================================================================
 * Shared components
 * ========================================================================== */

/*
 * Skip link: out of the layout until focused, then a real target at the top
 * left of the viewport.
 */
.tl-skip-link {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  white-space: nowrap;
  clip-path: inset(50%);
}

.tl-skip-link:focus {
  position: fixed;
  top: var(--tl-space-2);
  left: var(--tl-space-2);
  z-index: 1090;
  width: auto;
  height: auto;
  padding: var(--tl-space-2) var(--tl-space-3);
  margin: 0;
  overflow: visible;
  clip-path: none;
  color: var(--tl-primary);
  background: var(--tl-canvas);
  border: var(--tl-border-width) solid var(--tl-primary);
  border-radius: var(--tl-radius-sm);
}

.tl-page-header {
  margin-bottom: var(--tl-space-4);
}

.tl-eyebrow {
  margin-bottom: var(--tl-space-1);
  font-size: var(--tl-text-2xs);
  font-weight: 600;
  color: var(--tl-ink-muted);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

/*
 * Baseline, not centre: the action group is a flex item whose baseline comes
 * from its first button's text baseline, so it lines up with the title's
 * first line however many lines the title wraps to.
 */
.tl-page-header-row {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--tl-space-3);
}

/* Object state sits beside the title and shares its baseline. */
.tl-page-header-heading {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--tl-space-2);
  min-width: 0;
}

.tl-page-header-title {
  min-width: 0;
  margin-bottom: 0;
  font-size: var(--tl-text-2xl);
  font-weight: 600;
  line-height: 1.25;
}

.tl-page-header-meta {
  margin-top: var(--tl-space-2);
  margin-bottom: 0;
  font-size: var(--tl-text-sm);
  color: var(--tl-ink-muted);
}

/*
 * A title with a pencil keeps both on one row: the title wraps its own text,
 * even a long unbroken word, instead of pushing the pencil onto a line of its
 * own or running under it.
 */
.tl-page-header-heading-editable {
  flex-wrap: nowrap;
}

.tl-page-header-heading-editable .tl-page-header-title {
  overflow-wrap: anywhere;
}

/*
 * The pencil centres on the title. Its negative margins keep the 44px target
 * from making the title row taller than the title.
 */
.tl-page-header-edit {
  align-self: center;
  margin-block: calc(-1 * var(--tl-space-2));
}

/*
 * Icon-only control: a small icon centred in a 44px touch target, with no box
 * of its own until hover, so it stays quiet beside what it acts on.
 */
.tl-icon-button {
  display: inline-flex;
  flex: none;
  align-items: center;
  justify-content: center;
  width: 2.75rem;
  height: 2.75rem;
  font-size: var(--tl-text-2xl);
  color: var(--tl-ink-muted);
  border-radius: var(--tl-radius-sm);
  transition: color var(--tl-motion-fast) var(--tl-motion-ease),
    background-color var(--tl-motion-fast) var(--tl-motion-ease);
}

.tl-icon-button:hover {
  color: var(--tl-primary);
  background-color: var(--tl-primary-tint);
}

/* Action groups wrap to a new line rather than shrinking or dropping labels. */
.tl-action-group {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--tl-space-2);
}

.tl-action-group-end {
  justify-content: flex-end;
}

.tl-action-group-start {
  justify-content: flex-start;
}

.tl-action-group-between {
  justify-content: space-between;
  width: 100%;
}

/*
 * Form actions: one row at the end of the form, separated from the last field
 * so a submit is never mistaken for another field. Cancel and submit alignment
 * comes from the shared action-group rules above.
 */
.tl-form-actions {
  margin-top: var(--tl-space-4);
}

/*
 * Notice: left accent, severity icon, body. Info carries the lowest visual
 * weight of the three so it never competes with measurements.
 */
.tl-notice {
  display: flex;
  gap: var(--tl-space-2);
  padding: var(--tl-space-3);
  margin-bottom: var(--tl-space-3);
  border: var(--tl-border-width) solid;
  border-left-width: var(--tl-border-accent-width);
  border-radius: var(--tl-radius-md);
}

.tl-notice > :last-child > :last-child {
  margin-bottom: 0;
}

.tl-notice-icon {
  display: flex;
  flex: none;
  align-items: center;
  height: calc(1.5 * var(--tl-text-md));
  font-size: var(--tl-text-lg);
}

.tl-notice-content {
  min-width: 0;
}

.tl-notice-title {
  margin-bottom: var(--tl-space-1);
  font-weight: 600;
}

.tl-notice-info {
  color: var(--tl-info-ink);
  background: var(--tl-info-tint);
  border-color: var(--tl-info-ink);
}

.tl-notice-success {
  color: var(--tl-success-ink);
  background: var(--tl-success-tint);
  border-color: var(--tl-success-ink);
}

.tl-notice-warning {
  color: var(--tl-warning-ink);
  background: var(--tl-warning-tint);
  border-color: var(--tl-warning-ink);
}

.tl-notice-danger {
  color: var(--tl-danger-ink);
  background: var(--tl-danger-tint);
  border-color: var(--tl-danger-ink);
}

.tl-notice a {
  color: inherit;
}

/* Sections are structural headings, not cards or tinted boxes. */
.tl-section {
  margin-bottom: var(--tl-space-5);
}

.tl-section-title {
  margin-bottom: var(--tl-space-1);
}

/*
 * Confirmation facts: the concrete values a user checks before an irreversible
 * action. Compact and muted, so the consequence sentence above stays the
 * loudest line in the notice.
 */
.tl-confirm-facts {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--tl-space-1) var(--tl-space-3);
  font-size: var(--tl-text-sm);
}

.tl-confirm-facts dt {
  font-weight: 600;
  color: var(--tl-ink-muted);
}

.tl-confirm-facts dd {
  margin-bottom: 0;
}

/* Inline help: one short sentence, muted, no icon, border, or panel. */
.tl-inline-help {
  margin-bottom: var(--tl-space-3);
  font-size: var(--tl-text-sm);
  color: var(--tl-ink-muted);
}

/* Detached by spacing and a danger boundary, at the end of the page. */
.tl-danger-zone {
  padding: var(--tl-space-3);
  margin-top: var(--tl-space-6);
  border: var(--tl-border-width) solid var(--tl-danger-ink);
  border-radius: var(--tl-radius-md);
}

.tl-danger-zone-title {
  margin-bottom: var(--tl-space-1);
  color: var(--tl-danger-ink);
}

.tl-danger-zone-consequence {
  margin-bottom: var(--tl-space-3);
  font-size: var(--tl-text-sm);
  color: var(--tl-ink-muted);
}

.tl-value {
  font-family: var(--tl-font-mono);
  font-variant-numeric: tabular-nums;
}

/* One heading scale, so a section heading is the same size on every page. */
.tl-heading-section {
  font-size: var(--tl-text-xl);
  font-weight: 600;
  line-height: 1.25;
}

.tl-heading-subsection {
  font-size: var(--tl-text-lg);
  font-weight: 600;
  line-height: 1.25;
}

.plotly-graph-div {
  min-height: 420px;
}

.page-shell {
  padding-bottom: var(--tl-space-6);
}

/* Site footer: the legal links, below every page and never printed. */
.tl-site-footer {
  border-top: var(--tl-border-width) solid var(--tl-border-subtle);
  font-size: var(--tl-text-sm);
}

.tl-site-footer-links {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0 var(--tl-space-4);
  padding: var(--tl-space-2) 0;
  margin: 0;
  list-style: none;
}

.tl-site-footer-links a {
  display: inline-block;
  padding: var(--tl-space-1) 0;
  color: var(--tl-ink-muted);
}

.tl-site-footer-links a:hover {
  color: var(--tl-ink);
}

.tone-log-detail-page,
.plot-section-figure,
.plot-target {
  min-width: 0;
}

.tone-log-detail-page {
  max-width: 1680px;
  margin-right: auto;
  margin-left: auto;
}

.plot-target {
  overflow-x: auto;
}

.signal-overview .plotly-graph-div {
  min-height: 120px;
}

.spectrum-overview .plotly-graph-div,
.spectrogram-overview .plotly-graph-div,
.level-time-overview .plotly-graph-div {
  min-height: 120px;
}

.plot-panel.is-updating .plot-target {
  opacity: 0.72;
}

/*
 * Band Level Readout below the Band spectrum, ADR 0098: a bordered box with
 * rounded corners, as wide as its content and flush right with the figure,
 * with every line inside flush right too. No tint, so the box survives print.
 * Calibrated and relative values share one style and differ only in unit
 * text and the uncalibrated status.
 */
.tl-band-levels {
  width: fit-content;
  max-width: 100%;
  padding: var(--tl-space-2) var(--tl-space-3);
  margin-top: var(--tl-space-3);
  margin-left: auto;
  text-align: right;
  border: var(--tl-border-width) solid var(--tl-border-subtle);
  border-radius: var(--tl-radius-md);
}

.tl-band-levels p {
  margin-bottom: 0;
}

.tl-band-levels .tl-band-levels-status {
  margin-top: var(--tl-space-2);
}

.tl-band-levels-status .badge {
  display: inline-flex;
  align-items: center;
  gap: var(--tl-space-1);
}

.tl-band-levels-label {
  font-size: var(--tl-text-xs);
  font-weight: 500;
  color: var(--tl-ink-muted);
}

.tl-band-levels-value {
  font-size: var(--tl-text-3xl);
  font-weight: 600;
  line-height: 1.25;
  color: var(--tl-ink);
}

.tl-band-levels-scope {
  font-size: var(--tl-text-xs);
  color: var(--tl-ink-muted);
}

/*
 * Always two lines, the Z-weighted level and then the time region and band
 * range, so the small text never sets the box width.
 */
.tl-band-levels-scope-part {
  display: block;
}

.tl-band-levels-scope .tl-value {
  white-space: nowrap;
}

.language-switcher .btn {
  min-width: 2.25rem;
  padding-right: 0.45rem;
  padding-left: 0.45rem;
}

.brand-logo {
  display: block;
}

/* Icon and label stay on one line and keep a mis-tap-safe gap. */
.tl-nav-link {
  display: inline-flex;
  align-items: center;
  gap: var(--tl-space-2);
}

.app-navbar .nav-link.active {
  font-weight: 600;
  color: var(--tl-primary);
  box-shadow: inset 0 -2px 0 var(--tl-primary);
}

.detail-collapse > summary {
  cursor: pointer;
  font-weight: 600;
  list-style-position: inside;
}

.tone-logs-message-stack {
  position: fixed;
  top: 4.5rem;
  right: var(--tl-space-3);
  z-index: 1080;
  width: min(24rem, calc(100vw - 2rem));
  pointer-events: none;
}

.tone-logs-floating-message {
  pointer-events: auto;
  box-shadow: var(--tl-shadow-2);
}

.tone-log-measurement-chain {
  background: var(--tl-surface-sunken);
  border-color: var(--tl-border-subtle);
}

.tone-log-detail-header .btn svg {
  vertical-align: -0.125em;
}

/* The Note under the analysis title: compact, unboxed, and short-lined. */
.tone-log-note {
  max-width: 48rem;
  margin-top: var(--tl-space-3);
}

.tone-log-note-heading {
  margin-bottom: var(--tl-space-1);
}

.tone-log-note-text {
  margin-bottom: 0;
}

/*
 * The analysis title is the largest text in the product, but it stays inside
 * the type scale: it never exceeds the size reserved for the landing hero.
 */
.tone-log-detail-title {
  font-size: clamp(var(--tl-text-2xl), 1.2rem + 1.4vw, var(--tl-text-3xl));
}

.detail-info-table > :not(caption) > * > * {
  border-bottom-color: var(--tl-border-subtle);
}

.detail-info-table th {
  width: 12rem;
  color: var(--tl-ink-muted);
  white-space: nowrap;
}

.sortable-heading {
  color: inherit;
  text-decoration: none;
}

.sortable-heading:hover,
.sortable-heading:focus {
  color: inherit;
  text-decoration: underline;
  text-underline-offset: 0.15em;
}

.plot-section-controls {
  background: var(--tl-surface-sunken);
}

.plot-control-group-heading {
  padding-top: 0.75rem;
  margin-top: 0.75rem;
  color: var(--tl-ink-muted);
  border-top: var(--tl-border-width) solid var(--tl-border-subtle);
}

/* Lines separate groups; the group that opens a panel has none above it. */
.plot-control-group-heading:first-child {
  padding-top: 0;
  margin-top: 0;
  border-top: 0;
}

.new-tone-log-choice {
  border-color: var(--tl-border-subtle);
}

.equipment-card {
  border-color: var(--tl-border-subtle);
  transition: border-color var(--tl-motion-fast) var(--tl-motion-ease),
    box-shadow var(--tl-motion-fast) var(--tl-motion-ease);
}

.equipment-card:hover,
.equipment-card:focus-within {
  border-color: var(--tl-primary);
  box-shadow: var(--tl-shadow-1);
}

/*
 * One real anchor per row, in the title cell, and nothing else in the row
 * navigates. See ADR 0073. The anchor fills its own cell so the pointer target
 * stays large without intercepting clicks meant for the rest of the row.
 */
.tone-log-row-link {
  display: block;
  padding-block: var(--tl-space-1);
  color: inherit;
  text-decoration: none;
}

.tone-log-row-link:hover,
.tone-log-row-link:focus {
  color: var(--tl-primary);
  text-decoration: underline;
  text-underline-offset: 0.15em;
}

/*
 * Column priority: narrow screens keep Title, Created, and Calibration, since
 * Calibration carries the row's interpretive meaning. See visual-system.md.
 */
.tl-col-md,
.tl-col-lg {
  display: none;
}

@media (min-width: 768px) {
  .tl-col-md {
    display: table-cell;
  }
}

@media (min-width: 992px) {
  .tl-col-lg {
    display: table-cell;
  }
}

/* Keeps an invite link readable; narrow screens scroll the table instead. */
.tl-invite-link {
  min-width: 18rem;
}

.new-tone-log-or {
  position: absolute;
  top: 50%;
  left: 50%;
  z-index: 2;
  align-items: center;
  justify-content: center;
  width: 2.5rem;
  height: 2.5rem;
  font-size: var(--tl-text-sm);
  color: var(--tl-ink-muted);
  background: var(--tl-canvas);
  border: var(--tl-border-width) solid var(--tl-border-subtle);
  border-radius: 50%;
  transform: translate(-50%, -50%);
}

.new-tone-log-or-mobile span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.5rem;
  height: 2.5rem;
  font-size: var(--tl-text-sm);
  color: var(--tl-ink-muted);
  border: var(--tl-border-width) solid var(--tl-border-subtle);
  border-radius: 50%;
}

.new-tone-log-upload-dashboard {
  width: min(100%, 320px);
  margin-right: auto;
  margin-left: auto;
}

.new-tone-log-upload-dashboard .UppyDashboard-inner,
.new-tone-log-upload-dashboard .uppy-Dashboard-inner {
  width: 100% !important;
  max-width: 320px !important;
  height: 320px !important;
  min-height: 0 !important;
  margin-right: auto;
  margin-left: auto;
}

.recording-upload-progress .UppyDashboard-inner,
.recording-upload-progress .uppy-Dashboard-inner {
  min-height: 220px;
}

/* Drop zone around the native file input of the UMIK calibration-file import. */
.tl-file-drop {
  padding: var(--tl-space-4);
  text-align: center;
  background: var(--tl-surface-sunken);
  border: 2px dashed var(--tl-border-control);
  border-radius: var(--tl-radius-md);
}

.tl-file-drop:focus-within,
.tl-file-drop.is-dragover {
  background: var(--tl-primary-tint);
  border-color: var(--tl-focus);
}

.tone-logs-recorder {
  min-width: 0;
}

.tone-logs-recorder-timer {
  margin-bottom: 0.35rem;
  font-family: var(--tl-font-mono);
  font-size: clamp(1.4rem, 1.1rem + 1vw, 2rem);
  font-variant-numeric: tabular-nums;
  font-weight: 600;
  letter-spacing: 0.04em;
}

.tone-logs-recorder-status {
  min-height: 1.5rem;
}

.tone-logs-recorder-start,
.tone-logs-recorder-active,
.tone-logs-recorder-review {
  display: none;
}

.tone-logs-recorder[data-state="idle"] .tone-logs-recorder-start,
.tone-logs-recorder[data-state="failure"] .tone-logs-recorder-start,
.tone-logs-recorder[data-state="recording"] .tone-logs-recorder-active,
.tone-logs-recorder[data-state="review"] .tone-logs-recorder-review {
  display: block;
}

.tone-logs-recorder[data-state="requesting-permission"],
.tone-logs-recorder[data-state="stopping-encoding"],
.tone-logs-recorder[data-state="uploading"] {
  cursor: progress;
}

.tone-logs-recorder-primary-action {
  min-width: 12rem;
  min-height: 3.25rem;
  font-size: var(--tl-text-lg);
  font-weight: 600;
}

.tone-logs-recorder-review audio {
  display: block;
  min-width: 0;
}

.tone-logs-recorder-review-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
}

.tone-logs-recorder-report-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--tl-space-2);
  margin-top: var(--tl-space-2);
}

.tone-logs-recorder-diagnostics {
  max-width: 100%;
  max-height: 32rem;
  padding: var(--tl-space-3);
  overflow: auto;
  background: var(--tl-surface-sunken);
  border: var(--tl-border-width) solid var(--tl-border-subtle);
  border-radius: var(--tl-radius-md);
}

@media (max-width: 575.98px) {
  .tone-logs-message-stack {
    top: 4.5rem;
    right: 0.75rem;
    left: 0.75rem;
    width: auto;
  }

  .new-tone-log-upload-dashboard,
  .new-tone-log-upload-dashboard .UppyDashboard-inner,
  .new-tone-log-upload-dashboard .uppy-Dashboard-inner {
    max-width: 280px !important;
  }

  .new-tone-log-upload-dashboard .UppyDashboard-inner,
  .new-tone-log-upload-dashboard .uppy-Dashboard-inner {
    height: 280px !important;
  }

  .tone-logs-recorder-primary-action {
    width: 100%;
    min-width: 0;
    min-height: 4rem;
    font-size: var(--tl-text-xl);
  }

  .tone-logs-recorder-review-actions,
  .tone-logs-recorder-review-actions .btn {
    width: 100%;
  }

  .recording-upload-progress,
  .recording-upload-progress .UppyDashboard-inner,
  .recording-upload-progress .uppy-Dashboard-inner {
    max-width: 100% !important;
  }
}

.plot-section-layout {
  display: grid;
  gap: var(--tl-space-3);
}

.plot-section-controls {
  align-self: start;
}

.frequency-tick-row {
  display: flex;
  justify-content: space-between;
  gap: var(--tl-space-1);
}

.dual-boundary-control {
  --boundary-start: 0%;
  --boundary-end: 100%;
}

.dual-boundary-control.is-disabled {
  opacity: 0.65;
}

/*
 * Slider hierarchy: label, then control, then a mono summary of the resulting
 * selection. The row is 44px tall so the drag target meets the touch minimum,
 * while the visible thumb stays 24px.
 */
.dual-boundary-label {
  display: block;
  margin-bottom: var(--tl-space-1);
  font-size: var(--tl-text-sm);
  font-weight: 500;
  color: var(--tl-ink);
}

.tl-boundary-summary {
  margin-top: var(--tl-space-1);
  margin-bottom: 0;
  font-family: var(--tl-font-mono);
  font-size: var(--tl-text-xs);
  font-variant-numeric: tabular-nums;
  color: var(--tl-ink-muted);
}

.dual-boundary-slider {
  position: relative;
  height: 2.75rem;
}

/*
 * The track boundary must be findable, so it carries a 3:1 border rather than
 * relying on the fill alone.
 */
.dual-boundary-track {
  position: absolute;
  top: 50%;
  left: 0;
  right: 0;
  height: 0.5rem;
  overflow: hidden;
  background: var(--tl-neutral-tint);
  border: var(--tl-border-width) solid var(--tl-border-control);
  border-radius: 999px;
  transform: translateY(-50%);
}

.dual-boundary-fill {
  position: absolute;
  top: 0;
  bottom: 0;
  left: var(--boundary-start);
  right: calc(100% - var(--boundary-end));
  background: var(--tl-primary);
}

.dual-boundary-range {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 2.75rem;
  margin: 0;
  pointer-events: none;
  background: transparent;
  /* Vertical scrolling still passes through a horizontal drag target. */
  touch-action: pan-y;
  appearance: none;
}

.dual-boundary-range::-webkit-slider-runnable-track {
  height: 0.5rem;
  background: transparent;
}

.dual-boundary-range::-moz-range-track {
  height: 0.5rem;
  background: transparent;
}

.dual-boundary-range::-webkit-slider-thumb {
  width: 1.5rem;
  height: 1.5rem;
  margin-top: -0.5rem;
  pointer-events: auto;
  background: var(--tl-canvas);
  border: 2px solid var(--tl-primary);
  border-radius: 50%;
  box-shadow: var(--tl-shadow-1);
  appearance: none;
}

.dual-boundary-range::-moz-range-thumb {
  width: 1.5rem;
  height: 1.5rem;
  pointer-events: auto;
  background: var(--tl-canvas);
  border: 2px solid var(--tl-primary);
  border-radius: 50%;
  box-shadow: var(--tl-shadow-1);
}

.dual-boundary-range:focus-visible::-webkit-slider-thumb {
  outline: 2px solid var(--tl-focus);
  outline-offset: 2px;
}

.dual-boundary-range:focus-visible::-moz-range-thumb {
  outline: 2px solid var(--tl-focus);
  outline-offset: 2px;
}

@media (min-width: 992px) {
  .plot-section-layout {
    grid-template-columns: minmax(220px, 280px) minmax(0, 1fr);
    align-items: start;
  }

  .plot-section-controls {
    position: sticky;
    top: var(--tl-space-3);
  }
}

.report-print-page {
  max-width: 1120px;
}

/*
 * Report footer: once at the document end, in screen and print alike, so a
 * printed page always carries the source and the interpretation limit.
 */
.tl-report-footer {
  display: flex;
  gap: var(--tl-space-3);
  padding-top: var(--tl-space-3);
  margin-top: var(--tl-space-6);
  border-top: var(--tl-border-width) solid var(--tl-border-subtle);
  break-inside: avoid;
  page-break-inside: avoid;
}

.tl-report-footer-logo {
  flex: none;
}

.tl-report-footer p {
  margin-bottom: var(--tl-space-1);
  font-size: var(--tl-text-xs);
  color: var(--tl-ink-muted);
}

.tl-report-footer-brand {
  font-weight: 600;
  color: var(--tl-ink);
}

.tl-report-footer-disclaimer {
  margin-bottom: 0;
}

/* ==========================================================================
 * Landing page
 * ========================================================================== */

/*
 * The hero line is the one text set in the display size, which
 * visual-system.md reserves for it.
 */
.tl-landing-title {
  margin-bottom: var(--tl-space-4);
  font-size: clamp(2rem, 1.25rem + 2.5vw, var(--tl-text-display));
  font-weight: 600;
  line-height: 1.15;
}

/* Each sentence of the hero line wraps as a unit, so no word is left behind. */
.tl-landing-title > span {
  display: inline-block;
  text-wrap: balance;
}

/* The lead says what ToneLogs records; a clear gap separates it from analysis. */
.tl-landing-lead {
  max-width: 44rem;
  margin-bottom: var(--tl-space-4);
  font-size: var(--tl-text-xl);
  text-wrap: pretty;
}

.tl-landing-intro {
  max-width: 44rem;
  margin-bottom: var(--tl-space-4);
  text-wrap: pretty;
}

.tl-landing-actions {
  margin-bottom: var(--tl-space-4);
}

/* Calls to action meet the 44px mobile primary-action minimum. */
.tl-landing-actions .btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 2.75rem;
}

/*
 * Product screenshots. A desktop shot is a flat bordered panel; a phone shot
 * gets a dark bezel, the one landing-only shape, so it reads as a phone.
 */
.tl-landing-shot {
  display: block;
  max-width: 100%;
  height: auto;
  background: var(--tl-canvas);
  border: var(--tl-border-width) solid var(--tl-border-subtle);
  border-radius: var(--tl-radius-lg);
}

.tl-landing-shot-phone {
  border: 0.375rem solid var(--tl-ink);
  border-radius: 1.5rem;
}

/*
 * Two screenshots, the second offset towards the lower right of the first. The
 * offsets are padding, so the pair keeps its proportions at every width.
 */
.tl-landing-stack {
  position: relative;
  padding-right: var(--tl-landing-stack-x);
  padding-bottom: var(--tl-landing-stack-y);
}

.tl-landing-stack > :first-child {
  position: relative;
  width: 100%;
}

.tl-landing-stack > :last-child {
  position: absolute;
  right: 0;
  bottom: 0;
}

/*
 * The central statement: one ToneLog on a computer, and on a phone in front of
 * its lower right corner. The phone may cover part of the analysis view.
 */
.tl-landing-showcase {
  --tl-landing-stack-x: 14%;
  --tl-landing-stack-y: 10%;

  margin-top: var(--tl-space-4);
}

.tl-landing-showcase > .tl-landing-shot-phone {
  width: 24%;
  border-width: 0.25rem;
  border-radius: var(--tl-radius-lg);
}

/* A printed report: page 1 on top, page 2 behind it towards the lower right. */
.tl-landing-pages {
  --tl-landing-stack-x: 22%;
  --tl-landing-stack-y: 10%;

  justify-self: center;
  width: 86%;
}

.tl-landing-pages > :first-child {
  z-index: 1;
}

.tl-landing-pages > :last-child {
  width: calc(100% - var(--tl-landing-stack-x));
}

/* Paper rather than a screen: near-square corners and a shadow. */
.tl-landing-shot-page {
  border-radius: var(--tl-radius-sm);
  box-shadow: var(--tl-shadow-2);
}

/* A file-type hint beside a document's screenshot, such as the report's PDF. */
.tl-landing-file {
  display: flex;
  gap: var(--tl-space-2);
  align-items: center;
  font-weight: 600;
  color: var(--tl-primary);
}

.tl-landing-file .tl-icon {
  font-size: var(--tl-text-2xl);
}

.tl-landing-section {
  margin-bottom: var(--tl-space-6);
}

.tl-landing-section-title {
  margin-bottom: var(--tl-space-4);
  font-size: var(--tl-text-2xl);
  font-weight: 600;
  line-height: 1.25;
}

/* A scenario beside its screenshot; stacked text first on narrow screens. */
.tl-landing-feature {
  display: grid;
  gap: var(--tl-space-4);
  align-items: center;
  margin-bottom: var(--tl-space-6);
}

.tl-landing-feature-phone .tl-landing-shot-phone {
  justify-self: center;
  width: min(13rem, 60%);
}

.tl-landing-audiences,
.tl-landing-setups,
.tl-landing-methods {
  display: grid;
  gap: var(--tl-space-4);
}

/*
 * From `md`, a large gauge, centered in a 3/12 column, beside an explanation
 * that uses the other 9/12. Narrower, the gauge sits above the text, so the
 * explanation keeps the full width.
 */
.tl-landing-why {
  display: grid;
  gap: var(--tl-space-3);
  align-items: center;
}

.tl-landing-why-icon {
  display: flex;
  align-items: center;
  justify-content: flex-start;
  font-size: 4rem;
  line-height: 1;
  color: var(--tl-primary);
}

@media (min-width: 768px) {
  .tl-landing-why {
    grid-template-columns: minmax(0, 3fr) minmax(0, 9fr);
    gap: var(--tl-space-4);
  }

  .tl-landing-why-icon {
    justify-content: center;
    font-size: 6rem;
  }
}

.tl-landing-hero {
  margin-bottom: var(--tl-space-6);
}

/* The page's one statement: what ToneLogs is for, above the showcase. */
.tl-landing-statement {
  margin-bottom: var(--tl-space-3);
  font-size: clamp(var(--tl-text-2xl), 1.1rem + 1.6vw, var(--tl-text-3xl));
  font-weight: 600;
  line-height: 1.25;
}

.tl-landing-setups,
.tl-landing-methods {
  padding: 0;
  margin: 0;
  list-style: none;
}

.tl-landing-methods-note {
  margin-top: var(--tl-space-4);
  margin-bottom: 0;
}

/* Audiences and equipment setups: equal sunken panels, none a step. */
.tl-landing-panel {
  padding: var(--tl-space-4);
  background: var(--tl-surface-sunken);
  border-radius: var(--tl-radius-md);
}

.tl-landing-icon {
  display: flex;
  gap: var(--tl-space-1);
  margin-bottom: var(--tl-space-2);
  font-size: var(--tl-text-2xl);
  color: var(--tl-primary);
}

.tl-landing-checklist {
  display: grid;
  gap: var(--tl-space-2) var(--tl-space-5);
  padding: 0;
  margin: 0;
  list-style: none;
}

.tl-landing-checklist > li {
  position: relative;
  padding-left: var(--tl-space-4);
}

.tl-landing-checklist > li::before {
  position: absolute;
  top: 0.7em;
  left: 0;
  width: 0.75em;
  height: 2px;
  content: "";
  background: var(--tl-primary);
}

@media (min-width: 768px) {
  .tl-landing-checklist {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .tl-landing-audiences {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (min-width: 992px) {
  .tl-landing-feature {
    grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
  }

  .tl-landing-feature-phone {
    grid-template-columns: minmax(0, 2fr) minmax(0, 1fr);
  }

  /* Alternate sides on wide screens; the reading order stays text first. */
  .tl-landing-feature-reverse > :last-child {
    order: -1;
  }

  .tl-landing-feature-reverse {
    grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
  }

  .tl-landing-setups,
  .tl-landing-methods {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

/* ==========================================================================
 * Reduced motion
 *
 * Motion clarifies state changes and is never required to read state, so
 * removing it loses no information. See docs/design/interaction-motion.md.
 * ========================================================================== */

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    transition-duration: 0.01ms !important;
    transition-delay: 0s !important;
    animation-duration: 0.01ms !important;
    animation-delay: 0s !important;
    animation-iteration-count: 1 !important;
    scroll-behavior: auto !important;
  }

  /* Hover elevation becomes an immediate boundary change. */
  .equipment-card:hover,
  .equipment-card:focus-within {
    box-shadow: none;
    border-color: var(--tl-primary);
  }
}

@media print {
  .navbar,
  .print-hidden,
  .report-print-actions {
    display: none !important;
  }

  .report-print-page {
    max-width: none;
    margin: 0 !important;
  }

  /*
   * The page is about 718 px wide on A4, where Bootstrap would cap the outer
   * container at 540 px; a printed page uses its full printable width.
   */
  .page-shell {
    max-width: none;
    padding-bottom: 0;
  }

  .report-figure {
    break-inside: avoid;
    page-break-inside: avoid;
  }
}
