@font-face {
  font-family: "Poppins";
  src: url("../fonts/Poppins-Regular.48cbe3a935fb.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Poppins";
  src: url("../fonts/Poppins-SemiBold.1792e2773e6e.woff2") format("woff2");
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}

:root {
  /* Brand colors */
  --primary: #567c8d;
  --primary-soft: color-mix(in srgb, var(--primary) 18%, white);
  --accent: #b7c688;
  --navy: #2f4156;
  --muted: #6b7280;
  /* v2 visual design (2026-08-08): warm near-white page, pure white cards,
     soft shadow instead of a hard border. */
  --bg: #faf7f4;
  --surface: #ffffff;
  /* Recessed fields inside a white card (search input, avatar fallback). */
  --surface-sunken: #f7f4f1;
  --border: #ebe5df;
  --banner-bg: #e9eff3;
  --success: #16a34a;
  --warning: #d9a441;
  --error: #dc2626;

  /* Typography */
  --font: "Poppins", system-ui, -apple-system, sans-serif;

  /* Spacing scale */
  --s-1: 4px;
  --s-2: 8px;
  --s-3: 12px;
  --s-4: 16px;
  --s-5: 24px;
  --s-6: 32px;
  --s-7: 48px;
  --s-8: 64px;

  /* Radius */
  --radius-sm: 8px;
  --radius-md: 12px;
  --radius-lg: 16px;
  --radius-xl: 20px;

  /* Shadow — cards carry a soft lift rather than a visible border. */
  --shadow-sm: 0 1px 3px rgba(47, 65, 86, 0.05), 0 6px 16px rgba(47, 65, 86, 0.05);
  --shadow-md: 0 2px 6px rgba(47, 65, 86, 0.07), 0 12px 28px rgba(47, 65, 86, 0.08);
  --shadow-elevated: 0 8px 24px rgba(47, 65, 86, 0.12), 0 24px 64px rgba(47, 65, 86, 0.12);
}

* {
  box-sizing: border-box;
}

/* The hidden attribute must always win, even over a component's display rule
   (a class like `display:flex` otherwise beats [hidden]'s UA `display:none`). */
[hidden] {
  display: none !important;
}

body {
  margin: 0;
  font-family: var(--font);
  background: var(--bg);
  color: var(--navy);
  padding-bottom: var(--s-8);
}

/* Form controls do not inherit font-family: the browser forces its own UI font
   (Arial here), so every button and input rendered in Arial inside a Poppins
   design. It showed up as a <button> looking visibly smaller than an <a>
   styled to match it, at identical font-size, weight and line-height. This is
   the root fix; base.css already carried a dozen local `font-family: inherit`
   patches for the same cause, which this makes redundant. */
button,
input,
select,
textarea {
  font-family: inherit;
}

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

/* Type scale — one consistent set of heading sizes across every page, so
   "similar sections" (page titles, card headings, sub-headings) line up
   instead of each bare <h1> falling back to the oversized browser default. */
h1,
h2,
h3 {
  color: var(--navy);
  font-weight: 600;
  line-height: 1.25;
}

h1 { font-size: 1.5rem; margin: 0 0 var(--s-4); }
h2 { font-size: 1.125rem; margin: 0 0 var(--s-3); }
h3 { font-size: 1rem; margin: 0 0 var(--s-2); }

.kp-container {
  max-width: 72rem;
  margin: 0 auto;
  padding: 0 var(--s-4);
}

/* Card primitive */
.card {
  background: var(--surface);
  border: 1px solid transparent;
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  padding: var(--s-5);
  margin-bottom: var(--s-4);
}

/* Modifier for standalone forms (e.g. login) that shouldn't stretch to the
   full width of the wider .kp-container. */
.card-narrow {
  /* Used only by the login card. 28rem gives the logo and the pill inputs
     room to breathe without a two-field form sprawling across the viewport.

     width: 100% is load-bearing. .page-auth is a column flex container, and
     the auto margins below make this a shrink-to-fit flex item: without an
     explicit width it sizes to its content (267px) and never reaches
     max-width, so raising the cap alone changed nothing. */
  width: 100%;
  max-width: 28rem;
  margin-left: auto;
  margin-right: auto;
}

.card-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: var(--s-3);
}

/* Inside a card head the heading sits inline with the badge — drop its margin
   and let the global type scale drive the size (title h1 > section h2/h3). */
.card-head h1,
.card-head h2,
.card-head h3 {
  margin: 0;
}

/* Groups a heading with an adjacent action (e.g. an inline-edit pencil) so
   card-head's space-between treats them as one unit, not a third column. */
.card-head-title {
  display: flex;
  align-items: center;
  gap: var(--s-2);
}

/* Modal shell — mobile-first bottom sheet, centered dialog ≥560px. Shared by
   the capture modal, the project-create modal and the assign modal (any future
   "small form in an overlay" reuses this rather than re-declaring it). */
.modal[hidden] { display: none; }   /* self-contained hide — no reliance on (cached) base.css */
.modal { position: fixed; inset: 0; z-index: 80; display: flex;
  align-items: flex-end; justify-content: center; padding: 0; }
.modal-backdrop { position: absolute; inset: 0; background: rgba(20,25,45,.45); }
.modal-card { position: relative; width: 100%; max-width: 440px; background: var(--surface);
  border: 1px solid var(--border); border-radius: 18px 18px 0 0; box-shadow: var(--shadow-elevated);
  padding: 1.1rem 1.2rem calc(1.2rem + env(safe-area-inset-bottom)); max-height: 92vh; overflow-y: auto; }
@media (min-width: 560px) {
  .modal { align-items: center; padding: 1rem; }
  .modal-card { border-radius: 18px; }
}
.modal-head { display: flex; justify-content: space-between; align-items: center; margin-bottom: .9rem; }
.modal-head strong { font-size: 1.05rem; color: var(--navy); }
.modal-x { border: 0; background: none; font-size: 1.5rem; line-height: 1; cursor: pointer;
  color: var(--muted); padding: 0 .2rem; box-shadow: none; }
.modal-x:hover { background: none; transform: none; color: var(--navy); }
.rec-head-actions { display: inline-flex; gap: .4rem; align-items: center; }
.rec-fields { display: flex; flex-direction: column; gap: .7rem; margin-bottom: .9rem; }
.rec-fields .field { margin: 0; }
.rec-fields .field-label { display: block; font-size: .8rem; color: var(--muted); margin-bottom: .2rem; }
.rec-fields input,
.rec-fields select { width: 100%; padding: .6rem; border: 1px solid var(--border);
  border-radius: var(--radius-sm); font-size: 1rem; font-family: inherit;
  background: var(--surface); color: var(--navy); }
.rec-btn { padding: .55rem 1rem; font-size: .9rem; border-radius: 999px; border: 1px solid var(--border);
  background: transparent; color: var(--navy); cursor: pointer; box-shadow: none; }
.rec-btn:hover { transform: none; box-shadow: none; background: var(--bg); }
.rec-btn.rec-primary, .rec-btn.rec-primary:hover { background: var(--primary); color: #fff; border-color: var(--primary); }

/* Nav bar: brand left, tabs CENTRED, avatar right. The three-column grid is
   what keeps the tabs optically centred on the page regardless of how wide the
   tenant name or the avatar are (flex + space-between would let a long tenant
   name push the tabs off-centre). */
.kp-nav-bar {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: var(--s-4);
  border-bottom: 1px solid var(--border);
  padding: var(--s-4) 0;
  margin-bottom: var(--s-6);
}

.kp-nav-bar > :last-child {
  justify-self: end;
}

/* justify-self is load-bearing: .kp-nav-bar is a grid, and a grid item
   defaults to `stretch`, so without this the (blockified) anchor's box fills
   its whole 1fr column and the focus ring outlines a third of the viewport. */
.kp-brand {
  color: var(--navy);
  text-decoration: none;
  font-weight: 600;
  justify-self: start;
  border-radius: var(--radius-sm);
}

.kp-brand:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
}

.kp-brand-logo {
  display: block;
  height: 32px;
  width: auto;
  /* Caps an unusually wide logo so it scales down instead of crowding the
     tabs. */
  max-width: 45vw;
  object-fit: contain;
}

.auth-logo {
  display: block;
  height: 44px;
  width: auto;
  max-width: 70%;
  object-fit: contain;
  margin-bottom: var(--s-4);
}

.btn-subtle {
  background: transparent;
  color: var(--navy);
  border: 1px solid var(--border);
  box-shadow: none;
  padding: var(--s-1) var(--s-4);
  font-size: 0.85rem;
}

.btn-subtle:hover {
  background: var(--surface);
  color: var(--primary);
  box-shadow: none;
  transform: none;
}

/* .btn-subtle sets only colour, border and padding; the radius and layout come
   from the `button` element rule, which an <a> never matches. Without this an
   <a class="btn-subtle"> renders as underlined inline text in a square box. */
a.btn-subtle {
  display: inline-flex;
  align-items: center;
  border-radius: 999px;
  text-decoration: none;
  font-weight: 600;
}

/* Filled variant of .btn-subtle, sized and painted like an active filter chip
   (.chip / .chip.active): same 40px height and padding, same --primary fill as
   the Sprachaufnahme action button, so a page's emphasised controls read as one
   set. The :hover pair is required, otherwise .btn-subtle:hover repaints it
   back to the outlined look mid-interaction. */
