:root {
  --bg: #f5f6f8;
  --surface: #ffffff;
  --surface-alt: #eef0f3;
  --text: #1b1e22;
  --text-muted: #5b6572;
  --border: #dde1e6;
  --primary: #2e6f8e;
  --primary-contrast: #ffffff;
  --danger: #c0392b;
  --success: #2e7d32;
  --radius: 10px;
  --shadow: 0 1px 3px rgba(0,0,0,0.08);
}

html[data-theme="dark"] {
  --bg: #14171a;
  --surface: #1e2226;
  --surface-alt: #262b30;
  --text: #eceef0;
  --text-muted: #9aa4ad;
  --border: #33393f;
  --primary: #62a8cc;
  --primary-contrast: #06202b;
  --danger: #e57373;
  --success: #81c784;
  --shadow: 0 1px 3px rgba(0,0,0,0.4);
}

@media (prefers-color-scheme: dark) {
  html[data-theme="auto"] {
    --bg: #14171a;
    --surface: #1e2226;
    --surface-alt: #262b30;
    --text: #eceef0;
    --text-muted: #9aa4ad;
    --border: #33393f;
    --primary: #62a8cc;
    --primary-contrast: #06202b;
    --danger: #e57373;
    --success: #81c784;
    --shadow: 0 1px 3px rgba(0,0,0,0.4);
  }
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  background: var(--bg);
  color: var(--text);
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  font-size: 16px;
  -webkit-tap-highlight-color: transparent;
}

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

.topbar {
  position: sticky;
  top: 0;
  z-index: 20;
  background: var(--surface);
  border-bottom: 1px solid var(--border);
}
.topbar-inner {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px 12px;
  max-width: 900px;
  margin: 0 auto;
}
.app-title {
  font-weight: 600;
  font-size: 1.05rem;
  min-width: 0;
  flex: 0 1 auto;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: inherit;
  text-decoration: none;
}
.app-title:active { opacity: 0.7; }

/* Feature: coherent icon set / new logo -- sticky header now shows the
   Merknis horizontal wordmark instead of the plain StudyName text (see
   base.html's header_title block). Sized to fit the single-line header
   alongside the back/action/account-menu groups; scales down naturally
   on narrow screens since .app-title itself is allowed to shrink. */
.app-logo {
  height: 26px;
  max-width: 100%;
  width: auto;
  display: block;
}

/* Feature: redesigned sticky header -- <app name> <-filler-> *1 *2 *3.
   *1 (topbar-back) and *2 (topbar-page-actions) share one horizontally-
   scrolling group (pushed to the right via margin-left:auto on
   .topbar-actions, same trick as before) so they never wrap onto a second
   row; either collapses to nothing via `:empty` when a page doesn't use
   it. *3 (topbar-account, the site-wide hamburger menu) sits outside that
   scrolling group, always anchored at the very right and always visible. */
.topbar-actions {
  display: flex;
  align-items: center;
  flex-wrap: nowrap;
  flex-shrink: 0;
  max-width: 100%;
  gap: 6px;
  margin-left: auto;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
}
.topbar-actions::-webkit-scrollbar { display: none; }
.topbar-actions .btn, .topbar-actions .icon-btn { white-space: nowrap; flex-shrink: 0; }

.topbar-back, .topbar-page-actions {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-shrink: 0;
}
.topbar-back:empty, .topbar-page-actions:empty { display: none; }

/* Feature: site-wide "my account" hamburger menu (*3). Always anchored to
   the header's far right; the dropdown panel is positioned relative to
   this wrapper. */
.topbar-account {
  position: relative;
  flex-shrink: 0;
  margin-left: 6px;
}
.account-menu-panel {
  position: absolute;
  top: calc(100% + 6px);
  right: 0;
  min-width: 240px;
  max-width: 80vw;
  /* CR009 #2: cap the panel's own height to what fits below the sticky
     header and make it independently scrollable, so a tall menu (e.g. a
     participant's full menu on a short-viewport landscape phone) scrolls
     its OWN content instead of overflowing off-screen with no way to
     reach the lower items. overscroll-behavior stops that internal
     scroll from "chaining" into the page behind it once the panel's own
     scroll reaches either end -- this is what fixes the reported
     "swipe scrolls the background page instead" symptom. */
  max-height: calc(100vh - 70px);
  overflow-y: auto;
  overflow-x: hidden;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  z-index: 50;
  display: none;
}
.account-menu-panel.open { display: block; }
.account-menu-section { padding: 6px 0; border-bottom: 1px solid var(--border); }
.account-menu-section:last-child { border-bottom: none; }
/* Feature: page-specific items (see base.html's account_menu_page_items
   block) -- collapses away entirely on pages that don't define any,
   instead of leaving an empty bordered section at the top of the menu. */
.account-menu-page-items:empty { display: none; padding: 0; border-bottom: none; }
/* CRS02-1: "feature scope" account-menu section -- collapses away
   entirely (no empty bordered section) whenever no addon has registered
   a standalone main-view entry via add_feature_menu_item(). */
.account-menu-feature-items:empty { display: none; padding: 0; border-bottom: none; }
.account-menu-item {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  box-sizing: border-box;
  text-align: left;
  padding: 10px 14px;
  background: none;
  border: none;
  color: var(--text);
  text-decoration: none;
  font-size: 0.9rem;
  font-family: inherit;
  cursor: pointer;
}
.account-menu-item:hover, .account-menu-item:active { background: var(--surface-alt); }
.account-menu-item-label { display: flex; align-items: center; gap: 10px; }

.page {
  max-width: 900px;
  margin: 0 auto;
  padding: 12px 12px 90px 12px;
}

.icon-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: none;
  background: transparent;
  font-size: 1.2rem;
  line-height: 1;
  padding: 6px 8px;
  border-radius: var(--radius);
  cursor: pointer;
  color: var(--text);
  text-decoration: none;
}
.icon-btn:active { background: var(--surface-alt); }

/* Feature: coherent icon set -- shared sizing/alignment for every inline
   SVG icon used across buttons, icon-only buttons, and account-menu
   items (add/copy/remove log entry, theme toggle, add photo, clear
   text field). `.btn`, `.icon-btn` and `.account-menu-item` are already
   flex containers with a `gap`, so dropping one of these <img> tags in
   next to existing label text lines up automatically.
   Dark mode: these are single-color line icons, so they're inverted
   (roughly white-on-transparent) to stay legible against the dark
   surface colors -- the brand logo (.app-logo above) is deliberately
   EXCLUDED from this, since it carries its own colors and should look
   the same in both themes. */
.ui-icon {
  width: 18px;
  height: 18px;
  flex: 0 0 auto;
  vertical-align: -4px;
}
.icon-btn .ui-icon {
  width: 20px;
  height: 20px;
  vertical-align: middle;
}

html[data-theme="dark"] .ui-icon {
  filter: invert(1) brightness(1.8);
}
@media (prefers-color-scheme: dark) {
  html[data-theme="auto"] .ui-icon {
    filter: invert(1) brightness(1.8);
  }
}

/* Feature: check-in/out status button colors (participant home header) --
   the button's background reflects the participant's CURRENT status (not
   the action it triggers), so it's obvious at a glance without reading the
   label. Mirrors the existing flash-success/flash-error color language. */