.btn-subtle.btn-solid {
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  min-height: 40px;
  padding: var(--s-2) var(--s-4);
  background: var(--primary);
  border-color: var(--primary);
  color: #fff;
  font-weight: 600;
}

.btn-subtle.btn-solid:hover {
  background: var(--primary);
  border-color: var(--primary);
  color: #fff;
  box-shadow: var(--shadow-sm);
}

/* Desktop tab nav — plain text links, underline marks the active tab */
.kp-tabs {
  display: flex;
  gap: var(--s-5);
  flex-wrap: wrap;
}

.kp-tab {
  color: var(--muted);
  text-decoration: none;
  font-size: 0.9rem;
  padding-bottom: var(--s-2);
  border-bottom: 2px solid transparent;
}

.kp-tab:hover {
  color: var(--accent);
}

.kp-tab.active {
  color: var(--navy);
  font-weight: 600;
  border-bottom-color: var(--primary);
}

.kp-tab.disabled {
  color: var(--muted);
  opacity: 0.5;
  pointer-events: none;
}

/* Floating action button */
.kp-fab {
  position: fixed;
  right: var(--s-5);
  bottom: calc(var(--s-7) + var(--s-4));
  width: 56px;
  height: 56px;
  border-radius: 50%;
  background: var(--primary);
  color: #fff;
  border: none;
  box-shadow: var(--shadow-elevated);
  font-size: 1.75rem;
  font-weight: 600;
  line-height: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  z-index: 20;
}

/* Forms */
/* display:block is load-bearing. .field is applied to both <div class="field">
   and <label class="field">, and a <label> is display:inline by default, where
   vertical margins do not affect layout. The margin below was therefore
   silently dropped on every label-based field, so the same class produced two
   different layouts depending on the tag (project_detail.html uses both and
   was inconsistent with itself). */
.field {
  display: block;
  margin-bottom: var(--s-4);
}

.field label {
  display: block;
  font-size: 0.875rem;
  margin-bottom: var(--s-1);
}

.field input {
  width: 100%;
  padding: var(--s-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  font-size: 1rem;
}

.errors {
  color: var(--error);
  font-size: 0.875rem;
  margin-bottom: var(--s-4);
  list-style: none;
  padding: 0;
}

button {
  padding: var(--s-3) var(--s-5);
  background: var(--primary);
  color: #fff;
  border: none;
  border-radius: 999px;
  font-size: 0.95rem;
  font-weight: 600;
  cursor: pointer;
  box-shadow: var(--shadow-sm);
  transition: transform 0.15s ease, box-shadow 0.15s ease, background 0.15s ease;
}

button:hover {
  background: var(--accent);
  box-shadow: var(--shadow-md);
  transform: translateY(-2px);
}

/* Status badge */
.badge {
  display: inline-block;
  padding: var(--s-1) var(--s-3);
  border-radius: 999px;
  font-size: 0.8rem;
  background: var(--border);
  color: var(--navy);
}

.badge.uploaded,
.badge.transcribing {
  background: var(--primary-soft);
  color: var(--primary);
}

.badge.done {
  background: #e6f6ea;
  color: var(--success);
}

.badge.error {
  background: #fde8e8;
  color: var(--error);
}

/* Recordings toolbar: search + status filter + sort (a plain GET form) */
.list-toolbar {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-3);
  align-items: center;
  margin-bottom: var(--s-5);
}

.list-toolbar .toolbar-search {
  flex: 1 1 220px;
  min-width: 0;
}

.list-toolbar .toolbar-search,
.list-toolbar select {
  padding: var(--s-2) var(--s-3);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  font-size: 0.9rem;
  font-family: inherit;
  color: var(--navy);
  background: var(--surface);
}

.list-toolbar select {
  cursor: pointer;
}

/* Group-by heading above a grid of that group's recordings */
.group-heading {
  margin: var(--s-6) 0 var(--s-3);
  padding-bottom: var(--s-2);
  border-bottom: 1px solid var(--border);
  display: flex;
  align-items: baseline;
  gap: var(--s-2);
}

.group-heading:first-of-type {
  margin-top: 0;
}

.group-count {
  font-size: 0.85rem;
  font-weight: 400;
  color: var(--muted);
}

/* Recording list: card-per-recording grid */
.entity-grid {
  margin-bottom: var(--s-4);
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: var(--s-4);
}

.entity-card {
  display: flex;
  flex-direction: column;
  text-decoration: none;
  color: inherit;
}

.entity-card:hover {
  box-shadow: var(--shadow-md);
  transform: translateY(-2px);
}

/* Title spans the full tile width and clamps to two lines, so a long title
   never collides with the status badge (which now lives in the footer row).
   The reserved two-line height keeps every tile the same height. */
.entity-title {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  min-height: 2.5em;
  margin: 0 0 var(--s-3);
  overflow-wrap: anywhere;
}

/* Footer pinned to the bottom of the tile: date on the left, badge on the
   right. Wraps the badge below the date only if the tile is very narrow. */
.entity-foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-1) var(--s-2);
  margin-top: auto;
}

.entity-foot .meta {
  margin: 0;
}

.empty {
  color: var(--muted);
}

/* Hides an input visually while keeping it functional and accessible
   (used for the file input triggered by the mic-FAB label). */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* Detail page top bar: back link + destructive action */
.btn-danger {
  background: transparent;
  color: var(--error);
  border: 1px solid color-mix(in srgb, var(--error) 35%, var(--border));
  box-shadow: none;
  padding: var(--s-1) var(--s-4);
  font-size: 0.85rem;
}

.btn-danger:hover {
  background: color-mix(in srgb, var(--error) 10%, transparent);
  color: var(--error);
  box-shadow: none;
  transform: none;
}

/* Details card: view + edit of the AI fields (title/category/customer/address) */
.meta-list {
  margin: 0;
  display: grid;
  gap: var(--s-2);
}

.meta-list > div {
  display: grid;
  grid-template-columns: 7rem 1fr;
  gap: var(--s-3);
  align-items: baseline;
}

.meta-list dt {
  color: var(--muted);
  font-size: 0.85rem;
}

.meta-list dd {
  margin: 0;
  color: var(--navy);
  font-size: 0.85rem;
}

@media (max-width: 480px) {
  .meta-list > div { grid-template-columns: 1fr; gap: 0; }
}

.meta-form .field-label {
  display: block;
  font-size: 0.8rem;
  color: var(--muted);
  margin-bottom: var(--s-1);
}

.meta-form .field select {
  width: 100%;
  padding: var(--s-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  font-size: 1rem;
  font-family: inherit;
  background: var(--surface);
  color: var(--navy);
}

/* A field label with an affordance beside it (e.g. the Kunde rename pencil).
   The <label> keeps the `for` association; the button is a sibling so that
   clicking it does not also activate the labelled control. */
.meta-form .field-label-row {
  display: flex;
  align-items: center;
  gap: var(--s-1);
}

/* A bare glyph sitting on the label baseline: no padding, no background, no
   button chrome. Anything more reads as a second control competing with the
   field itself. */
.icon-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  border: none;
  background: transparent;
  color: var(--muted);
  cursor: pointer;
  box-shadow: none;
  line-height: 1;
}

.icon-btn .icon {
  width: 0.9em;
  height: 0.9em;
  vertical-align: baseline;
}

.icon-btn:hover {
  background: transparent;
  color: var(--primary);
  box-shadow: none;
  transform: none;
}

.icon-btn[aria-expanded="true"] {
  color: var(--primary);
}

/* Löschen sits bottom-left, away from Speichern: destructive and constructive
   actions should not be adjacent targets. */
.meta-form-actions {
  display: flex;
  justify-content: flex-end;
  gap: var(--s-3);
  margin-top: var(--s-3);
}

.meta-form-actions .btn-danger {
  margin-right: auto;
}

/* Audio player */
.audio-player {
  width: 100%;
  margin: var(--s-4) 0 var(--s-2);
}

/* Playback-speed control under the audio player */
.audio-speed {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  margin-bottom: var(--s-3);
}

.audio-speed-label {
  font-size: 0.8rem;
  color: var(--muted);
}

.audio-speed button {
  padding: var(--s-1) var(--s-3);
  font-size: 0.8rem;
  font-weight: 500;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: transparent;
  color: var(--navy);
  box-shadow: none;
  cursor: pointer;
}

.audio-speed button:hover {
  transform: none;
  box-shadow: none;
  background: var(--surface);
}

.audio-speed button.active,
.audio-speed button.active:hover {
  background: var(--primary);
  color: #fff;
  border-color: var(--primary);
}

/* Row of actions at the foot of a card (Kopieren + Neu generieren) */
.card-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-3);
  align-items: center;
  margin-top: var(--s-4);
}

/* "Transcription running" state with a live pulse */
.processing-state {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s-2) var(--s-3);
}

.processing-hint {
  color: var(--muted);
  font-size: 0.9rem;
}

/* Transcript */
.transcript-details {
  margin-top: var(--s-4);
}

.transcript-details summary {
  cursor: pointer;
  color: var(--primary);
  font-size: 0.9rem;
}