.status-checked-in { background: rgba(46,125,50,0.18); color: var(--success); border-color: var(--success); }
.status-checked-out { background: rgba(192,57,43,0.18); color: var(--danger); border-color: var(--danger); }

/* Feature: Log Entry editor prev/next navigation -- previous entry button
   pinned to the left, next entry button pinned to the right, date/time
   summary centered in the space between them. The summary keeps its
   natural size (flex-shrink:0, so it's never compressed/truncated) while
   flex-grow:1 lets it claim all the leftover space for centering; the nav
   buttons are fixed-size and, with flex-wrap, drop to their own line
   first if there isn't enough room rather than squeezing the summary. */
.entry-summary-row {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
}
.entry-summary-text {
  flex: 1 0 auto;
  min-width: 0;
  text-align: center;
}
.entry-summary-nav-prev,
.entry-summary-nav-next {
  flex: 0 0 auto;
}

.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 14px;
  margin-bottom: 12px;
}

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 10px 16px;
  border-radius: var(--radius);
  border: 1px solid var(--border);
  background: var(--surface-alt);
  color: var(--text);
  font-size: 0.95rem;
  cursor: pointer;
  text-decoration: none;
}
.btn-primary { background: var(--primary); color: var(--primary-contrast); border-color: var(--primary); }
.btn-danger { background: transparent; color: var(--danger); border-color: var(--danger); }
.btn-sm { padding: 6px 10px; font-size: 0.85rem; }
.btn-block { width: 100%; }
.btn-row { display: flex; gap: 8px; flex-wrap: wrap; }

input[type=text], input[type=password], input[type=date], input[type=datetime-local],
input[type=number], input[type=color], input[type=url], input[type=email], input[type=search],
input[type=tel], textarea, select {
  width: 100%;
  padding: 10px;
  border-radius: var(--radius);
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text);
  font-size: 1rem;
}
textarea { min-height: 70px; resize: vertical; }
label { display: block; font-size: 0.85rem; color: var(--text-muted); margin: 8px 0 4px; }

.flash-stack { margin-bottom: 12px; }
.flash { padding: 10px 12px; border-radius: var(--radius); margin-bottom: 8px; font-size: 0.9rem; }
.flash-success { background: rgba(46,125,50,0.15); color: var(--success); }
.flash-error { background: rgba(192,57,43,0.15); color: var(--danger); }

table { border-collapse: collapse; width: 100%; }
th, td { border: 1px solid var(--border); padding: 6px 8px; font-size: 0.85rem; text-align: left; }
th { background: var(--surface-alt); }

.badge { display: inline-block; padding: 2px 8px; border-radius: 999px; font-size: 0.75rem; }
.badge-draft { background: #ffe9a8; color: #5a4400; }
.badge-committed { background: rgba(46,125,50,0.2); color: var(--success); }
.badge-uncommitted { background: rgba(192,57,43,0.2); color: var(--danger); }

.list-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  margin-bottom: 8px;
  text-decoration: none;
  color: var(--text);
}
.list-row:active { background: var(--surface-alt); }

/* Feature: participant home screen -- Log Entries flagged as "Wichtig"
   (see models.py LogEntry.Important) get a red border instead of the
   usual grey one, so they stand out at a glance in the entry list. */
.list-row-important { border-color: var(--danger); }

/* Feature: participant home-screen list row, second line -- a truncated
   one-line Description snippet (left) and a small row of colored squares
   (right). */
.list-row-content {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.list-row-second-line {
  display: flex;
  align-items: center;
  gap: 8px;
}
.list-row-first-line {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 6px;
}
.list-row-first-line-main { min-width: 0; }
.list-row-photo-count {
  position: relative;
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  color: var(--text-muted);
}
.list-row-photo-count svg { display: block; width: 16px; height: 16px; }
.list-row-photo-count-bubble {
  position: absolute;
  top: -7px;
  right: -8px;
  min-width: 16px;
  height: 16px;
  padding: 0 4px;
  box-sizing: border-box;
  border-radius: 8px;
  background: var(--primary);
  color: var(--primary-contrast);
  font-size: 0.65rem;
  font-weight: 700;
  line-height: 16px;
  text-align: center;
}
.list-row-desc-snippet {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--text-muted);
  font-size: 0.85rem;
}
.aqc-mini-preview {
  flex: 0 0 auto;
  display: flex;
  gap: 3px;
}
.aqc-mini-box {
  flex: 0 0 auto;
  width: 14px;
  height: 14px;
  border: 1px solid #000;
  box-sizing: border-box;
}

/* Feature: per-row "⋮" popup menu on the participant home screen (see
   participant_home.html) -- holds "Als neuen Eintrag kopieren" and
   "Löschen", replacing two always-visible buttons that were easy to
   mis-tap (in particular the copy action, right next to the row's own
   tap-to-edit area). Mirrors the site-wide account menu's visual style
   (.account-menu-panel/.account-menu-item in base.html) but is scoped
   per-row and only one can be open at a time (see the toggleRowMenu()
   script). */
.row-menu {
  position: relative;
  flex: 0 0 auto;
}
.row-menu-panel {
  position: absolute;
  top: calc(100% + 4px);
  right: 0;
  min-width: 210px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  z-index: 40;
  display: none;
  overflow: hidden;
}
.row-menu-panel.open { display: block; }
.row-menu-item {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  box-sizing: border-box;
  text-align: left;
  padding: 10px 14px;
  background: none;
  border: none;
  color: var(--text);
  text-decoration: none;
  font-size: 0.9rem;
  font-family: inherit;
  cursor: pointer;
}
.row-menu-item:hover, .row-menu-item:active { background: var(--surface-alt); }
.row-menu-item-danger { color: var(--danger); }

/* Feature: home-screen multi-selection ("multi selection mode") -- long-
   press/long-click a row to enter, tap rows to toggle selection, and use
   the top bar (counter + "X" to clear/exit, "⋮" for bulk actions) while
   active. See participant_home.html's extra_scripts block. */
.multiselect-bar {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 10px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--shadow);
  margin-bottom: 12px;
  position: sticky;
  top: 56px; /* stays visible just below the sticky app header */
  z-index: 15;
}
.ms-counter { flex: 1 1 auto; font-weight: 600; font-size: 0.9rem; }

/* Selection checkmark at the start of each row -- an empty rounded square
   normally, filled with the primary color and a checkmark glyph once that
   row is part of the current selection. Only takes up space while
   multi-select mode is active (body.ms-active), so ordinary browsing
   keeps the row's original compact layout. */
.ms-checkbox {
  display: none;
  flex: 0 0 auto;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  border: 2px solid var(--border);
  border-radius: 5px;
  color: var(--primary-contrast);
  font-size: 0.85rem;
  font-weight: 700;
}
body.ms-active .ms-checkbox { display: flex; }
.list-row.ms-selected .ms-checkbox {
  background: var(--primary);
  border-color: var(--primary);
}
.list-row.ms-selected .ms-checkbox::before { content: "✓"; }
.list-row.ms-selected {
  background: rgba(46,111,142,0.10);
  border-color: var(--primary);
}
/* Bugfix: this used to be `body.ms-active .row-menu { display: none; }`,
   but the multiselect-bar's own "⋮" bulk-actions menu wrapper was ALSO
   using the .row-menu class at the time, so this rule hid that menu too
   -- exactly while multi-select mode (and thus this menu) was active,
   making it invisible. The bulk-actions menu now uses a distinct
   .ms-menu-wrap class (see below) specifically so it's unaffected by
   this rule, which now only ever targets the PER-ROW "⋮" menus
   (copy/report/delete a single entry) -- those are still hidden while
   multi-select mode is active, to keep a row's tap target unambiguously
   about selection during that mode. */
body.ms-active .log-entry-list .row-menu { display: none; }

/* Feature: the multiselect-bar's own "⋮" bulk-actions menu wrapper --
   positioned the same way as .row-menu (see above) but under its own
   class so the per-row-menu-hiding rule above never touches it. */
.ms-menu-wrap { position: relative; flex: 0 0 auto; }

/* Non-functional dividing line inside a "⋮" popup menu (see the bulk
   action menu's "Löschen" separated from the other actions above it). */
.row-menu-divider {
  border: none;
  border-top: 1px solid var(--border);
  margin: 4px 0;
}

/* Home screen view selection (date picker + split button). */
.home-view-form { display: flex; gap: 8px; align-items: flex-end; flex-wrap: wrap; }
.home-view-date { flex: 1 1 160px; }
.home-view-actions { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }

/* Split button: a main action plus a caret that opens a list of options. */
.split-btn { position: relative; display: inline-flex; }
.split-btn .split-btn-main { border-top-right-radius: 0; border-bottom-right-radius: 0; }
.split-btn .split-btn-toggle { border-top-left-radius: 0; border-bottom-left-radius: 0; margin-left: -1px; padding-left: 8px; padding-right: 8px; }
.split-btn .row-menu-panel { right: auto; left: 0; min-width: 160px; }
.split-btn-check { display: inline-block; width: 1em; text-align: center; }

/* Card carousel */
.win-nav-strip { display: flex; gap: 6px; overflow-x: auto; padding: 6px 0 10px; }
.win-nav-dot {
  flex: 0 0 auto;
  min-width: 40px;
  padding: 6px 10px;
  border-radius: 999px;
  border: 2px solid var(--border);
  background: var(--surface-alt);
  font-size: 0.8rem;
  text-align: center;
  cursor: pointer;
}
.win-nav-dot.filled { border-color: var(--success); }
.win-nav-dot.active { border-color: var(--primary); font-weight: 700; }

.carousel { display: flex; overflow-x: auto; scroll-snap-type: x mandatory; gap: 10px; }
.carousel-card {
  flex: 0 0 100%;
  scroll-snap-align: start;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 14px;
}

.aqc-group { display: flex; gap: 8px; flex-wrap: wrap; margin: 8px 0; }
.aqc-btn {
  flex: 1 1 auto;
  min-width: 64px;
  padding: 10px 6px;
  border-radius: var(--radius);
  border: 3px solid transparent;
  color: #111;
  font-weight: 600;
  font-size: 0.85rem;
  cursor: pointer;
  text-align: center;
}
.aqc-btn.selected { border-color: var(--text); box-shadow: 0 0 0 2px var(--primary) inset; }
.aqc-btn.selected::after { content: " ✓"; }

/* "?" option: dashed, transparent instead of a solid color fill. */
.aqc-btn-override {
  background: transparent !important;
  border: 2px dashed var(--border);
  color: var(--text-muted);
}

/* Feature (CR010): split-button wrapper (the "+ Eintrag" choice popup's
   template-picker arrow, see base.html) -- the main action button and its
   adjoining "▾" arrow render as one visually joined control. */
/* Bugfix (CR011): the split-buttons' own template-picker panel used to
   inherit its absolute-positioning context from the whole modal `.card`
   (the nearest ancestor with `position: relative` set), which placed it
   at the bottom edge of the entire dialog instead of directly below
   whichever split-button's arrow opened it. `.split-btn` is now itself
   that positioning context -- the panel is reparented into the relevant
   split-button (see base.html's toggleTemplateMenu()) before it opens, so
   its `top: calc(100% + 4px)` (see .row-menu-panel) is relative to that
   button group's own height, not the dialog's.
   Feature: also gives the two split-buttons ("Log Entry" / "Unterbrechung")
   an equal share of the row's width via `flex: 1 1 0`, instead of each
   sizing to its own (differently long) label text -- previously left them
   visibly uneven widths next to each other. */
.split-btn { display: flex; position: relative; flex: 1 1 0; }
.split-btn .btn:first-child { border-top-right-radius: 0; border-bottom-right-radius: 0; flex: 1 1 auto; }
.split-btn-arrow { border-top-left-radius: 0; border-bottom-left-radius: 0; border-left: 1px solid rgba(0,0,0,0.15); padding: 10px 10px; flex: 0 0 auto; }
.new-entry-int-form { margin-top: 12px; }
.new-entry-int-tpl { font-size: 0.9rem; color: var(--text-muted); }
.new-entry-int-tpl strong { color: var(--text); }
.new-entry-int-form input[type=date], .new-entry-int-form input[type=time] {
  width: 100%;
  padding: 10px;
  border-radius: var(--radius);
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text);
  font-size: 1rem;
}
.new-entry-int-times { display: flex; gap: 8px; }
.new-entry-int-times > div { flex: 1 1 0; min-width: 0; }
.new-entry-int-form .flash { margin: 8px 0 0; }
.new-entry-final-row { margin-top: 12px; }
.new-entry-final-row .btn { flex: 1 1 0; }

.checkbox-row { display: flex; align-items: center; gap: 8px; margin: 10px 0; }
.checkbox-row input[type=checkbox] { width: 22px; height: 22px; }
.checkbox-row[hidden] { display: none; }

/* Feature: "Wichtig" checkbox, in line with the Description card's label,
   right-aligned relative to the description text field below it. */
.desc-header-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  flex-wrap: wrap;
}
.desc-header-row label { margin: 0; }
.important-checkbox-row { margin: 0; }

/* Feature: "Wichtig" badge (Report One detail block header) -- reuses the
   danger color language already used elsewhere (e.g. status-checked-out). */
.badge-important { background: rgba(192,57,43,0.2); color: var(--danger); }

/* Quick-erase icon button next to Pollutant #1/#2 free-text fields
   (with local undo-on-empty-click, see log_entry_form.html). */
.field-with-icon { display: flex; align-items: center; gap: 8px; }
.field-with-icon .autocomplete-wrap { flex: 1 1 auto; min-width: 0; }
.clear-icon-btn {
  flex: 0 0 auto;
  width: 42px;
  height: 42px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--radius);
  border: 1px solid var(--border);
  background: var(--surface-alt);
  color: var(--text);
  font-size: 1.1rem;
  cursor: pointer;
  padding: 0;
}
.clear-icon-btn:active { background: var(--surface); }

/* Feature: rich text Description editor (Log Entry form) -- a plain
   contenteditable <div>, styled to match the other text fields (see the
   generic textarea rule above) since it isn't matched by that selector.
   No formatting toolbar by design; only paste/typing populate it (see
   richtext.js). */