.transcript {
  white-space: pre-wrap;
  line-height: 1.5;
  margin-top: var(--s-3);
}

.meta {
  color: var(--muted);
  font-size: 0.85rem;
  margin-bottom: var(--s-5);
}

.error-msg {
  color: var(--error);
}

/* Summary card — a calm, consistent surface like every other card (not a heavy
   dark block), with a thin left accent bar so it still reads as the primary
   insight without shouting. */
.insight-hero {
  border-left: 3px solid var(--primary);
}

.insight-hero #summary-text {
  font-size: 0.95rem;
  line-height: 1.6;
  margin-top: 0;
}

.insight-hero #summary-key-points {
  padding-left: var(--s-5);
}

.insight-hero #summary-key-points li {
  font-size: 0.95rem;
  line-height: 1.5;
}

/* Pulsing "generating" indicator */
.pulse-pill {
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  font-size: 0.9rem;
}

.pulse-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: currentColor;
  animation: pulse 1.2s ease-in-out infinite;
}

@keyframes pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.3; }
}

/* Extraction card: exactly three text levels — the card title (h2), section
   labels (h3), and one uniform body treatment for ALL content (the lead
   sentence, item lines, materials, open questions) so nothing drifts in size. */
.extraction-list h3 {
  margin: var(--s-4) 0 var(--s-2);
}

.extraction-list h3:first-child {
  margin-top: 0;
}

.extraction-list p,
.extraction-list li {
  font-size: 0.95rem;
  line-height: 1.5;
  color: var(--muted);
}

.extraction-list p {
  margin: 0 0 var(--s-2);
}

.extraction-lead {
  margin-bottom: var(--s-4);
}

.extraction-list ul {
  list-style: none;
  padding: 0;
  margin: 0;
}

.extraction-list li {
  padding: var(--s-1) 0;
}

/* Protocol (recording hero) — topic headings + bulleted notes, Granola-style.
   Kept distinct from .extraction-list so the protocol shows real bullets while
   the project extraction keeps its marker-less layout. */
.protocol-body h3 {
  margin: var(--s-4) 0 var(--s-2);
  color: var(--navy);
}
.protocol-body h3:first-child {
  margin-top: 0;
}
.protocol-body ul {
  list-style: disc;
  margin: 0 0 var(--s-3);
  padding-left: 1.35rem;
}
.protocol-body li {
  font-size: 0.95rem;
  line-height: 1.5;
  color: var(--navy);
  padding: var(--s-1) 0;
}

.hidden {
  display: none;
}

/* Toast notification */
.kp-toast {
  position: fixed;
  left: 50%;
  bottom: var(--s-6);
  transform: translateX(-50%);
  background: var(--navy);
  color: #fff;
  padding: var(--s-3) var(--s-5);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-md);
  font-size: 0.85rem;
  z-index: 30;
}

/* ===========================================================================
   Capture UI — moved out of recordings/_capture_modal.html's inline <style>
   during the 2026-08-08 UI revamp (templates keep markup, styling lives here).
   =========================================================================== */

.upload-queue { position: fixed; right: 1rem; bottom: 5.5rem; width: 340px; max-width: 92vw;
  background: var(--surface); border: 1px solid var(--border); border-radius: 12px; z-index: 60;
  box-shadow: var(--shadow-elevated); padding: .6rem .8rem; max-height: 60vh; overflow-y: auto; }
.upload-queue-head { display: flex; justify-content: space-between; align-items: center; margin-bottom: .4rem; }
#upload-queue-close { border: 0; background: none; font-size: 1.2rem; line-height: 1; cursor: pointer; color: var(--muted); }
#upload-queue-close:hover { background: none; transform: none; box-shadow: none; }
.upload-item { margin: .5rem 0; font-size: .85rem; }
.upload-item .upload-name { display: block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.upload-bar { height: 6px; background: var(--primary-soft); border-radius: 999px; overflow: hidden; margin: .25rem 0; }
.upload-bar-fill { height: 100%; width: 0; background: var(--primary); transition: width .12s ease; }
.upload-item.done .upload-bar-fill { background: var(--success); }
.upload-item.failed .upload-bar-fill { background: var(--error); }
.upload-state { color: var(--muted); font-size: .78rem; }

/* FAB row: mic + upload, same style, side by side */
.kp-fab-row { position: fixed; right: var(--s-5); bottom: calc(var(--s-7) + var(--s-4));
  display: flex; align-items: center; gap: .8rem; z-index: 20; }
.kp-fab-row .kp-fab { position: static; right: auto; bottom: auto; }
/* Mic glyph as text (emoji) — renders at font-size, can't be shrunk like an inline SVG */
#rec-open .mic-glyph { font-size: 1.7rem; line-height: 1; }

#rec-settings-btn { font-size: 1.15rem; }
.rec-mic-row { display: flex; gap: .6rem; align-items: flex-end; margin-bottom: .9rem; }
.rec-mic-row select { width: 100%; padding: .5rem; border: 1px solid var(--border);
  border-radius: var(--radius-sm); font-size: .95rem; font-family: inherit; background: var(--surface); color: var(--navy); }
.rec-meter { display: flex; align-items: center; gap: .5rem; margin: .2rem 0 .5rem; }
.rec-dot { width: 10px; height: 10px; border-radius: 50%; background: var(--error);
  animation: pulse 1.2s ease-in-out infinite; }
.rec-dot.paused { animation: none; opacity: .45; }
.rec-time { font-variant-numeric: tabular-nums; font-weight: 600; color: var(--navy); }
.rec-state { color: var(--muted); font-size: .85rem; }
.rec-level { height: 9px; background: var(--border); border-radius: 999px; overflow: hidden; margin: .1rem 0 .6rem; }
.rec-level-fill { height: 100%; width: 0; border-radius: 999px;
  background: linear-gradient(90deg, #2f7d5d, #d9a441 65%, #c0392b); transition: width .06s linear; }
.rec-preview { width: 100%; margin: .2rem 0 .6rem; }
#rec-error { margin: .2rem 0 .6rem; font-size: .85rem; }
.rec-controls { display: flex; flex-wrap: wrap; gap: .5rem; }

/* Small helpers used by the modal field rows */
.field-hint { margin: 0; font-size: .85rem; color: var(--muted); }
.field-stacked { margin-top: .5rem; }

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

.landing-greeting { margin-bottom: var(--s-5); }

/* Capture + create actions. The upload control is a <label>, not a <button>,
   so the shared look lives on the class rather than on the element type. */
.action-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-3);
  margin-bottom: var(--s-6);
}

.action-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--s-2);
  padding: var(--s-3) var(--s-5);
  min-height: 44px;
  background: var(--primary);
  color: #fff;
  border: none;
  border-radius: 999px;
  font-size: 0.95rem;
  font-weight: 600;
  font-family: inherit;
  cursor: pointer;
  box-shadow: var(--shadow-sm);
  transition: transform 0.15s ease, box-shadow 0.15s ease, background 0.15s ease;
}

/* The upload "+" is a <label>, so it never matched the global button:hover
   rule and stayed inert while its neighbours lifted. Hover lives on the class
   so every capture/create control behaves identically. */
.kp-fab:hover,
.action-btn:hover {
  background: var(--accent);
  box-shadow: var(--shadow-md);
  transform: translateY(-2px);
}

/* Unassigned-recordings banner: same accent bar as the insight hero, so
   "this needs your attention" reads consistently across the app. */
.banner-unassigned { border-left: 3px solid var(--primary); }

.assign-list { list-style: none; margin: 0; padding: 0; }

.assign-list li {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  padding: var(--s-2) 0;
  border-top: 1px solid var(--border);
}

.assign-list li:first-child { border-top: 0; }
.assign-list li a { flex: 1 1 auto; }
.assign-list li .meta { margin: 0; }
.assign-list li button { margin-left: auto; }

/* One-line version of the same nudge, on the projects page. */
.banner-line {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  flex-wrap: wrap;
  margin: 0 0 var(--s-4);
  color: var(--muted);
  font-size: 0.9rem;
}

/* ===========================================================================
   Entity cards (recordings AND projects) + project pills
   =========================================================================== */

.pill-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-2);
  margin-bottom: var(--s-2);
}

.pill {
  display: inline-block;
  padding: 2px var(--s-3);
  border-radius: 999px;
  font-size: 0.78rem;
  line-height: 1.6;
}

/* Customer filled, category outlined: the customer is the card's owner, the
   category a secondary tag. */
.pill-customer { background: var(--primary-soft); color: var(--primary); }
.pill-category { background: transparent; border: 1px solid var(--border); color: var(--muted); }

.entity-sub {
  margin: 0 0 var(--s-3);
  color: var(--muted);
  font-size: 0.85rem;
  overflow-wrap: anywhere;
}

/* Per-card state: red for a failed recording, pulsing for one still running. */
.state-dot { width: 8px; height: 8px; border-radius: 50%; flex: 0 0 auto; }
.state-error { background: var(--error); }
.state-processing { background: var(--primary); animation: pulse 1.2s ease-in-out infinite; }

/* ===========================================================================
   Filter chips (rendered only when their count is above zero)
   =========================================================================== */

.chip-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-2);
  margin-bottom: var(--s-5);
}