.rich-text-editable {
  width: 100%;
  min-height: 70px;
  max-height: 320px;
  overflow-y: auto;
  padding: 10px;
  border-radius: var(--radius);
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text);
  font-size: 1rem;
  font-family: inherit;
  line-height: 1.4;
}
.rich-text-editable:focus { outline: 2px solid var(--primary); outline-offset: -1px; }
.rich-text-editable:empty:before {
  content: attr(data-placeholder);
  color: var(--text-muted);
}
.rich-text-editable p { margin: 0 0 8px; }
.rich-text-editable p:last-child { margin-bottom: 0; }
.rich-text-editable ul, .rich-text-editable ol { margin: 0 0 8px 20px; padding: 0; }
.rich-text-editable table { border-collapse: collapse; margin: 0 0 8px; }
.rich-text-editable td, .rich-text-editable th { border: 1px solid var(--border); padding: 4px 6px; }

/* Feature: Pollutant #1/#2 fields are textareas (so multiple textblocks can
   be inserted and line-wrapped) that normally sit at a compact single line
   but temporarily grow to ~4 visible lines while focused (rows attribute
   toggled in log_entry_form.html), to make editing longer/combined texts
   easier without permanently enlarging the carousel card. Overrides the
   generic `textarea { min-height: 70px; }` rule above, which would
   otherwise always force a tall box regardless of the `rows` attribute. */
textarea.tb-input {
  min-height: 0;
  height: auto;
}

/* Feature: section headings inside the "Textbausteine durchsuchen" modal,
   separating "already entered for other windows in this session" from the
   full Textblock list. */
.tb-modal-section-heading {
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--text-muted);
  padding: 10px 4px 4px;
  border-top: 1px solid var(--border);
  margin-top: 4px;
}
.tb-modal-section-heading:first-child { border-top: none; margin-top: 0; padding-top: 0; }

/* Bugfix (CR015-0): prevents the browser's native text-selection
   highlight from appearing during a long-press-then-drag gesture on a
   modal row (mouse or touch) -- same precedent as .pa-thumb-wrap img's
   own -webkit-user-select: none fix for the identical class of
   long-press-vs-native-gesture conflict (see photo_archive.js). */
.tb-modal-item {
  -webkit-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
}

/* Feature (CR015-0): fixed header (title + search) and fixed footer
   (Schließen, or Abbrechen/Ersetzen/Einfügen once multi-select is
   active) for the "Textbausteine durchsuchen" modal, with only the
   textblock list itself scrolling in between -- mirrors the Notice
   popup's own fixed-header/scrollable-body/fixed-footer structure
   (.fullscreen-modal-overlay/.fullscreen-modal-body/.fullscreen-modal-footer
   above), so the action buttons stay reachable without scrolling all
   the way down a long textblock list first. */
.tb-modal-card {
  display: flex;
  flex-direction: column;
  max-height: 80vh;
}
.tb-modal-head { flex: 0 0 auto; }
.tb-modal-scroll {
  flex: 1 1 auto;
  overflow-y: auto;
  min-height: 0;
  margin: 10px 0;
}
.tb-modal-foot { flex: 0 0 auto; }
.tb-modal-foot #tb-modal-close-btn { margin-top: 10px; }
.tb-modal-foot .btn-row { margin-top: 10px; }

#rf-modal .ms-checkbox { display: flex; }
#rf-modal .rf-head {
  flex: 0 0 auto;
  padding: 8px 12px;
  border-bottom: 1px solid var(--border);
  background: var(--surface);
}
#rf-modal .rf-head-title {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 2px 10px;
}
#rf-modal .rf-head-title h4 { margin: 0; }
#rf-modal .rf-head-title .rf-hint { margin: 0; }
#rf-modal .rf-bar {
  position: static;
  box-shadow: none;
  border: none;
  background: none;
  padding: 6px 0 0;
  margin: 0;
}
#rf-modal .rf-alert {
  margin: 8px 0 0;
  padding: 10px 12px;
  border: 1px solid var(--danger);
  border-left-width: 6px;
  font-size: 0.95rem;
  font-weight: 600;
  max-height: 30vh;
  overflow-y: auto;
}
#rf-modal .rf-alert[hidden] { display: none; }
#rf-modal .rf-alert::before { content: "\26A0\FE0E\00A0"; }
#rf-modal .list-row {
  cursor: pointer;
  align-items: flex-start;
  -webkit-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
}
#rf-modal .split-btn-arrow { flex: 0 0 auto; }
#rf-modal .btn:disabled { opacity: 0.5; cursor: not-allowed; }
#rf-modal .rf-menu {
  top: auto;
  bottom: calc(100% + 4px);
  left: 0;
  right: auto;
  width: max-content;
  min-width: 100%;
  max-width: calc(100vw - 24px);
}
#rf-modal .rf-menu .row-menu-item { white-space: nowrap; }
#rf-confirm-modal { z-index: 220; }
.rf-text { white-space: pre-wrap; overflow-wrap: anywhere; font-size: 0.9rem; }
.rf-mark {
  background: rgba(255,193,7,0.38);
  color: inherit;
  border-radius: 3px;
  padding: 0 1px;
  font-weight: 600;
}
.rf-hint { color: var(--text-muted); font-size: 0.85rem; margin: 0 0 6px; }

.autocomplete-wrap { position: relative; }
.autocomplete-list {
  position: absolute;
  z-index: 30;
  left: 0; right: 0;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  max-height: 200px;
  overflow-y: auto;
  box-shadow: var(--shadow);
  display: none;
}
.autocomplete-list.open { display: block; }
.autocomplete-item { padding: 8px 10px; cursor: pointer; border-bottom: 1px solid var(--border); }
.autocomplete-item:last-child { border-bottom: none; }
.autocomplete-item:hover, .autocomplete-item:active { background: var(--surface-alt); }

/* Feature: Textbaustein modal multi-select (long-press) -- selected items
   get a strong, color+checkbox-glyph visual (not color alone) so multiple
   selections are unambiguous; already-inserted items are dimmed and
   inert to prevent inserting the same text twice into one field. */
.tb-item-selected {
  background: rgba(46,111,142,0.18);
  border-left: 3px solid var(--primary);
}
.tb-item-disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