.chip {
  padding: var(--s-1) var(--s-4);
  border: 1px solid var(--border);
  border-radius: 999px;
  font-size: 0.82rem;
  color: var(--navy);
  background: var(--surface);
  text-decoration: none;
}

.chip:hover { border-color: var(--primary); }
.chip.active { background: var(--primary); border-color: var(--primary); color: #fff; }

.group-link { margin-left: auto; font-size: 0.85rem; font-weight: 400; }

.back-link {
  display: inline-block;
  margin-bottom: var(--s-4);
  font-size: 0.85rem;
}

/* ===========================================================================
   Flash messages (the non-member redirect explains itself through these)
   =========================================================================== */

.messages { list-style: none; margin: 0 0 var(--s-4); padding: 0; }

.message {
  padding: var(--s-3) var(--s-4);
  border-radius: var(--radius-md);
  font-size: 0.9rem;
  margin-bottom: var(--s-2);
}

.message.error { background: #fde8e8; color: var(--error); }
.message.success { background: #e6f6ea; color: var(--success); }

/* ===========================================================================
   Login page. It blanks the nav block, and the nav bar is what supplies the
   top spacing on every other page, so without this the card sits flush
   against the viewport edge.
   =========================================================================== */

.page-auth {
  display: flex;
  flex-direction: column;
  justify-content: center;
  min-height: 80vh;
  padding: var(--s-7) 0;
}

/* Pill-style inputs, scoped to the login page only — .field is shared by
   every modal and the project/recording edit forms, which weren't asked
   for and shouldn't change incidentally. */
.page-auth .field input {
  border-radius: 999px;
  padding: var(--s-3) var(--s-5);
  min-height: 44px;
  border: 1px solid var(--border);
  background: var(--surface);
}

/* ===========================================================================
   Mobile. On-site capture is phone-in-hand, so every screen is checked at
   360px: single-column cards, full-width controls, no horizontal scroll.
   =========================================================================== */

@media (max-width: 520px) {
  .entity-grid { grid-template-columns: 1fr; }

  .action-row { flex-direction: column; align-items: stretch; }
  .action-row .action-btn { width: 100%; }

  .list-toolbar { flex-direction: column; align-items: stretch; }
  .list-toolbar .toolbar-search,
  .list-toolbar select,
  .list-toolbar button { width: 100%; min-height: 44px; }

  .assign-list li { flex-wrap: wrap; }
  .assign-list li button { margin-left: 0; }

  /* This block used to carry `.kp-nav-bar { flex-wrap: wrap }`, which was inert
     (.kp-nav-bar is a grid, not a flex container). The nav's real mobile reflow
     lives in the second max-width:520px block further down, which is the single
     owner of it: do not re-declare grid-template-columns here, it would only be
     overridden by that later block. */
  .kp-nav-bar { gap: var(--s-3); }
  .kp-tabs { gap: var(--s-4); }
  .kp-brand-logo { height: 24px; }
}

/* Even spacing on the project detail page: each section heading sits one
   card-gap below the block above it. The header card and the card grid share
   the same bottom margin, so dropping the heading's own top margin makes both
   gaps identical. (Was an inline <style> in project_detail.html.) */
.group-heading-flush { margin-top: 0; }

/* ===========================================================================
   v2 visual design (2026-08-08). Spec: the "Amendment: v2 visual design"
   section of docs/superpowers/specs/2026-08-08-ui-revamp-design.md
   =========================================================================== */

/* Inline SVG icons inherit the colour of the text they sit beside. */
.icon {
  width: 1.05em;
  height: 1.05em;
  flex: 0 0 auto;
  vertical-align: -0.15em;
}

/* ---- Account menu (replaces the top-bar Abmelden button) ---------------- */

.user-menu { position: relative; }

.user-avatar {
  width: 40px;
  height: 40px;
  padding: 0;
  border-radius: 50%;
  background: var(--primary);
  color: #fff;
  border: none;
  font-size: 0.95rem;
  font-weight: 600;
  box-shadow: none;
  cursor: pointer;
}

.user-avatar:hover {
  background: var(--primary);
  transform: none;
  box-shadow: var(--shadow-sm);
}

.user-menu-panel {
  position: absolute;
  right: 0;
  top: calc(100% + var(--s-2));
  min-width: 12rem;
  background: var(--surface);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-md);
  padding: var(--s-2);
  z-index: 70;
}

.user-menu-name {
  margin: 0;
  padding: var(--s-2) var(--s-3);
  font-size: 0.85rem;
  color: var(--muted);
  border-bottom: 1px solid var(--border);
}

.user-menu-item {
  display: block;
  width: 100%;
  text-align: left;
  padding: var(--s-3);
  margin-top: var(--s-1);
  background: transparent;
  color: var(--navy);
  border: none;
  border-radius: var(--radius-sm);
  font-size: 0.9rem;
  font-weight: 500;
  box-shadow: none;
  cursor: pointer;
}

.user-menu-item:hover {
  background: var(--surface-sunken);
  color: var(--navy);
  transform: none;
  box-shadow: none;
}

/* The menu holds both a link (Konto) and a submit button (Abmelden); the link
   needs the underline removed to read as the same row as the button. */
a.user-menu-item {
  text-decoration: none;
}

/* ---- Account page ------------------------------------------------------- */

/* Everything below is scoped to .account-page. The page stacks four cards of
   short forms, where the app-wide button size and the 0-top-margin heading
   rules read as cramped; other screens are wider and are left alone. */

/* Two columns on a wide viewport (Konto | Passwort, then Sicherheit |
   Richtlinie), one column below 900px. 900px rather than the sheet's usual
   520px because two 28rem cards plus the gap need ~920px before side-by-side
   stops being cramped. The grid drives the spacing, so the cards drop their
   own bottom margin. */
.account-page {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--s-5);
  /* Grid's default `stretch` is kept on purpose so both cards in a row share a
     height and the row reads as one band. The dead space that would otherwise
     leave in the shorter card is taken up by the rule below. */
}

.account-page .card {
  margin-bottom: 0;
  display: flex;
  flex-direction: column;
}

/* When a card ENDS in a form, that form absorbs the stretch and drops its
   action row to the card's bottom edge, so the buttons of both cards in a row
   sit on the same line instead of one floating mid-card. Fields stay put at
   the top: only .meta-form-actions moves.

   :last-child is the whole trick. The Konto card ends in a <p>, not a form, so
   its Speichern button is left where the content puts it; Passwort and
   Richtlinie do end in a form and so line up against it. */
.account-page .card > form:last-child {
  display: flex;
  flex: 1;
  flex-direction: column;
}

.account-page .card > form:last-child .meta-form-actions {
  margin-top: auto;
  /* padding, not margin: `margin-top: auto` replaces the 16px margin, and when
     the card has no slack left auto resolves to 0 and the button ends up flush
     against the last input. Padding is immune to that, so this is the floor. */
  padding-top: var(--s-4);
}

/* Full-width above the grid rather than sitting in the first cell. */
.account-page .back-link {
  grid-column: 1 / -1;
}

@media (min-width: 900px) {
  .account-page {
    grid-template-columns: 1fr 1fr;
    /* Two 28rem cards plus the gap. Without this the grid fills .kp-container's
       72rem and the cards, still capped at 28rem and auto-centred, sit marooned
       with a gutter between them. */
    max-width: 60rem;
    margin-inline: auto;
  }

  .account-page .card-narrow {
    max-width: none;
  }
}

/* Smaller than the app-wide pill: these are settings-form actions, not the
   page's primary call to action, and the narrow card exaggerates their size. */
.account-page button,
.account-page a.btn-subtle {
  padding: var(--s-2) var(--s-4);
  font-size: 0.875rem;
  line-height: 1.25;
}

/* Two things made this link-button bigger than the <button>s beside it:
   btn-solid pins a 40px min-height for the toolbar rows it was built for, and
   .btn-subtle carries a 1px border where the `button` element rule sets
   border: none, so identical padding still rendered 2px taller and wider.
   btn-solid paints background and border the same --primary, so dropping the
   border changes the size and nothing else. */
.account-page a.btn-subtle.btn-solid {
  min-height: 0;
  border: none;
}

/* Binds the label to its own input: 1.25 line-height leaves visible leading
   under a 0.8rem label, which works against the 4px margin. */
.account-page .meta-form .field-label {
  line-height: 1.2;
}

/* The last .field's 16px bottom margin stacked with the action row's own top
   margin, so the save button sat in a 32px pocket, wider than any other gap on
   the card. Drop the field's margin and let one deliberate gap do the work. */
.account-page .meta-form .field:last-of-type {
  margin-bottom: 0;
}

.account-page .meta-form-actions {
  margin-top: var(--s-4);
}

/* Same double-margin below: 24px margin plus 16px padding put the rule 40px
   under the button and only 16px above the list it introduces, so it read as
   belonging to the button. Even it out. */
.account-page .account-readonly {
  margin-top: var(--s-5);
  padding-top: var(--s-5);
}

/* The h1 is 1.5rem; 12px under it is tighter than the 16px rhythm the fields
   below use, which made the heading look stuck to the first label. */
.account-page .card-head {
  margin-bottom: var(--s-4);
}

/* .account-note sets margin: top-only, because everywhere else it is the last
   thing in a card. In the policy card it introduces a form, so without a
   bottom gap the "Wirksam für ..." status line collides with the first field
   label. Scoped to .meta-form so the recovery-codes form, which is a bare
   <form> whose .meta-form-actions already supplies the gap, is not doubled. */
.account-page .account-note + .meta-form {
  margin-top: var(--s-4);
}

/* The global h2/h3 rules set margin-top: 0, which is right for a heading that
   opens a card and wrong for one that starts a new section partway down it.
   Give only the latter its own top space. */
.account-page .meta-form-actions + h3,
.account-page form + h3,
.account-page ul + h3,
.account-page p + h3 {
  margin-top: var(--s-6);
}

/* A subsection heading sitting directly under its card's h2 needs separation,
   but not a full section break. */
.account-page h2 + h3,
.account-page .codes-panel + h3 {
  margin-top: var(--s-4);
}

/* The last control in a card should not touch the card's bottom padding. */
.account-page .card > form:last-child .meta-form-actions {
  margin-bottom: 0;
}

/* Read-only identity (username, workspace), below the editable fields. The
   top border separates "what you can change" from "what you cannot". */
.account-readonly {
  /* The form above ends in a right-aligned pill button with no bottom margin,
     so without this margin the divider is drawn straight through it. */
  margin-top: var(--s-5);
  padding-top: var(--s-4);
  border-top: 1px solid var(--border);
}

/* Pills instead of label/value rows plus a footnote: the same three facts in
   one line rather than four, which is most of why this card used to tower over
   its row partner. */
.account-ids {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-2);
  margin: 0;
}