.photo-grid { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 8px; }
.photo-thumb { position: relative; width: 84px; height: 84px; border-radius: var(--radius); overflow: hidden; border: 1px solid var(--border); }
.photo-thumb img { width: 100%; height: 100%; object-fit: cover; }
.photo-thumb .del-photo { position: absolute; top: 2px; right: 2px; background: rgba(0,0,0,0.6); color: #fff; border: none; border-radius: 50%; width: 22px; height: 22px; cursor: pointer; }
.photo-thumb.uploading::after { content: "…"; position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; background: rgba(0,0,0,0.35); color: #fff; }

/* Feature: photo capture-date/time caption ("DD.MM.YYYY - HH:MM"), shown
   below every photo thumbnail (Log Entry editor, Notice editor, Report
   One) so visually similar photos can be told apart -- see
   AssessmentPhoto/NoticePhoto.CaptureDateTime. Each thumbnail is wrapped
   in .photo-item (image + caption stacked, centered as a column); the
   caption uses a small font with no wrapping so a gallery row never grows
   taller than the 84px thumbnail above it -- if the caption text is wider
   than the thumbnail, the item itself just grows slightly wider rather
   than the caption wrapping onto a second line. */
.photo-item { display: flex; flex-direction: column; align-items: center; gap: 3px; }
.photo-caption { font-size: 0.65rem; color: var(--text-muted); white-space: nowrap; text-align: center; }

/* Editor photo grids (Log Entry editor, Notice popup): multi-selection.
   Scoped to .photo-grid-editable so Report One thumbnails are unaffected. */
.photo-grid-editable .photo-item { cursor: pointer; }
.photo-grid-editable .photo-thumb img {
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  user-select: none;
}
.photo-grid-editable .photo-thumb .ms-checkbox {
  position: absolute;
  top: 4px;
  left: 4px;
}
.photo-grid-editable .photo-item.ms-selected .photo-thumb {
  outline: 3px solid var(--primary);
  outline-offset: -3px;
}
.photo-grid-editable .photo-item.ms-selected .ms-checkbox {
  background: var(--primary);
  border-color: var(--primary);
}
.photo-grid-editable .photo-item.ms-selected .ms-checkbox::before { content: "✓"; }
body.ms-active .photo-grid-editable .del-photo { display: none; }
.photo-item.photo-busy { opacity: 0.5; pointer-events: none; }

.lightbox-overlay {
  display: none; position: fixed; inset: 0; background: rgba(0,0,0,0.85);
  z-index: 100; align-items: center; justify-content: center;
}
.lightbox-overlay.open { display: flex; }
/* Shared dialogs sit above the full-screen overlays (z-index 200). */
#photo-remove-modal { z-index: 220; }
#confirm-modal { z-index: 220; }
#leave-guard-modal { z-index: 230; }
/* Feature: photo capture-date/time caption below the lightbox image --
   the image (and its caption) are wrapped in .lightbox-content, a
   centered column, so the caption sits directly under the image
   regardless of that image's own aspect ratio; the prev/next nav buttons
   stay absolutely positioned over the whole overlay, unaffected by this
   wrapper. */
.lightbox-content { display: flex; flex-direction: column; align-items: center; max-width: 95%; max-height: 95%; }
.lightbox-overlay img { max-width: 100%; max-height: 85vh; display: block; }
.lightbox-caption { color: #fff; font-size: 0.95rem; text-align: center; margin-top: 10px; }

/* Feature: lightbox navigation arrows (photo Log Entry viewer) — lets the
   participant page through all photos attached to a Log Entry, in
   addition to the touch-swipe support wired up in carousel.js.
   Bugfix (CR007-5): the original translucent-WHITE backdrop
   (rgba(255,255,255,0.15/0.3)) nearly disappeared against anything but a
   fairly dark, uniform photo -- switched to a solid-ish translucent DARK
   backdrop instead, which reads reliably against both light and dark
   photo content, keeping the white arrow glyph on top. Applies to every
   lightbox in the app (#lightbox in the Log Entry editor and Report One,
   #notice-lightbox in the Notice popup) since they all share this one
   class -- no per-template change needed for this part of the fix. */
.lightbox-nav {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  width: 48px;
  height: 48px;
  border-radius: 50%;
  border: none;
  background: rgba(0,0,0,0.55);
  color: #fff;
  font-size: 2.2rem;
  line-height: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  z-index: 101;
}
.lightbox-nav:active { background: rgba(0,0,0,0.75); }
.lightbox-prev { left: 10px; }
.lightbox-next { right: 10px; }

/* Feature (CR007-5): always-visible lightbox close ("X") button, top-right,
   same dark/translucent visual language as .lightbox-nav above (and for
   the same contrast reasoning) -- added to every lightbox overlay in the
   app (Log Entry editor, Report One, Notice popup) since none of them
   previously offered an explicit close affordance beyond tapping the
   backdrop or swiping. Sized as a generous >=44px touch target,
   deliberately at least as large as .lightbox-nav's own 48px, since "hard
   to hit on mobile" is exactly the complaint this fixes. */
.lightbox-close {
  position: absolute;
  top: 10px;
  right: 10px;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  border: none;
  background: rgba(0,0,0,0.55);
  color: #fff;
  font-size: 1.8rem;
  line-height: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  z-index: 102;
}
.lightbox-close:active { background: rgba(0,0,0,0.75); }

/* Drag-and-drop reorder list (dragdrop.js). */
.drag-list { list-style: none; padding: 0; margin: 0; }
.drag-item {
  display: flex; align-items: center; gap: 10px;
  padding: 10px; margin-bottom: 6px; border-radius: var(--radius);
  border: 1px solid var(--border); background: var(--surface);
  cursor: grab;
}
.drag-item.dragging { opacity: 0.4; }
.aqc-color-dot { width: 20px; height: 20px; border-radius: 5px; flex: 0 0 auto; border: 1px solid rgba(0,0,0,0.2); }

/* Feature: Administration -> Textbausteine spreadsheet-style bulk editor. */
.tb-editor-table { border-collapse: collapse; width: 100%; }
.tb-editor-table th, .tb-editor-table td { border: 1px solid var(--border); padding: 4px; vertical-align: top; }
.tb-editor-table input[type=text], .tb-editor-table textarea, .tb-editor-table select {
  min-height: 0;
  margin: 0;
}
.tb-editor-table textarea { min-height: 44px; }

.tabs { display: flex; gap: 6px; margin-bottom: 10px; overflow-x: auto; }
.tab-btn {
  padding: 8px 14px; border-radius: 999px; border: 1px solid var(--border);
  background: var(--surface-alt); cursor: pointer; white-space: nowrap;
}
.tab-btn.active { background: var(--primary); color: var(--primary-contrast); border-color: var(--primary); }

/* Release group editor: tables with a per-row menu, documents table with
   multi-selection (leading checkbox column, trailing menu column). */
@media (max-width: 640px) {
  .col-low-priority { display: none; }
}
.rg-menu-col { width: 36px; text-align: center; padding: 2px; }
.rgdoc-name { overflow-wrap: anywhere; }
#rgdoc-table input[type=text] { min-height: 0; margin: 0; width: 100%; box-sizing: border-box; }
#rgdoc-table input[type=checkbox] { margin: 0; }
#rgdoc-area .ms-col { display: none; width: 28px; text-align: center; }
body.ms-active #rgdoc-area .ms-col { display: table-cell; }
body.ms-active #rgdoc-area .ms-checkbox { display: inline-flex; }
#rgdoc-area tr.rgdoc-row { cursor: pointer; }
#rgdoc-area tr.rgdoc-row { -webkit-touch-callout: none; }
#rgdoc-area tr.ms-selected td { background: rgba(46,111,142,0.10); }
#rgdoc-area tr.ms-selected .ms-checkbox { background: var(--primary); border-color: var(--primary); }
#rgdoc-area tr.ms-selected .ms-checkbox::before { content: "✓"; }
body.ms-active #rgdoc-area .row-menu { display: none; }

@media print {
  .topbar, .menubar, .btn, .no-print { display: none !important; }
  body { background: #fff; color: #000; }
  .page { padding: 0; max-width: none; }
  .card { box-shadow: none; border: none; }
  table { font-size: 10px; }
}

/* ---------------------------------------------------------------------
   Feature: message logging system (Administration -> Log)
   --------------------------------------------------------------------- */

/* Notification bubbles -- admin home screen "Log" link and the
   account-menu "Log" item's dynamically-inserted error bubble. Blue for
   new "information" messages, red for new "error" messages; a bubble is
   simply omitted (not rendered) when its count is zero. */
.log-bubble-row { display:flex; gap:6px; align-items:center; }
.log-bubble {
  display:inline-flex;
  align-items:center;
  justify-content:center;
  min-width: 20px;
  height: 20px;
  padding: 0 6px;
  border-radius: 999px;
  font-size: 0.7rem;
  font-weight: 700;
  color: #fff;
  line-height: 1;
}
.log-bubble-info { background: var(--primary); }
.log-bubble-error { background: var(--danger); }

/* Log table: grouped by date via a dedicated full-width row (also always
   repeated directly under the header, per spec, so the visible page is
   never disorienting about which day it's showing). */
.log-date-row td {
  background: var(--surface-alt);
  font-weight: 600;
  color: var(--text-muted);
}
.log-type-icon { text-align:center; font-size: 1.05rem; }
/* Truncates a log message to roughly three lines of visible text in the
   table (the full message is always available in the popup). */
.log-message-cell {
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
  max-height: 4.2em;
}
/* Occurrence-count column can be hidden on smaller screens, per spec. */
@media (max-width: 640px) {
  .log-count-col { display: none; }
}

/* Inline detail popup, opened by tapping a log row. Supports left/right
   swipe (touch) and chevron-style prev/next buttons (see admin_log.html)
   to page quickly through the currently loaded messages. */
.log-popup-overlay {
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(0,0,0,0.6);
  z-index: 100;
  align-items: center;
  justify-content: center;
}
.log-popup-overlay.open { display: flex; }
.log-popup-card {
  background: var(--surface);
  border-radius: var(--radius);
  padding: 18px 36px;
  max-width: 480px;
  width: 90%;
  max-height: 85vh;
  overflow-y: auto;
  position: relative;
}
.log-popup-nav {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  background: none;
  border: none;
  font-size: 2rem;
  line-height: 1;
  cursor: pointer;
  color: var(--text);
  padding: 4px 6px;
}
.log-popup-prev { left: 0; }
.log-popup-next { right: 0; }
.log-popup-field { margin-bottom: 10px; }
.log-popup-field label { color: var(--text-muted); font-size: 0.75rem; margin: 0 0 2px; }

/* ---------------------------------------------------------------------
   Full-screen overlays and the "Meine Notizen" filter card
   --------------------------------------------------------------------- */

/* Full-screen overlay (like .lightbox-overlay, but its own class since it
   needs a column flex layout with a pinned footer, not centered content):
   used by the Photo Archive picker and by addon popups that open from any
   page. */
.fullscreen-modal-overlay {
  display: none;
  position: fixed;
  inset: 0;
  z-index: 200;
  background: var(--bg);
  flex-direction: column;
}
.fullscreen-modal-overlay.open { display: flex; }
.fullscreen-modal-body {
  flex: 1 1 auto;
  overflow-y: auto;
  padding: 12px;
}
.fullscreen-modal-footer {
  flex: 0 0 auto;
  display: flex;
  gap: 8px;
  padding: 10px 12px;
  border-top: 1px solid var(--border);
  background: var(--surface);
}
.fullscreen-modal-footer .btn { flex: 1 1 0; }

/* Feature: "Meine Notizen" collapsible filter card (task 2 follow-up) --
   collapsed by default so it doesn't dominate the screen on small
   devices, since filtering is an occasional action; automatically opened
   (via the `open` attribute, set server-side) whenever a filter is
   already active, so an in-progress search is never hidden behind a
   closed disclosure. Reuses the plain <details>/<summary> pattern already
   used for report addenda, styled instead to read like an ordinary .card
   with its own clickable header. */
.filter-details { padding: 0; }
.filter-details > summary {
  cursor: pointer;
  padding: 14px;
  font-weight: 600;
  list-style: none;
}
.filter-details > summary::-webkit-details-marker { display: none; }
.filter-details > summary::before { content: "▸ "; }
.filter-details[open] > summary::before { content: "▾ "; }
.filter-details-body { padding: 0 14px 14px; }

/* ---------------------------------------------------------------------
   Feature (CR008): Photo Archive + modal photo picker
   --------------------------------------------------------------------- */

:root {
  /* Named constant (spec CR008 3.1) -- default thumbnail column width for
     the Photo Archive grid, read by both this stylesheet and
     photo_archive.js's column-count estimate. */
  --pa-thumb-width: 250px;
}

.pa-sentinel { height: 1px; }

.pa-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(var(--pa-thumb-width), 1fr));
  gap: 10px;
  margin: 10px 0;
}

.pa-card { position: relative; }
/* Bugfix (CR008-1, Issue #1): this used to have `overflow: hidden` to
   round the thumbnail's corners -- but that also clipped away the "⋮"
   card menu panel (.pa-card-menu-panel below), which is positioned
   outside this wrap's own box via its `bottom` offset. Rounding now
   happens on the <img> itself (border-radius: inherit, see below), which
   doesn't need a clipping ancestor, so this wrap no longer needs
   `overflow: hidden` at all. */
.pa-thumb-wrap {
  position: relative;
  width: 100%;
  aspect-ratio: 1 / 1;
  border-radius: var(--radius);
  border: 1px solid var(--border);
  cursor: pointer;
}
.pa-thumb-wrap > img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  border-radius: inherit;
  /* Bugfix (CR008-1, Issue #2): suppresses the browser's own native
     long-press image context menu ("save image" / "share image"), which
     otherwise races against -- and often wins over -- this app's own
     long-press-to-multiselect timer on mobile, cancelling it via a
     pointercancel before the 500ms threshold is reached. */
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  user-select: none;
}

.pa-star-toggle {
  position: absolute;
  top: 4px; right: 4px;
  width: 30px; height: 30px;
  border-radius: 50%;
  border: none;
  background: rgba(0,0,0,0.45);
  color: rgba(255,255,255,0.55);
  font-size: 1rem;
  cursor: pointer;
  display: flex; align-items: center; justify-content: center;
}
.pa-star-toggle.pa-star-marked { color: #ffd54f; }

.pa-menu-btn {
  position: absolute;
  bottom: 4px; right: 4px;
  background: rgba(0,0,0,0.45);
  color: #fff;
  border-radius: 50%;
  width: 28px; height: 28px;
  padding: 0;
}
.pa-card-menu-panel {
  position: absolute;
  /* Bugfix (CR008-1, Issue #1): the generic .row-menu-panel rule (shared
     base class, applied first) sets `top: calc(100% + 4px)`; without
     resetting it here, this element inherited both that `top` AND this
     rule's own `bottom: 36px` at once, producing an invalid/collapsed
     box that rendered with no visible height. */
  top: auto;
  bottom: 36px; right: 4px;
  min-width: 160px;
  z-index: 15;
}

.pa-checkbox {
  position: absolute;
  top: 4px; left: 4px;
  display: none;
}
body.ms-active .pa-checkbox,
#photo-archive-picker-root .pa-checkbox {
  display: flex;
}

.pa-card.ms-selected .pa-thumb-wrap { outline: 3px solid var(--primary); outline-offset: -3px; }
/* Bugfix (CR008-1, Issue #3): the shared .ms-checkbox fill/checkmark
   rules (see the .list-row-based ones above, used by the participant
   home screen and "Meine Notizen") are scoped to a .list-row ancestor --
   the Photo Archive marks its own selection state on .pa-card instead
   (matching this grid's own layout), so it needs its own counterpart
   here or the checkbox stays permanently in its empty state. */
.pa-card.ms-selected .pa-checkbox {
  background: var(--primary);
  border-color: var(--primary);
}
.pa-card.ms-selected .pa-checkbox::before {
  content: "✓";
}

.pa-details-card {
  max-width: 420px;
  width: 92vw;
  max-height: 88vh;
  overflow-y: auto;
  position: relative;
}
.pa-details-image-wrap { position: relative; width: 100%; margin-bottom: 10px; }
.pa-details-image-wrap img { width: 350px; max-width: 100%; display: block; margin: 0 auto; border-radius: var(--radius); }
.pa-details-image-wrap .pa-star-toggle { top: 8px; right: calc(50% - 175px + 8px); }
@media (max-width: 420px) {
  .pa-details-image-wrap .pa-star-toggle { right: 8px; }
}

#pa-picker-overlay { z-index: 205; }
#pa-picker-overlay .fullscreen-modal-body { padding-bottom: 8px; }

/* Feature (CR008-3, issue #1): upload-batch progress overlay track/fill,
   see photo_archive.html / photo_archive.js. */
.pa-upload-progress-track {
  width: 100%;
  height: 10px;
  border-radius: 999px;
  background: var(--surface-alt);
  overflow: hidden;
}
.pa-upload-progress-fill {
  height: 100%;
  background: var(--primary);
  transition: width 0.2s ease;
}
#pa-picker-overlay .pa-grid { --pa-thumb-width: 140px; }

.tristate-hint { color: var(--text-muted); font-size: 0.8rem; margin-left: 6px; }
#lb-tabs-card [role="tabpanel"] { touch-action: pan-y; }

.new-entry-title-wrap { position: relative; }
.new-entry-logbook-switch {
  background: none; border: none; padding: 0; margin: 0;
  font: inherit; color: var(--primary); cursor: pointer;
}
.new-entry-logbook-switch:hover, .new-entry-logbook-switch:focus-visible { text-decoration: underline; }
.new-entry-logbook-switch:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; border-radius: 3px; }

/* Settings pages: one tabbed card, staged lists, editor popups. */
.settings-tabs { scroll-margin-top: 64px; }
.settings-tabs [role="tabpanel"] > .card { border: 0; box-shadow: none; padding: 0; margin-bottom: 0; background: transparent; }
.tab-count { color: inherit; opacity: 0.8; }
.staged-row { flex-wrap: wrap; cursor: default; }
.staged-row input[type=text], .staged-row select, .staged-row textarea { flex: 1 1 160px; margin: 0; min-height: 0; width: auto; min-width: 0; }
.staged-row textarea { min-height: 44px; }
.staged-row .staged-label { flex: 1 1 160px; min-width: 0; overflow-wrap: anywhere; }
.staged-row .staged-check { display: inline-flex; align-items: center; gap: 6px; margin: 0; white-space: nowrap; }
.staged-row .staged-check input { width: auto; margin: 0; }
.staged-row .staged-actions { display: inline-flex; gap: 6px; flex-wrap: wrap; }
.drag-handle { cursor: grab; user-select: none; padding: 4px 6px; }
.row-move { padding: 4px 8px; }
@media (pointer: coarse) { .staged-row .drag-handle { display: none; } }
@media not all and (pointer: coarse) { .staged-row .row-move { display: none; } }
.staged-empty { color: var(--text-muted); padding: 10px; margin: 0; }
.staged-hint { color: var(--text-muted); font-size: 0.85rem; margin: 6px 0; }
.staged-textblock { align-items: flex-start; }
.staged-textblock textarea { flex: 2 1 220px; }
#staged-popup-classification, #staged-popup-target { z-index: 215; }
.staged-error { color: var(--danger); margin: 8px 0 0; }