/* The title plus both pills is wider than the ~400px of card interior, so the
   head wraps to a second line instead of overflowing. margin-left: auto keeps
   the pills right-aligned on the wider viewports where they do fit. */
.account-page .card-head {
  flex-wrap: wrap;
  gap: var(--s-2) var(--s-3);
}

.account-page .card-head .account-ids {
  margin-left: auto;
}

/* Stacked two-line pills: label above value. Narrower than the side-by-side
   form, which is what lets both sit on the title's line instead of wrapping
   under it. Scoped to .account-ids so the single-line .attr-chip used for
   materials on the project overview is untouched.

   cursor: help because the tooltip is now the only place the "admin changes
   these" note lives, so hovering has to look like it does something. */
.account-ids .attr-chip {
  position: relative;
  flex-direction: column;
  align-items: center;
  gap: 1px;
  /* Roomier than the single-line chip: at two lines the 999px radius resolves
     to a stadium curve that would otherwise crowd the text at the corners. */
  padding: var(--s-2) var(--s-5);
  line-height: 1.3;
  text-align: center;
  cursor: help;
}

/* Tooltip. Below the pill rather than above: these sit at the top of the card,
   where anything drawn upward runs into the nav bar. */
.account-ids .attr-chip::after {
  content: attr(data-tooltip);
  position: absolute;
  top: calc(100% + var(--s-2));
  left: 50%;
  z-index: 20;
  width: max-content;
  max-width: 14rem;
  padding: var(--s-2) var(--s-3);
  border-radius: var(--radius-sm);
  background: var(--navy);
  color: #fff;
  font-size: 0.72rem;
  font-weight: 400;
  line-height: 1.35;
  text-align: center;
  white-space: normal;
  transform: translateX(-50%);
  opacity: 0;
  /* Never intercept the pointer, or the tooltip covering the pill would make
     the hover flicker as focus bounces between the two. */
  pointer-events: none;
  transition: opacity 0.12s ease;
}

.account-ids .attr-chip:hover::after,
.account-ids .attr-chip:focus-visible::after {
  opacity: 1;
}

/* The label stays muted (inherited from .attr-chip); the value is the thing
   being read, so it gets the body colour and weight. */
.attr-chip-value {
  margin-left: var(--s-2);
  color: var(--navy);
  font-weight: 600;
}

/* Stacked, so the value sits under its label rather than beside it. */
.account-ids .attr-chip-value {
  margin-left: 0;
}

.account-note {
  margin: var(--s-2) 0 0;
  color: var(--muted);
  font-size: 0.8rem;
}

/* Confirmed second factors. Previously had no CSS at all, so it rendered as a
   default bulleted <ul> despite each row carrying a remove button. */
.device-list {
  list-style: none;
  margin: 0 0 var(--s-4);
  padding: 0;
}

.device-list li {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-4);
  padding: var(--s-3) 0;
  border-bottom: 1px solid var(--border);
}

.device-list li:last-child {
  border-bottom: none;
}

.device-name {
  font-size: 0.9rem;
  font-weight: 600;
}

.device-detail {
  display: block;
  color: var(--muted);
  font-size: 0.8rem;
  font-weight: 400;
}

/* One-time recovery codes. Shown exactly once, so this is the only place the
   plaintext ever exists: it gets a highlighted panel rather than the red
   .errors styling it used to borrow. */
.codes-panel {
  margin-bottom: var(--s-5);
  padding: var(--s-4);
  border: 1px solid var(--success);
  border-radius: var(--radius-md);
  background: #e6f6ea;
}

.codes-panel-lead {
  margin: 0 0 var(--s-3);
  color: var(--success);
  font-size: 0.875rem;
  font-weight: 600;
}

.codes-list {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--s-2) var(--s-4);
  list-style: none;
  margin: 0;
  padding: 0;
}

.codes-list code {
  font-size: 0.9rem;
  letter-spacing: 0.05em;
}

/* ---- Page header (title + subtitle + one primary action) ---------------- */

.page-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--s-4);
  margin-bottom: var(--s-5);
}

.page-head h1 { margin: 0; }

/* Variant for a head whose action is a control rather than a label. A 40px
   button makes the row taller than the 30px heading, so centring is what keeps
   the two optically aligned.

   Centring alone, though, splits the 10px difference and pushes the heading
   5px below where it sits on every page whose head has no action (compare
   Angebote and the landing greeting, both at the same offset). Pulling the row
   up by that half-difference puts the heading back on their line while leaving
   the button centred against it.

   The calc spells out the derivation rather than hiding a -5px: h1 is 1.5rem at
   the 1.25 body line-height, the action is .btn-subtle.btn-solid's 40px
   min-height. Update it if either changes. */
.page-head-inline {
  align-items: center;
  margin-top: calc((1.5rem * 1.25 - 40px) / 2);
  margin-bottom: var(--s-4);
}

.page-subtitle {
  margin: var(--s-1) 0 0;
  color: var(--muted);
  font-size: 0.95rem;
}

/* ---- Landing action row ------------------------------------------------- */

/* Equal columns on purpose: the primary action is emphasised by colour, not
   by being wider than its neighbours. */
.action-row {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--s-3);
  margin-bottom: var(--s-5);
}

/* Icon sits left of the label on all three, so the row reads as one set. */
.action-btn {
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: center;
  gap: var(--s-2);
  min-height: 60px;
  padding: var(--s-3) var(--s-4);
  border-radius: var(--radius-md);
  background: var(--surface);
  color: var(--navy);
  border: none;
  box-shadow: var(--shadow-sm);
  font-family: inherit;
  font-size: 0.88rem;
  font-weight: 600;
  cursor: pointer;
  transition: transform 0.15s ease, box-shadow 0.15s ease, background 0.15s ease;
}

.action-btn .icon { width: 1.15rem; height: 1.15rem; }

/* Two-button variant of .action-row (e.g. project detail: mic + upload,
   no "Neues Projekt" since we're already inside one). */
.action-row-2 { grid-template-columns: repeat(2, 1fr); }

.action-btn-primary {
  background: var(--primary);
  color: #fff;
}

.action-btn:hover {
  box-shadow: var(--shadow-md);
  transform: translateY(-2px);
  background: var(--surface);
  color: var(--navy);
}

.action-btn-primary:hover {
  background: var(--primary);
  color: #fff;
}

/* ---- Unassigned-recordings banner --------------------------------------- */

.banner-unassigned {
  background: var(--banner-bg);
  border-radius: var(--radius-lg);
  padding: var(--s-4) var(--s-5);
  margin-bottom: var(--s-6);
}

.banner-row {
  display: flex;
  align-items: center;
  gap: var(--s-3);
}

/* The unassigned recordings live inside the banner, revealed by its Zuordnen
   button, so the summary and the thing you act on are one component instead of
   two sections repeating the same count. */
.banner-list {
  display: flex;
  flex-direction: column;
  gap: var(--s-2);
  margin-top: var(--s-4);
  padding-top: var(--s-4);
  border-top: 1px solid rgba(47, 65, 86, 0.12);
}

.banner-list .row-item {
  background: var(--surface);
  box-shadow: none;
  padding: var(--s-3) var(--s-4);
}

.banner-text { flex: 1 1 auto; }

.banner-title {
  margin: 0;
  font-size: 0.95rem;
  font-weight: 600;
  color: var(--navy);
}

.banner-sub {
  margin: 2px 0 0;
  font-size: 0.85rem;
  color: var(--muted);
}

.banner-cta {
  background: var(--surface);
  color: var(--navy);
  border: none;
  border-radius: 999px;
  padding: var(--s-3) var(--s-5);
  font-size: 0.78rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  box-shadow: var(--shadow-sm);
  cursor: pointer;
}