.optional-attachment .optional-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
}
.optional-attachment .optional-title { font-weight: 600; min-width: 0; overflow-wrap: anywhere; }
.optional-attachment .optional-toggle {
  flex: 0 0 auto;
  width: 36px;
  height: 36px;
  padding: 0;
  border-radius: 50%;
  border: 1px solid var(--border);
  background: var(--surface-alt);
}
.optional-attachment .optional-body {
  border: 0;
  padding: 0;
  margin: 12px 0 0;
  min-width: 0;
}
.optional-attachment .optional-body[hidden] { display: none; }

.staged-popup-card { max-width: 420px; width: 90%; max-height: 90vh; overflow: auto; }
.staged-popup-card.cal-wide { width: 96vw; max-width: min(680px, 96vw); }
[data-cal-section][hidden] { display: none; }
.cal-hint { color: var(--text-muted); margin: 8px 0; font-size: 0.9em; }
.cal-editor { margin: 8px 0; }
.cal-svg { display: block; width: 100%; height: auto; touch-action: none; user-select: none; -webkit-user-select: none; }
.cal-grid { stroke: var(--border); stroke-width: 1; }
.cal-tick, .cal-axis-title, .cal-readout { fill: var(--text-muted); font-size: 10px; }
.cal-readout { fill: var(--text); font-size: 12px; }
.cal-diag { stroke: var(--text-muted); stroke-width: 1; stroke-dasharray: 4 3; fill: none; }
.cal-curve { stroke: var(--primary); stroke-width: 2; fill: none; stroke-linejoin: round; }
.cal-anchor { cursor: grab; outline: none; }
.cal-hit { fill: transparent; }
.cal-dot { fill: var(--primary); stroke: var(--surface-alt); stroke-width: 1.5; }
.cal-anchor:focus .cal-dot, .cal-anchor:hover .cal-dot { stroke: var(--text); stroke-width: 2; }
.cal-table { width: 100%; border-collapse: collapse; margin: 8px 0; }
.cal-table th, .cal-table td { padding: 2px 4px; text-align: left; border-bottom: 1px solid var(--border); }
.cal-table input { width: 100%; box-sizing: border-box; }
.cal-tools { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.cal-axis-label { margin: 0 0 0 auto; }
.cal-axis-input { width: 9em; }
.cal-note { color: var(--text-muted); margin: 6px 0 0; min-height: 1.2em; font-size: 0.9em; }
.cal-sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }

/* Noise log attachment */
.noise-hint { color: var(--text-muted); font-size: 0.85rem; margin: 6px 0; }
.noise-empty { color: var(--text-muted); margin: 8px 0 0; }
.noise-error { color: var(--danger); margin: 6px 0; }
.noise-list { margin-top: 8px; }
.noise-row { align-items: center; cursor: pointer; -webkit-touch-callout: none; }
.noise-row.noise-busy { opacity: 0.5; pointer-events: none; }
.noise-thumb { flex: 0 0 auto; width: 64px; height: 48px; border-radius: 6px; background: var(--surface-alt); }
.noise-thumb img { width: 64px; height: 48px; object-fit: cover; border-radius: inherit; display: block; -webkit-user-select: none; user-select: none; }
.noise-row .list-row-content input { width: 100%; }
.noise-info { color: var(--text-muted); font-size: 0.8rem; flex-wrap: wrap; }
.noise-overlay { z-index: 210; }
.noise-row-pending { cursor: pointer; align-items: flex-start; }
.noise-pending-title { font-weight: 600; }
.noise-pending-status { margin-top: 2px; }
.noise-pending-failed { color: var(--danger); }
.noise-pending-actions { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 6px; }
.noise-banner { position: fixed; left: 8px; right: 8px; bottom: 8px; z-index: 220; display: flex; flex-wrap: wrap; align-items: center; gap: 8px; padding: 10px 12px; border-radius: 8px; background: var(--surface); border: 1px solid var(--border); box-shadow: 0 2px 12px rgba(0, 0, 0, 0.3); font-size: 0.9rem; }
.noise-banner { padding-right: 40px; }
.noise-banner-text { flex: 1 1 220px; }
.noise-banner-close { position: absolute; top: 4px; right: 4px; width: 32px; height: 32px; border: 0; border-radius: 6px; background: transparent; color: var(--text-muted); font-size: 1.1rem; cursor: pointer; }
.noise-banner-close:hover, .noise-banner-close:focus-visible { background: var(--surface-alt); }
.noise-banner [hidden], .noise-pending-actions [hidden] { display: none !important; }
body.has-noise-banner { padding-bottom: 150px; }
.noise-banner-actions { display: flex; flex-wrap: wrap; gap: 6px; }
.noise-capture-card { max-width: 380px; width: 94%; max-height: 96vh; overflow-y: auto; padding: 12px; }
.noise-capture-head { display: flex; align-items: center; justify-content: space-between; min-height: 40px; margin-bottom: 4px; }
.noise-capture-card .noise-error { font-size: 0.85rem; margin: 4px 0 8px; }
.noise-capture-head h4 { margin: 0; }
.noise-capture-notice { font-size: 0.75rem; line-height: 1.3; margin: 0 0 8px; }
.noise-icon-btn { width: 40px; height: 40px; border: 0; border-radius: 50%; background: transparent; color: var(--text); font-size: 1.3rem; line-height: 1; cursor: pointer; display: inline-flex; align-items: center; justify-content: center; }
.noise-icon-btn:hover, .noise-icon-btn:focus-visible { background: var(--surface-alt); }
.noise-icon-btn[hidden], .noise-bar [hidden], .noise-rec-chip[hidden] { display: none !important; }
.noise-stage { position: relative; }
.noise-rec-chip { position: absolute; top: 8px; left: 8px; display: inline-flex; align-items: center; gap: 5px; padding: 2px 8px; border-radius: 4px; background: rgba(0, 0, 0, 0.6); color: #fff; font: 700 0.75rem sans-serif; letter-spacing: 0.05em; }
.noise-rec-chip i { width: 9px; height: 9px; border-radius: 50%; background: #ff3b30; animation: noise-blink 1s steps(2, start) infinite; }
.noise-stage.is-recording { outline: 3px solid #ff3b30; outline-offset: -3px; }
.noise-status { text-align: center; font-variant-numeric: tabular-nums; }
.noise-status.is-recording { color: #ff3b30; font-weight: 600; }
.noise-bar { display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; gap: 8px; margin-top: 4px; min-height: 72px; }
.noise-bar-side { display: flex; align-items: center; justify-content: flex-start; }
.noise-bar-side-end { justify-content: flex-end; }
.noise-bar-center { display: flex; justify-content: center; align-items: center; }
.noise-save-btn { min-width: 120px; min-height: 48px; font-size: 1rem; }
.noise-record-btn { position: relative; width: 68px; height: 68px; padding: 0; border-radius: 50%; border: 4px solid var(--text); background: transparent; cursor: pointer; display: inline-flex; align-items: center; justify-content: center; transition: border-color 0.2s; -webkit-tap-highlight-color: transparent; }
.noise-record-btn span { display: block; width: 48px; height: 48px; border-radius: 50%; background: #ff3b30; transition: width 0.2s, height 0.2s, border-radius 0.2s, background 0.2s; }
.noise-record-btn:focus-visible { outline: 3px solid var(--primary); outline-offset: 3px; }
.noise-record-btn:active span { transform: scale(0.92); }
.noise-record-btn[data-state="recording"] { border-color: #ff3b30; animation: noise-pulse 1.4s ease-out infinite; }
.noise-record-btn[data-state="recording"] span { width: 26px; height: 26px; border-radius: 6px; }
.noise-record-btn[data-state="starting"], .noise-record-btn[data-state="unsupported"] { border-color: var(--text-muted); opacity: 0.55; cursor: default; }
.noise-record-btn[data-state="starting"] span, .noise-record-btn[data-state="unsupported"] span { background: var(--text-muted); }
.noise-record-btn[data-state="starting"] span { animation: noise-breathe 1s ease-in-out infinite; }
.noise-record-btn[data-state="error"] { border-color: #ffb300; }
.noise-record-btn[data-state="error"] span { width: 48px; height: 48px; background: transparent; color: #ffb300; font-size: 2rem; font-weight: 700; line-height: 48px; text-align: center; }
.noise-record-btn[data-state="error"] span::before { content: "\21BB"; }
.noise-menu { position: relative; }
.noise-menu-panel { position: absolute; right: 0; bottom: calc(100% + 6px); min-width: 190px; padding: 4px; background: var(--surface); border: 1px solid var(--border); border-radius: 8px; box-shadow: 0 2px 12px rgba(0, 0, 0, 0.3); z-index: 5; }
.noise-menu-panel[hidden] { display: none; }
.noise-menu-panel .row-menu-item { display: block; width: 100%; text-align: left; }
@keyframes noise-pulse { 0% { box-shadow: 0 0 0 0 rgba(255, 59, 48, 0.5); } 100% { box-shadow: 0 0 0 14px rgba(255, 59, 48, 0); } }
@keyframes noise-blink { 50% { opacity: 0.25; } }
@keyframes noise-breathe { 50% { opacity: 0.4; } }
@media (prefers-reduced-motion: reduce) { .noise-record-btn, .noise-record-btn span, .noise-rec-chip i { animation: none !important; transition: none !important; } }
.noise-stage { background: #000; border-radius: 6px; overflow: hidden; }
.noise-stage canvas, .noise-stage video { display: block; width: 100%; height: auto; aspect-ratio: 4 / 3; background: #000; }
.noise-stage video[hidden], .noise-stage canvas[hidden] { display: none; }
.noise-status { min-height: 1.3em; margin: 6px 0; font-size: 0.9rem; }
#noise-lightbox video { max-width: 100%; max-height: 80vh; background: #000; }
#noise-lightbox .lightbox-close { z-index: 2; }
.noise-ref-meter { display: flex; align-items: flex-end; gap: 12px; background: #000; color: #fff; border-radius: 6px; padding: 10px; height: 120px; }
.noise-ref-level { font-size: 2rem; font-weight: 700; min-width: 4.5ch; }
.noise-ref-level small { font-size: 0.75rem; font-weight: 400; }
.noise-ref-bars { display: flex; flex: 1; align-items: stretch; gap: 3px; height: 100%; }
.noise-ref-bar-slot { flex: 1; display: flex; align-items: flex-end; }
.noise-ref-bar { width: 100%; height: 0; background: #c9ced6; transition: height 0.08s linear; }
.noise-ref-state { margin: 6px 0; }