.banner-cta:hover {
  background: var(--surface);
  color: var(--primary);
  box-shadow: var(--shadow-md);
  transform: translateY(-1px);
}

/* ---- Section headings --------------------------------------------------- */

.section-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s-3);
  margin: var(--s-6) 0 var(--s-4);
}

.section-head h2 { margin: 0; }

.section-count {
  font-size: 0.9rem;
  font-weight: 400;
  color: var(--muted);
  margin-left: var(--s-2);
}

/* ---- Filter card (search + chips) --------------------------------------- */

.filter-card {
  background: var(--surface);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  padding: var(--s-4);
  margin-bottom: var(--s-5);
}

.search-field {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  background: var(--surface-sunken);
  border-radius: 999px;
  padding: 0 var(--s-4);
  margin-bottom: var(--s-3);
}

.search-field .icon {
  color: var(--muted);
  width: 1.15rem;
  height: 1.15rem;
}

.search-field input {
  flex: 1 1 auto;
  min-width: 0;
  border: none;
  background: transparent;
  padding: var(--s-3) 0;
  font-family: inherit;
  font-size: 0.95rem;
  color: var(--navy);
  min-height: 44px;
}

.search-field input:focus { outline: none; }

.filter-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s-2);
}

/* Native select carets sit hard against the right edge, which looks cramped
   inside a pill. Draw our own so its distance from the edge is ours to set. */
.filter-row select {
  appearance: none;
  -webkit-appearance: none;
  padding: var(--s-2) var(--s-3);
  padding-right: var(--s-8);
  min-height: 40px;
  border: 1px solid var(--border);
  border-radius: 999px;
  background-color: var(--surface);
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%236b7280' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='m6 9 6 6 6-6'/></svg>");
  background-repeat: no-repeat;
  background-position: right var(--s-4) center;
  color: var(--navy);
  font-family: inherit;
  font-size: 0.85rem;
  cursor: pointer;
}

.filter-row .btn-search { margin-left: auto; }

/* Chips: pill filters, the active one filled. */
.chip {
  display: inline-flex;
  align-items: center;
  padding: var(--s-2) var(--s-4);
  min-height: 40px;
  border: 1px solid var(--border);
  border-radius: 999px;
  font-size: 0.85rem;
  color: var(--navy);
  background: var(--surface);
  text-decoration: none;
  white-space: nowrap;
}

.chip:hover { border-color: var(--primary); color: var(--navy); }

.chip.active {
  background: var(--primary);
  border-color: var(--primary);
  color: #fff;
  font-weight: 600;
}

/* ---- Entity cards ------------------------------------------------------- */

.entity-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
  gap: var(--s-4);
  margin-bottom: var(--s-4);
}

.entity-card {
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  padding: var(--s-5);
  text-decoration: none;
  color: inherit;
}

.entity-card:hover {
  box-shadow: var(--shadow-md);
  transform: translateY(-2px);
}

.entity-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--s-3);
  margin-bottom: var(--s-3);
}

.entity-title {
  margin: 0;
  font-size: 1.05rem;
  font-weight: 600;
  color: var(--navy);
  overflow-wrap: anywhere;
}

/* Category tag, top right of the card. */
.tag {
  flex: 0 0 auto;
  padding: var(--s-1) var(--s-3);
  border-radius: var(--radius-sm);
  background: var(--banner-bg);
  color: var(--primary);
  font-size: 0.68rem;
  font-weight: 700;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  white-space: nowrap;
}

/* Customer / address rows, each led by an icon. */
.entity-line {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  margin: 0 0 var(--s-2);
  color: var(--muted);
  font-size: 0.92rem;
  overflow-wrap: anywhere;
}

.entity-line .icon { color: var(--muted); }
.entity-line.is-error { color: var(--error); }

.entity-foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-2);
  margin-top: var(--s-4);
  padding-top: var(--s-3);
  border-top: 1px solid var(--border);
  font-size: 0.88rem;
}

.entity-count {
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  color: var(--primary);
  font-weight: 500;
}

.entity-when { color: var(--muted); }

/* Traffic-light state dot: red failed, amber running, green fine, grey empty.
   The mock only had green/grey; failures would then be invisible on the card. */
.state-dot { width: 9px; height: 9px; border-radius: 50%; flex: 0 0 auto; }
.state-error { background: var(--error); }
.state-processing { background: var(--warning); animation: pulse 1.2s ease-in-out infinite; }
.state-ok { background: var(--success); }
.state-empty { background: var(--border); }

/* ---- "In Bearbeitung": full-width rows, not grid cards ------------------ */

.row-list { display: flex; flex-direction: column; gap: var(--s-3); }

.row-item {
  display: flex;
  align-items: center;
  gap: var(--s-4);
  background: var(--surface);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  padding: var(--s-4) var(--s-5);
  text-decoration: none;
  color: inherit;
}

.row-item:hover { box-shadow: var(--shadow-md); }

.row-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  flex: 0 0 auto;
  border-radius: 50%;
  background: var(--surface-sunken);
  color: var(--primary);
}

.row-icon .icon { width: 1.3rem; height: 1.3rem; }

.row-body { flex: 1 1 auto; min-width: 0; }

.row-title {
  margin: 0;
  font-size: 0.98rem;
  font-weight: 600;
  color: var(--navy);
  overflow-wrap: anywhere;
}

.row-sub { margin: 2px 0 0; font-size: 0.85rem; color: var(--muted); }
.row-sub.is-error { color: var(--error); }
.row-when { color: var(--muted); font-size: 0.85rem; white-space: nowrap; }

/* ---- Unassigned list (landing banner detail rows) ----------------------- */

.assign-list li { border-top-color: var(--border); }

/* ---- Mobile ------------------------------------------------------------- */

@media (max-width: 520px) {
  .action-row { grid-template-columns: 1fr; }
  .action-row-2 { grid-template-columns: 1fr; }

  .page-head { flex-direction: column; }

  .banner-row { flex-wrap: wrap; }
  .banner-cta { width: 100%; }

  .filter-row select,
  .filter-row .btn-search { width: 100%; }
  .filter-row .btn-search { margin-left: 0; }

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

  .kp-nav-bar {
    grid-template-columns: auto 1fr;
    row-gap: var(--s-3);
  }
  .kp-tabs { grid-column: 1 / -1; grid-row: 2; justify-content: center; }
}

/* Row items stack their title above the subtitle. The elements are spans (a
   row can be a link, and a <div> inside an <a> is invalid), so they need an
   explicit block display; a title that is itself a link must not pick up the
   default underline/blue. */
.row-title,
.row-sub {
  display: block;
}

a.row-title,
.row-title a {
  color: var(--navy);
  text-decoration: none;
}

a.row-title:hover,
.row-title a:hover {
  color: var(--primary);
}

/* ===========================================================================
   Recording detail: "Protokoll senden" dialog textarea. Moved out of
   recordings/detail.html's inline <style> — the one place left over from the
   2026-08-08 revamp that hadn't moved into base.css.
   =========================================================================== */

.send-text {
  width: 100%;
  box-sizing: border-box;
  padding: .6rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  font-family: inherit;
  font-size: .95rem;
  line-height: 1.4;
  resize: vertical;
  background: var(--surface);
  color: var(--navy);
}

/* ===========================================================================
   Audit log. Moved out of audit/log.html's inline <style> — the last
   template left over from the 2026-08-08 revamp that hadn't moved its CSS
   into base.css. audit-head is dropped in favor of the existing .page-head.
   =========================================================================== */

.audit-flag { font-size: 11px; letter-spacing: .05em; text-transform: uppercase; color: var(--muted); }
.subtabs { display: flex; gap: var(--s-2); border-bottom: 1px solid var(--border); margin: 0 0 var(--s-5); }
.subtab { padding: 9px 16px; font-size: 14px; font-weight: 600; color: var(--muted);
  text-decoration: none; border-bottom: 2px solid transparent; margin-bottom: -1px; }
.subtab:hover { color: var(--navy); }
.subtab.active { color: var(--navy); border-bottom-color: var(--primary); }
.audit-warn { font-size: 11px; font-weight: 600; letter-spacing: .05em; text-transform: uppercase;
  color: #a86a12; background: #f8efd9; border-radius: 999px; padding: 3px 10px; }
.audit-sub { color: var(--muted); font-size: 14px; margin: 0 0 var(--s-5); max-width: 74ch; }
.audit-card { background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius-lg); box-shadow: var(--shadow-sm); overflow: hidden; }
.audit-scroll { overflow-x: auto; }
table.audit { width: 100%; border-collapse: collapse; min-width: 720px; font-size: 13.5px; }
table.audit th { text-align: left; font-size: 11px; letter-spacing: .06em; text-transform: uppercase;
  color: var(--muted); font-weight: 600; padding: 12px 16px;
  border-bottom: 1px solid var(--border); white-space: nowrap; }
table.audit td { padding: 11px 16px; vertical-align: top;
  border-bottom: 1px solid color-mix(in srgb, var(--border) 55%, transparent); }
table.audit tr:last-child td { border-bottom: none; }
.mono { font-family: ui-monospace, "Cascadia Code", Consolas, monospace; font-size: 12px; }
.a-time { color: var(--muted); white-space: nowrap; font-variant-numeric: tabular-nums; }
.a-label { font-weight: 600; color: var(--navy); }
.a-id { color: var(--muted); }
.a-link { color: var(--primary); text-decoration: none; }
.a-link:hover { text-decoration: underline; }
.a-via { font-size: 11px; text-transform: uppercase; letter-spacing: .04em; color: var(--muted); }
.a-actor { display: inline-flex; align-items: center; gap: 8px; white-space: nowrap; }
.a-pid { color: var(--muted); }
.badge.user { color: #2b6a7f; background: #e3eef2; }
.badge.agent { color: #6d4bc7; background: #efe9fb; }
.badge.system { color: #4a5a6b; background: #e8edf1; }
.badge.admin { color: #a86a12; background: #f8efd9; }
.badge.anonymous { color: #6b7280; background: #eceef1; }
.diff { margin-top: 6px; font-size: 12px; color: var(--muted); }
.diff .fld { color: var(--navy); font-weight: 600; }
.diff .from { text-decoration: line-through; opacity: .75; }
.diff .to { color: #1f7a52; }
.audit-empty { padding: var(--s-7) var(--s-5); text-align: center; color: var(--muted); }
.audit-foot { color: var(--muted); font-size: 12.5px; margin-top: var(--s-4); }

/* ---- Matched quote cards (Feature 2) ------------------------------------ */

.quote-match {
  padding: var(--s-4) 0;
  border-top: 1px solid var(--border);
}

.quote-match:first-of-type { border-top: none; }

.quote-match-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s-3);
}

.quote-match-title {
  margin: 0;
  font-size: 1rem;
  font-weight: 600;
  color: var(--navy);
}

/* The similarity score is context, not the headline: the reference and the
   customer are what a human judges the suggestion by. */
.quote-match-score {
  flex: 0 0 auto;
  font-size: 0.8rem;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

.quote-match-meta {
  margin: var(--s-1) 0 var(--s-2);
  font-size: 0.85rem;
  color: var(--muted);
}

.quote-match-no { font-weight: 600; color: var(--primary); }

.quote-match-items {
  margin: 0;
  padding-left: var(--s-5);
  font-size: 0.9rem;
  color: var(--navy);
}

.quote-match-items li { margin-bottom: var(--s-1); }

@media (max-width: 520px) {
  /* Score drops under the title rather than squeezing it. */
  .quote-match-head { flex-direction: column; align-items: flex-start; gap: var(--s-1); }
}

/* A disabled button must look disabled. "Passende Angebote finden" is disabled
   until a project has an extraction, but rendered identically to an enabled
   button: full colour, pointer cursor, hover lift. Clicking it did nothing and
   the only hint was a hover tooltip. The :hover pairs are needed so the lift
   and colour change do not fire on a dead control. */
button:disabled,
button[disabled] {
  opacity: 0.45;
  cursor: not-allowed;
  box-shadow: none;
  transform: none;
}

button:disabled:hover,
button[disabled]:hover {
  box-shadow: none;
  transform: none;
  background: var(--primary);
}

.action-btn:disabled:hover,
.btn-subtle:disabled:hover {
  background: var(--surface);
}

/* ===========================================================================
   Quote/invoice document tables (Angebote)
   =========================================================================== */
.doc-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  overflow: hidden;
  margin-bottom: var(--s-5);
}
.doc-scroll { overflow-x: auto; }
table.doc { width: 100%; border-collapse: collapse; min-width: 640px; font-size: 13.5px; }
table.doc th {
  text-align: left; font-size: 13px; letter-spacing: .03em; text-transform: uppercase;
  color: var(--navy); font-weight: 700; padding: 12px 16px;
  border-bottom: 1px solid var(--border); white-space: nowrap;
}
table.doc td {
  padding: 11px 16px; vertical-align: top;
  border-bottom: 1px solid color-mix(in srgb, var(--border) 55%, transparent);
}
table.doc tr:last-child td { border-bottom: none; }

/* Item tables (quote/invoice line items) get one extra column vs. the
   quotes list's table.doc, so scope the width hint to just this table --
   otherwise "Beschreibung" is squeezed into auto-layout's equal split while
   Menge/Einheit sit mostly empty. */
table.doc-items th:nth-child(3), table.doc-items td:nth-child(3) { width: 38%; }

/* On a phone the 6-column Angebote list can't fit -- table.doc's 640px
   min-width would force horizontal scrolling. Below 520px, collapse each row
   into a stacked label/value block (data-label supplies the field name that
   the hidden <thead> would have carried) so it reads top-to-bottom and never
   scrolls sideways. Scoped to .doc-list so the quote/invoice document tables
   (table.doc-items) keep their real columns. */
@media (max-width: 520px) {
  table.doc-list { min-width: 0; font-size: 14px; }
  table.doc-list thead { display: none; }
  table.doc-list tbody, table.doc-list tr, table.doc-list td { display: block; }
  table.doc-list tr {
    padding: 12px 16px;
    border-bottom: 1px solid var(--border);
  }
  table.doc-list tr:last-child { border-bottom: none; }
  table.doc-list td {
    border: none;
    padding: 3px 0;
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 16px;
    text-align: right;
  }
  table.doc-list td::before {
    content: attr(data-label);
    flex: none;
    text-align: left;
    color: var(--muted);
    font-weight: 600;
    font-size: 11px;
    letter-spacing: .03em;
    text-transform: uppercase;
  }
  /* Empty trailing "Rechnungen" cell adds nothing on mobile -- drop the row. */
  table.doc-list td:empty { display: none; }
  /* Lead the card with the Angebotsnummer. */
  table.doc-list td:first-child { font-weight: 700; font-size: 15px; padding-bottom: 4px; }
}

/* Line-item tables on the Angebot/Rechnung drill-down (7 columns, min-width
   640px) can't fit a phone either. Below 520px each position becomes a card:
   a "Pos N · Art" eyebrow, the Beschreibung as headline, then the money rows as
   label -> value with Gesamtpreis emphasised. Scoped to .doc-items. */
@media (max-width: 520px) {
  table.doc-items { min-width: 0; font-size: 14px; }
  table.doc-items thead { display: none; }
  table.doc-items tbody, table.doc-items tr, table.doc-items td { display: block; }
  table.doc-items tr {
    padding: 12px 16px;
    border-bottom: 1px solid var(--border);
  }
  table.doc-items tr:last-child { border-bottom: none; }
  table.doc-items td {
    border: none;
    padding: 2px 0;
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 16px;
    text-align: right;
  }
  table.doc-items td::before {
    content: attr(data-label);
    flex: none;
    text-align: left;
    color: var(--muted);
    font-weight: 600;
    font-size: 11px;
    letter-spacing: .03em;
    text-transform: uppercase;
  }
  /* Beschreibung is the line's headline: full width, no label, prominent. */
  table.doc-items td[data-label="Beschreibung"] {
    display: block;
    text-align: left;
    font-weight: 700;
    font-size: 15px;
    padding: 2px 0 6px;
  }
  table.doc-items td[data-label="Beschreibung"]::before { content: none; }
  /* Pos + Art read as one small muted eyebrow above the description. */
  table.doc-items td[data-label="Pos"],
  table.doc-items td[data-label="Art"] {
    display: inline-block;
    padding: 0 0 2px;
    color: var(--muted);
    font-size: 12px;
  }
  table.doc-items td[data-label="Art"]::before { content: none; }
  table.doc-items td[data-label="Pos"]::before {
    content: "Pos ";
    text-transform: none;
    letter-spacing: 0;
    font-size: 12px;
  }
  table.doc-items td[data-label="Pos"]::after { content: " ·"; }
  /* Gesamtpreis is the number that matters on each line. */
  table.doc-items td[data-label="Gesamtpreis"] { font-weight: 700; }
}

.pagination { display: flex; align-items: center; gap: var(--s-3); margin-top: var(--s-4); }
.pagination-status { color: var(--muted); font-size: 0.85rem; }
.pagination-link { font-size: 0.9rem; }

/* Angebote list: the running total sits on top and stays put while the list
   scrolls under it, so the count of matches is always in view. */
.list-count {
  position: sticky;
  top: 0;
  z-index: 2;
  background: var(--surface);
  padding: 10px 2px;
  margin-bottom: var(--s-3);
  border-bottom: 1px solid var(--border);
  color: var(--navy);
  font-size: 0.95rem;
}
.list-count strong { font-size: 1.15rem; font-weight: 700; }
.list-count-loaded { color: var(--muted); font-size: 0.85rem; }
/* Infinite-scroll "loading the next page" line. */
.list-loading { color: var(--muted); text-align: center; padding: var(--s-3); font-size: 0.9rem; }


.linked-invoices { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--s-2); }

/* The one number on a quote/invoice card that should read as a headline,
   not another entity-line -- same idea as insight-hero's border accent. */
.doc-total {
  font-size: 1.2rem;
  font-weight: 700;
  color: var(--primary);
}

/* Gesamtsumme leads; Rabatt and MwSt sit beside it as secondary context, so
   the three numbers that describe one total are read together. Wraps rather
   than shrinking the headline on narrow screens. */
.doc-total-row {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: var(--s-2) var(--s-4);
  margin: var(--s-3) 0 0;
}

.doc-total-part {
  font-size: 0.85rem;
  color: var(--muted);
}

/* ---- Match feedback controls -------------------------------------------- */

.match-vote {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-2);
  margin-top: var(--s-3);
}

/* Deliberately quiet by default: the judgement is the point, but it should
   not shout louder than the quote it is about. State is carried by colour
   once given, so a card shows at a glance whether it was already answered. */
.vote-btn {
  padding: var(--s-1) var(--s-3);
  font-size: 0.8rem;
  font-weight: 600;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: transparent;
  color: var(--muted);
  box-shadow: none;
  cursor: pointer;
}

.vote-btn:hover {
  background: var(--surface-sunken);
  color: var(--navy);
  box-shadow: none;
  transform: none;
}

.vote-on, .vote-on:hover { background: var(--success); border-color: var(--success); color: #fff; }
.vote-off, .vote-off:hover { background: var(--error); border-color: var(--error); color: #fff; }
.vote-chosen, .vote-chosen:hover { background: var(--navy); border-color: var(--navy); color: #fff; }

.match-no-match {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s-2);
  margin-top: var(--s-4);
  padding-top: var(--s-4);
  border-top: 1px solid var(--border);
}

.match-no-match input[type="text"] {
  flex: 1 1 16rem;
  padding: var(--s-2) var(--s-3);
  border: 1px solid var(--border);
  border-radius: 999px;
  font-family: inherit;
  font-size: 0.85rem;
}

/* A checkbox that reads as part of a filter row rather than a stacked form
   field (the Angebote "Auch in Positionen suchen" opt-in). */
.check-inline {
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  font-size: 0.85rem;
  color: var(--muted);
  white-space: nowrap;
  cursor: pointer;
}

.check-inline input[type="checkbox"] {
  width: 1rem;
  height: 1rem;
  accent-color: var(--primary);
  cursor: pointer;
}

/* ---- Project page tabs + Todos ------------------------------------------ */

/* The tab strip is the page's section heading: each tab is set at .group-heading
   scale (h2) and the strip carries that heading's bottom border, so the three
   panels read as one heading you switch between rather than as chrome sitting
   above a second, repeated title. Panels therefore carry no h2 of their own. */
.tabbar {
  display: flex;
  align-items: baseline;
  gap: var(--s-5);
  border-bottom: 1px solid var(--border);
  margin: var(--s-6) 0 var(--s-4);
  padding-bottom: var(--s-2);
}

.tab {
  padding: 0 0 var(--s-2);
  margin-bottom: calc(-1 * var(--s-2) - 1px);   /* underline sits on the strip's border */
  font-size: 1.125rem;                          /* h2 */
  font-weight: 600;
  line-height: 1.3;
  color: var(--muted);
  background: transparent;
  border: none;
  border-bottom: 2px solid transparent;
  border-radius: 0;
  box-shadow: none;
  cursor: pointer;
}

.tab:hover {
  color: var(--navy);
  background: transparent;
  box-shadow: none;
  transform: none;
}

.tab-active, .tab-active:hover {
  color: var(--navy);
  border-bottom-color: var(--primary);
}

.tab-count {
  display: inline-block;
  min-width: 1.25rem;
  padding: 0 0.35rem;
  font-size: 0.75rem;
  line-height: 1.25rem;
  text-align: center;
  vertical-align: 0.15em;
  color: #fff;
  background: var(--primary);
  border-radius: 999px;
}

@media (max-width: 520px) {
  /* Three h2-sized labels do not fit a phone: shrink and tighten rather than
     wrap, so the strip stays one line. */
  .tabbar { gap: var(--s-3); }
  .tab { font-size: 0.95rem; }
}

/* The panel's own primary action (Neu erstellen / Passende Angebote finden),
   top of the card. Both panels use this so the two buttons are identical. */
.panel-action {
  margin-bottom: var(--s-4);
}

/* ---- Ueberblick: work items as quote-style line items -------------------- */

/* The extraction summary, in the register of a quote's Betreffzeile: the one
   sentence that says what this job is, set above everything it summarises. */
.overview-lead {
  margin: 0 0 var(--s-3);
  font-size: 1rem;
  line-height: 1.55;
  color: var(--navy);
}

/* Project materials, promoted out of the old trailing "Materialien: ..." line
   to sit with the summary they belong to. */
.overview-materials {
  margin: 0 0 var(--s-2);
}


/* Area label above the items it groups. Quieter than an h2 (the tab holds that
   rank) but clearly a divider. Also used for the Todos panel's KI subsection. */
.work-area {
  margin: var(--s-5) 0 var(--s-2);
  padding-bottom: var(--s-1);
  border-bottom: 1px solid var(--border);
  font-size: 0.8rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted);
}

.work-list {
  margin: 0;
  padding: 0;
  list-style: none;
}

/* Quantity column, then body. The fixed first column aligns the measures down
   the page the way a quote does. */
.work-item {
  display: grid;
  grid-template-columns: 5rem 1fr;
  gap: var(--s-3);
  padding: var(--s-3) 0;
  border-bottom: 1px solid var(--border);
}

.work-item:last-child { border-bottom: none; }

.work-item-qty {
  font-size: 0.9rem;
  font-weight: 600;
  color: var(--navy);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.work-item-body {
  display: flex;
  flex-direction: column;
  gap: var(--s-2);
  align-items: flex-start;
}

/* Normal weight: a full sentence in bold turned the list into a wall. */
.work-item-desc {
  color: var(--navy);
  line-height: 1.5;
  overflow-wrap: anywhere;
}

@media (max-width: 520px) {
  .work-item { grid-template-columns: 4rem 1fr; gap: var(--s-2); }
}

/* Non-interactive chip: material, Maße, project materials. Same pill language
   as the filter chips, one step smaller and never clickable. */
.chip-row-static {
  margin-bottom: 0;
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-2);
}

/* .meta's default bottom margin is sized for a card footer; inside a panel that
   holds only the status pill it leaves a hole. */
.meta-flush { margin-bottom: 0; }

.attr-chip {
  display: inline-flex;
  align-items: center;
  padding: 0.1rem var(--s-3);
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--bg);
  font-size: 0.78rem;
  color: var(--muted);
  white-space: nowrap;
}

.todo-row {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  padding: var(--s-1) 0;
}

.todo-check {
  /* padding: 0 is load-bearing -- without it the global button padding
     (var(--s-3) var(--s-5)) indents every open todo away from the done ones,
     which are plain paragraphs. */
  padding: 0;
  width: 1.4rem;
  background: transparent;
  border: none;
  border-radius: 0;
  box-shadow: none;
  font-size: 1.1rem;
  line-height: 1;
  text-align: left;
  cursor: pointer;
  color: var(--muted);
}

.todo-check:hover { color: var(--primary); box-shadow: none; transform: none; }

/* Same 1.4rem marker column as .todo-check, so open and done rows line up. */
.todo-done {
  display: flex;
  gap: var(--s-2);
  align-items: baseline;
  color: var(--muted);
  padding: var(--s-1) 0;
  margin: 0;
}

.todo-done::before {
  content: "☑";
  width: 1.4rem;
  flex: 0 0 auto;
}

.todo-add {
  display: flex;
  gap: var(--s-2);
  margin-top: var(--s-3);
}

.todo-add input[type="text"] {
  flex: 1 1 auto;
  padding: var(--s-2) var(--s-3);
  border: 1px solid var(--border);
  border-radius: 999px;
  font-family: inherit;
  font-size: 0.85rem;
}

.suggestion-row {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  padding: var(--s-1) 0;
  border-bottom: 1px dashed var(--border);
}

.suggestion-row .todo-text { flex: 1 1 auto; color: var(--muted); }

/* ===========================================================================
   Transcript correction (recordings/detail.html). The user edits the whole
   transcript in a textarea; the read-only view and the form swap visibility.
   .send-text is the sibling textarea style for the "Protokoll senden" dialog:
   kept separate because this one is taller and sits inside a <details>.
   =========================================================================== */

.transcript-input {
  width: 100%;
  box-sizing: border-box;
  margin-top: var(--s-1);
  padding: .6rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  font-family: inherit;
  font-size: .95rem;
  line-height: 1.5;
  resize: vertical;
  background: var(--surface);
  color: var(--navy);
}

/* The transcript block runs right up to the button, so give it room to
   breathe rather than sitting flush against the last line of text. */
#transcript-edit-btn {
  margin-top: var(--s-4);
}

.transcript-hint {
  margin: var(--s-1) 0 0;
  font-size: .85rem;
  color: var(--muted);
}

.transcript-original {
  margin-top: var(--s-1);
}

.transcript-original > summary {
  font-size: .85rem;
  color: var(--muted);
  cursor: pointer;
}

/* Shown on the project Ueberblick tab when a recording was corrected after
   the extraction last ran, so the overview is knowably out of date. */
.stale-hint {
  margin: 0 0 var(--s-1);
  padding: var(--s-1) var(--s-2);
  border-left: 3px solid var(--primary);
  border-radius: var(--radius-sm);
  background: var(--surface-alt, var(--surface));
  font-size: .9rem;
  color: var(--navy);
}
