/* ═══════════════════════════════════════════════════════════════════════
   DASHBOARD MODULE
   ═══════════════════════════════════════════════════════════════════════ */

/* Stats grid (4 compact KPI tiles across, wraps to 2×2 on narrow) */
.dashboard-stats-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
  gap: var(--space-2);
  margin-top: 6px;
  /* Each card sizes to its OWN content — don't stretch a whole row to match its
     tallest. Labels are clamped to one line (.dashboard-stat-label nowrap), so
     KPI tiles share a uniform compact height; align-items:start still stops a
     card with a long VALUE (e.g. the org "Your role" name) inflating its
     row-mates. */
  align-items: start;
}
/* Compact icon-left KPI tile: the icon chip sits BESIDE the value with the
   label tucked under it (optional hint spans full-width below), instead of the
   old tall icon-on-top stack. Reflowed purely in CSS — the four children built
   in dashboard.js are unchanged. ~35% shorter per card, so the four org-KPIs
   stop eating the top of the dashboard. */
.dashboard-stat-card {
  background: var(--bg-surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 10px 12px;
  position: relative;
  transition: border-color 0.15s, transform 0.15s;
  display: grid;
  grid-template-columns: auto 1fr;
  align-items: center;
  column-gap: var(--space-2);
  row-gap: 2px;
}
.dashboard-stat-card:hover { border-color: var(--border-strong); }
/* Tappable KPI tiles (New tasks → Tasks, Noticeboard → the board). */
.dashboard-stat-card.is-actionable { cursor: pointer; -webkit-tap-highlight-color: transparent; }
.dashboard-stat-card.is-actionable:hover { border-color: var(--accent); }
.dashboard-stat-card.is-actionable:active { transform: scale(0.99); }
.dashboard-stat-card.is-actionable:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
/* Act-now highlight (amber) — set on a KPI tile when it has something waiting,
   e.g. the "New tasks" card when unclaimed jobs have landed for this department. */
.dashboard-stat-card.is-flagged { border-color: color-mix(in srgb, var(--warning) 55%, transparent); background: var(--warning-soft); }
.dashboard-stat-card.is-flagged .dashboard-stat-value { color: var(--warning); }
.dashboard-stat-card.is-flagged .dashboard-stat-icon { color: var(--warning); }

/* ─── "My tasks" collapsible card → unfolds the list inline ─── */
.dashboard-stat-card[data-stat-toggle] { position: relative; }
.dashboard-stat-chevron {
  position: absolute;
  top: 10px; right: 10px;
  color: var(--text-muted);
  transition: transform 0.18s ease, color 0.18s ease;
}
.dashboard-stat-card.is-expanded { border-color: var(--accent); }
.dashboard-stat-card.is-expanded .dashboard-stat-chevron { transform: rotate(180deg); color: var(--accent); }
.dashboard-mytasks-fold { margin-top: 10px; }
.dashboard-mytasks-fold[hidden] { display: none; }
.dashboard-mytasks-fold.is-open { animation: dashFoldIn 0.18s ease; }
@keyframes dashFoldIn { from { opacity: 0; transform: translateY(-4px); } to { opacity: 1; transform: translateY(0); } }

/* ─── "My tasks" list block (dashboard personal lens) ─── */
.dashboard-mytasks { display: flex; flex-direction: column; gap: 8px; }
/* "+ New personal task" — quick-add a private to-do straight from the dashboard. */
.dashboard-mytask-new {
  display: flex; align-items: center; justify-content: center; gap: 8px;
  width: 100%;
  padding: 12px;
  background: transparent;
  border: 1px dashed color-mix(in srgb, var(--accent) 45%, var(--border));
  border-radius: var(--radius-lg);
  color: var(--accent);
  font-size: var(--text-sm); font-weight: 600;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: background 0.12s, border-color 0.12s;
}
.dashboard-mytask-new:hover { background: color-mix(in srgb, var(--accent) 8%, transparent); border-color: var(--accent); }
.dashboard-mytask-new:active { transform: scale(0.995); }
.dashboard-mytask-row {
  position: relative;
  overflow: hidden;
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  text-align: left;
  padding: 12px 14px;
  background: var(--bg-surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: border-color 0.12s, background 0.12s;
}
/* Per-site accent spine (cross-site view only — single-site rows leave
   --mytask-site unset → transparent → no spine). Clipped to the row's
   rounded corners via the row's overflow:hidden. */
.dashboard-mytask-row::before {
  content: '';
  position: absolute;
  left: 0; top: 0; bottom: 0;
  width: 3px;
  background: var(--mytask-site, transparent);
}
.dashboard-mytask-row:hover { border-color: var(--accent); }
.dashboard-mytask-row:active { transform: scale(0.995); }
.dashboard-mytask-dot { flex-shrink: 0; width: 9px; height: 9px; border-radius: 50%; }
.dashboard-mytask-body { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1; }
.dashboard-mytask-title {
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--text-primary);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.dashboard-mytask-meta { font-size: var(--text-xs); color: var(--text-muted); }
.dashboard-mytask-meta.is-overdue { color: #f87171; font-weight: 600; }
/* Site tag — only shown in the cross-site (all-sites) view so a multi-site user knows
   which hotel a task belongs to. Keeps its own colour, never inherits the overdue red. */
.dashboard-mytask-site {
  display: inline-block;
  font-weight: 600;
  color: var(--text-secondary);
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
  padding: 1px 7px;
  margin-right: 3px;
  vertical-align: 1px;
}
/* Calm chip, colour only on the dot (matches the two-tier card rule): the dot
   carries the site's stable colour so a multi-site user reads the hotel fast. */
.dashboard-mytask-site-dot {
  display: inline-block;
  width: 7px; height: 7px;
  border-radius: 50%;
  margin-right: 5px;
  vertical-align: 0;
}
/* CALM (2026-06-29) — neutral chip + colour on the dot, matching the cards/detail. */
.dashboard-mytask-status {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  flex-shrink: 0;
  font-size: var(--text-xs);
  font-weight: 500;
  color: var(--text-primary);
  padding: 4px 9px;
  border-radius: var(--radius-sm);   /* squarish, matching the task cards (Radek 2026-06-29) */
  background: var(--bg-elevated);
  border: 1px solid var(--border);
}
.dashboard-mytask-status::before {
  content: ''; width: 6px; height: 6px; border-radius: 50%;
  background: var(--text-muted); flex-shrink: 0;
}
.dashboard-mytask-status[data-mystatus="new"]::before         { background: #2563eb; }
.dashboard-mytask-status[data-mystatus="in_progress"]::before  { background: #d97706; }
.dashboard-mytask-status[data-mystatus="blocked"]::before      { background: #dc2626; }
.dashboard-mytask-status[data-mystatus="on_hold"]::before      { background: #64748b; }
.dashboard-mytask-all {
  align-self: flex-start;
  margin-top: 2px;
  padding: 8px 4px;
  background: transparent;
  border: 0;
  color: var(--accent);
  font-size: var(--text-sm);
  font-weight: 600;
  cursor: pointer;
}
.dashboard-mytask-all:hover { text-decoration: underline; }
/* Chevron on a navigating row (the Sites accordion reuses .dashboard-mytask-row).
   Sits where the status chip sits on a task row. */
.dashboard-mytask-arrow {
  width: 16px; height: 16px; stroke-width: 2;
  flex-shrink: 0;
  color: var(--text-muted);
  transition: color 0.15s, transform 0.15s;
}
.dashboard-mytask-row:hover .dashboard-mytask-arrow { color: var(--accent); transform: translateX(2px); }
/* CALM (Radek 2026-06-30): bare icon — no coloured square behind it. The 28px cell
   stays for column alignment; the icon is a hair bigger + a calm grey now there's no
   chip to frame it. (.is-flagged still tints it amber; .is-expanded the card accent.) */
.dashboard-stat-icon {
  grid-column: 1;
  grid-row: 1 / span 2;
  align-self: center;
  width: 28px; height: 28px;
  display: grid; place-items: center;
  color: var(--text-secondary);
}
.dashboard-stat-icon svg { width: 18px; height: 18px; stroke-width: 1.9; }
.dashboard-stat-value {
  grid-column: 2; grid-row: 1;
  font-family: var(--display);
  font-size: var(--text-2xl);
  font-weight: 700;
  color: var(--text-primary);
  letter-spacing: -0.02em;
  line-height: 1.1;
}
.dashboard-stat-label {
  grid-column: 2; grid-row: 2;
  min-width: 0;                 /* shrink within the grid column so a long label ellipsizes… */
  font-size: var(--text-sm);
  color: var(--text-muted);
  font-weight: 500;
  line-height: 1.15;
  /* …one line ALWAYS → every KPI tile is the same compact height, no card stands
     taller because its label wrapped ("Docs to read" / "Noticeboard"). Radek
     2026-07-14. Same nowrap+ellipsis pattern as .dashboard-mytask-title. */
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.dashboard-stat-hint {
  grid-column: 1 / -1; grid-row: 3;
  font-size: var(--text-xs);
  color: var(--text-muted);
  font-style: italic;
  margin-top: 2px;
  opacity: 0.75;
}

/* (The old standalone .dashboard-sites-grid / .dashboard-site-tile* are retired —
   the Sites KPI now unfolds rows that reuse .dashboard-mytask-row, see dashboard.js
   renderSiteTile. Radek 2026-06-30.) */

/* Empty state block */
.dashboard-empty-block {
  text-align: center;
  padding: 32px 24px;
  background: var(--bg-surface);
  border: 1px dashed var(--border);
  border-radius: var(--radius-md);
}
.dashboard-empty-block-icon {
  width: 44px; height: 44px;
  border-radius: var(--radius-md);
  background: var(--bg-elevated);
  color: var(--text-muted);
  display: grid; place-items: center;
  margin: 0 auto 12px;
}
.dashboard-empty-block-icon svg { width: 22px; height: 22px; stroke-width: 1.8; }
.dashboard-empty-block-title {
  font-family: var(--display);
  font-size: var(--text-lg);
  font-weight: 600;
  color: var(--text-secondary);
  margin-bottom: 4px;
}
.dashboard-empty-block-sub {
  font-size: var(--text-base); color: var(--text-muted);
  max-width: 320px; margin: 0 auto; line-height: 1.5;
}

/* (The "Coming soon — customisable widgets" banner was removed 2026-06-30 — the
   dashboard ships what it has, no placeholder.) */

.coming-soon-state {
  text-align: center;
  padding: 64px 24px;
  color: var(--text-muted);
}
.coming-soon-icon {
  width: 64px; height: 64px;
  border-radius: var(--radius-lg);
  background: var(--bg-surface);
  border: 1px solid var(--border);
  display: grid; place-items: center;
  margin: 0 auto 16px;
  color: var(--accent);
}
.coming-soon-icon svg { width: 28px; height: 28px; stroke-width: 1.5; }
.coming-soon-title {
  font-family: var(--display);
  font-size: var(--text-2xl); font-weight: 600;
  color: var(--text-primary);
  margin-bottom: 4px;
}
.coming-soon-sub { font-size: var(--text-md); line-height: 1.6; max-width: 320px; margin: 0 auto; }

/* ═════════════════════════════════════════════════════════════════════
   DESKTOP LAYOUT — wider content area + multi-column card grids
   ═════════════════════════════════════════════════════════════════════
   On screens ≥1024px we widen the page shell, lay out cards in a
   responsive grid, and let tables/photos use the extra width while
   keeping prose at a comfortable reading width (~720px).
   Mobile/tablet behaviour below 1024px is unchanged.
*/
@media (min-width: 1024px) {

  /* 1. Widen the global page shell */
  .main {
    max-width: 1200px;
    padding-left: 32px;
    padding-right: 32px;
  }

  /* 2. Card grids — responsive auto-fit so cards reflow as window resizes.
     - Notes (Quick Entry cards): minimum card width 320px → 2-3 columns at 1200px
     - Instructions: minimum card width 360px → 2-3 columns
     - Folders: minimum card width 280px → 3-4 columns since they're smaller */
  /* Inbox/Archive note cards: stack one per row to match the folder
     pattern. Mixed-column grids made these views feel like a different
     screen — now everything in KB reads as a vertical stream. */
  .entries-list {
    display: flex;
    flex-direction: column;
    gap: 8px;
  }
  .kb-instr-list {
    display: flex;
    flex-direction: column;
    gap: 8px;
  }
  /* Folder cards stay stacked vertically on desktop (one per row) so the
     layout matches the mobile experience. Easier to predict how it'll
     look on a phone, and the row format reads like the document cards
     in the same view — consistent visual rhythm. */
  .kb-folder-list {
    display: flex;
    flex-direction: column;
    gap: 8px;
  }

  /* 3. Reader overlays — slightly wider than mobile but still capped for
     prose readability. Document blocks override below if they need more space. */
  .kb-reader-content {
    max-width: 900px;
  }
  /* Document type instructions: all blocks use full reader content width
     so text, notices, tables and photos all align consistently */
  .kb-doc-block-render-text {
    max-width: 100%;
  }
  /* Callout renders - full width to match tables */
  .kb-doc-content .kb-doc-callout-render {
    max-width: 100%;
  }
  /* Tables in document reader: allow them to use full available width
     (or scroll horizontally if columns sum to even more) */
  .kb-doc-table-render {
    max-width: 100%;
  }
  /* Photo blocks: full width too */
  .kb-doc-block-render-photo {
    max-width: 100%;
  }

  /* 4. Folder breadcrumb header — let the description and tags use space */
  .kb-folder-header-info { max-width: none; }

  /* 5. Empty states stay centered visually */
  .empty-state {
    max-width: 480px;
    margin: 0 auto;
  }

  /* 6. Search input + Quick Entry composer can be slightly wider too */
  .kb-search-bar,
  .quick-entry-form {
    max-width: 100%;
  }
}

/* Wider still on very large screens (≥1440px), but only fractionally —
   we don't want absurdly wide content. */
@media (min-width: 1440px) {
  .main {
    max-width: 1280px;
  }
  /* Cards stay in a single column at all widths — consistent visual
     stream across the app, easier to scan, mirrors mobile. */
}

/* ═════════════════════════════════════════════════════════════════════
   PHOTO ANNOTATION EDITOR
   ═════════════════════════════════════════════════════════════════════
   Full-screen overlay that lets the user draw circles, arrows, freehand
   strokes and text labels on top of a photo. Coordinates are stored as
   0-1 floats relative to natural image size.

   Layout: top bar (title + close), stage (photo + canvas overlay),
   bottom toolbar (tool select, color, undo/clear, save).
*/

/* The instruction lightbox container (used by openInstrPhotoLightbox_).
   This is separate from the multi-photo Notes lightbox (.kb-lightbox).
   Originally it had no styling at all — we need a positioned full-screen
   container so the close + annotate buttons land in the right place. */
.kb-lightbox-overlay {
  position: fixed;
  inset: 0;
  z-index: 1200;
  background: rgba(0, 0, 0, 0.92);
  display: flex;
  flex-direction: column;
  opacity: 0;
  transition: opacity 0.18s;
  /* Safe-area padding is handled by pv-header's padding-top */
  touch-action: manipulation;
}
.kb-lightbox-overlay.open { opacity: 1; }
.kb-lightbox-overlay .kb-lightbox-img-wrap {
  flex: 1;
  width: 100%;
  max-width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  touch-action: none;
}
.kb-lightbox-overlay .kb-lightbox-img-wrap img {
  max-width: 100%;
  max-height: 100%;
  display: block;
  object-fit: contain;
  border-radius: var(--radius-md);
}

.kb-annot-overlay {
  position: fixed;
  inset: 0;
  /* Sit above every other overlay: KB modals (1100), KB lightbox (1200),
     callout/asset detail overlays (8500), and the shared photo viewer
     (9000). 9500 keeps the editor below the topmost system toasts (9999). */
  z-index: 9500;
  background: #000;
  display: flex;
  flex-direction: column;
  opacity: 0;
  transition: opacity 0.2s;
  /* Full-screen annotation editor → clear the status bar robustly (see
     --safe-top) so the top toolbar is never stranded behind the notch. */
  padding-top: var(--safe-top);
  padding-bottom: env(safe-area-inset-bottom);
  /* iOS: .app-shell is permanently GPU-composited (its own transform layer),
     so a plain fixed overlay with no compositing trigger paints BEHIND it —
     the annotation editor opened from edit mode appeared "behind the view"
     until the document was closed. Self-composite this overlay so it gets its
     own layer above the shell. Same fix already applied to the tasks/callout
     modal overlays; this is paint-only and doesn't affect the inner canvas
     zoom (which transforms .kb-annot-canvas-wrap, not the overlay). */
  transform: translateZ(0);
  will-change: transform;
}
.kb-annot-overlay.open { opacity: 1; }

.kb-annot-topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 12px 16px;
  color: #fff;
  flex-shrink: 0;
  /* A defined header bar above the (black) canvas stage — a subtle elevated
     panel + clear separator, instead of bare text floating on black. Dark
     tones so it reads correctly in both themes (the editor stage is always
     black). The old separate mode-hint banner row was removed for canvas room. */
  background: rgba(255, 255, 255, 0.05);
  border-bottom: 1px solid rgba(255, 255, 255, 0.12);
}
/* Right-side cluster: contextual Edit / Delete (shown only when an annotation
   is selected) sit on the same line as the Close button. */
.kb-annot-topbar-actions {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-shrink: 0;
}
.kb-annot-topbar-actions .kb-annot-mode-edit { margin-left: 0; }
.kb-annot-title {
  font-family: var(--display);
  font-size: var(--text-xl);
  font-weight: 600;
  letter-spacing: -0.01em;
  /* Truncate (rather than wrap/push) on very narrow phones so the contextual
     action buttons + Close always keep their place on the one header line. */
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.kb-annot-close {
  width: 36px; height: 36px;
  display: grid; place-items: center;
  background: rgba(255,255,255,0.12);
  border: none;
  border-radius: var(--radius-full);
  color: #fff;
  cursor: pointer;
  padding: 0; line-height: 0;
}
.kb-annot-close:hover { background: rgba(255,255,255,0.22); }
.kb-annot-close svg { width: 18px; height: 18px; }

.kb-annot-stage {
  flex: 1;
  display: grid;
  place-items: center;
  overflow: hidden;
  position: relative; /* anchor for the drag magnifier loupe */
  /* No HORIZONTAL padding: the full-screen photo viewer (.photo-viewer-stage,
     css/14) shows the photo edge-to-edge across the full viewport width, so for
     edit mode to match its size exactly the editor photo must span the same
     width. Side padding here made the editor photo ~16px narrower (and so a few
     % smaller marks) than the full-screen view. Keep 8px top/bottom for a small
     gap from the top bar + toolbar (height-bound only; doesn't affect the
     width-bound phone case). */
  padding: 8px 0;
  min-height: 0; /* let it shrink */
}
.kb-annot-canvas-wrap {
  position: relative;
  /* Constrain to stage size while preserving aspect ratio */
  max-width: 100%;
  max-height: 100%;
  display: inline-block;
  /* Prevent canvas/img from being interpreted as draggable */
  user-select: none;
  -webkit-user-select: none;
  -webkit-touch-callout: none;
}
.kb-annot-img {
  display: block;
  /* WYSIWYG vs the FULL-SCREEN photo viewer (the view users actually compare
     against — they tap a photo to inspect the marks). Annotation marks are a
     fixed ~4% of the displayed photo height, so they only look the same size
     when the editor shows the photo at the same size the viewer does. The
     editor and the tap-to-fullscreen viewer are BOTH full-screen, so fill the
     stage (viewport minus the editor's top bar + toolbar) to match it.
     NOTE: an earlier 400px cap matched the small INLINE document photo instead,
     which made the marks look ~25% smaller in the editor than when the same
     photo was opened full-screen. .kb-annot-canvas-wrap max-height:100% keeps
     the photo inside the stage so the toolbar is never covered. */
  max-width: 100%;
  max-height: calc(100vh - 200px);
  object-fit: contain;
  user-select: none;
  -webkit-user-drag: none;
  pointer-events: none; /* canvas catches the events */
}
.kb-annot-canvas {
  position: absolute;
  top: 0; left: 0;
  /* We size width/height in JS to match displayed image */
  cursor: crosshair;
  touch-action: none; /* prevent scroll while drawing */
}

/* Drag magnifier — a zoomed loupe that appears while dragging an endpoint on
   touch, so a fingertip never hides the exact point being placed. Positioned
   top/bottom-centre (away from the finger) in JS; content drawn on the canvas. */
.kb-annot-loupe {
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  width: 116px; height: 116px;
  border-radius: 50%;
  border: 2.5px solid rgba(255,255,255,0.92);
  box-shadow: 0 6px 22px rgba(0,0,0,0.55);
  background: #000;
  pointer-events: none;
  z-index: 8;
}
.kb-annot-loupe[hidden] { display: none; }
.kb-annot-loupe.is-top { top: 12px; }
.kb-annot-loupe.is-bottom { bottom: 12px; }

.kb-annot-toolbar {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 14px;
  background: #1a1a1a;
  border-top: 1px solid rgba(255,255,255,0.08);
  flex-shrink: 0;
  flex-wrap: wrap;
  justify-content: center;
}
.kb-annot-tools, .kb-annot-actions {
  display: flex;
  gap: 6px;
  align-items: center;
}
/* Visual separator before the actions group (undo/clear). */
.kb-annot-options + .kb-annot-actions {
  padding-left: 12px;
  border-left: 1px solid rgba(255,255,255,0.15);
}

.kb-annot-tool, .kb-annot-action {
  width: 40px; height: 40px;
  display: grid; place-items: center;
  background: rgba(255,255,255,0.08);
  border: 1px solid transparent;
  border-radius: var(--radius-md);
  color: #fff;
  cursor: pointer;
  padding: 0; line-height: 0;
  transition: background 0.12s, border-color 0.12s;
}
.kb-annot-tool:hover, .kb-annot-action:hover { background: rgba(255,255,255,0.15); }
.kb-annot-tool.is-active {
  background: var(--accent-soft);
  border-color: var(--accent);
  color: var(--accent);
}
.kb-annot-tool svg, .kb-annot-action svg { width: 20px; height: 20px; }

/* Adaptive options row — one tidy strip under the tools holding the colour
   well + the tool-specific toggles (line mode / fill / dashed). Own full-width
   line in the wrapping toolbar; the groups inside flow inline. */
.kb-annot-options {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 12px;
  align-items: center;
  justify-content: center;
  flex-basis: 100%;
}
.kb-annot-optgroup {
  display: flex;
  flex-wrap: wrap;          /* Arrow group has 4 chips — wrap to 2 rows on tiny (≤320px) phones rather than clip */
  justify-content: center;
  gap: 6px;
  align-items: center;
}
.kb-annot-optgroup[hidden] { display: none; }
.kb-annot-linemode {
  display: inline-flex; align-items: center; gap: 6px;
  height: 34px; padding: 0 12px;
  background: rgba(255,255,255,0.08);
  border: 1px solid transparent;
  border-radius: var(--radius-md);
  color: #fff; cursor: pointer;
  font: 600 var(--text-sm) / 1 var(--body);
  transition: background 0.12s, border-color 0.12s;
}
.kb-annot-linemode svg { width: 16px; height: 16px; }
.kb-annot-linemode:hover { background: rgba(255,255,255,0.15); }
.kb-annot-linemode.is-active {
  background: var(--accent-soft);
  border-color: var(--accent);
  color: var(--accent);
}
/* Icon-only chips (the Arrow group: Single / Both-ends / Valve close / Valve open).
   Four labelled chips would clip on a phone; compact square icons read clearly and
   keep the whole group on one row even at 320px. */
.kb-annot-optgroup-icons .kb-annot-linemode {
  width: 40px; padding: 0; gap: 0;
  justify-content: center;
}
.kb-annot-optgroup-icons .kb-annot-linemode svg { width: 20px; height: 20px; }

/* Colour "well" — one swatch showing the current colour; tap reveals the
   palette popover (replaces the always-on 6-swatch row). */
.kb-annot-colorwell-wrap { position: relative; display: inline-flex; }
.kb-annot-colorwell {
  width: 40px; height: 40px;
  display: grid; place-items: center;
  background: rgba(255,255,255,0.08);
  border: 1px solid transparent;
  border-radius: var(--radius-md);
  cursor: pointer; padding: 0;
  transition: background 0.12s, border-color 0.12s;
}
.kb-annot-colorwell:hover { background: rgba(255,255,255,0.15); }
.kb-annot-colorwell[aria-expanded="true"] { border-color: var(--accent); }
.kb-annot-colorwell-dot {
  width: 22px; height: 22px;
  border-radius: var(--radius-full);
  box-shadow: 0 0 0 1.5px rgba(255,255,255,0.5);
}
.kb-annot-colorpop {
  position: absolute;
  bottom: calc(100% + 8px);
  left: 50%;
  transform: translateX(-50%);
  display: flex; gap: 8px; align-items: center;
  padding: 10px 12px;
  background: #232323;
  border: 1px solid rgba(255,255,255,0.12);
  border-radius: var(--radius-lg);
  box-shadow: 0 8px 24px rgba(0,0,0,0.45);
  z-index: 5;
}
.kb-annot-colorpop[hidden] { display: none; }

.kb-annot-color {
  width: 28px; height: 28px;
  border: 2px solid rgba(255,255,255,0.25);
  border-radius: var(--radius-full);
  cursor: pointer;
  padding: 0;
  transition: transform 0.12s, border-color 0.12s;
  flex-shrink: 0;
}
.kb-annot-color:hover { transform: scale(1.08); }
.kb-annot-color.is-active {
  border-color: #fff;
  box-shadow: 0 0 0 2px rgba(255,255,255,0.4);
}
/* White swatch needs an extra inner ring so it's visible against the
   dark toolbar — without this it looks like an empty white circle that's
   hard to distinguish from a missing button. */
.kb-annot-color[data-color="white"] {
  border-color: rgba(255,255,255,0.6);
}
.kb-annot-color[data-color="white"].is-active {
  box-shadow: 0 0 0 2px var(--accent, #06b6d4);
}
/* Black swatch with a faint outline so it doesn't blend into toolbar bg */
.kb-annot-color[data-color="black"] {
  border-color: rgba(255,255,255,0.4);
}

/* Disabled state for delete (no selection) */
.kb-annot-action:disabled {
  opacity: 0.35;
  cursor: not-allowed;
}
.kb-annot-action:disabled:hover {
  background: rgba(255,255,255,0.08);
}

.kb-annot-save {
  margin-left: auto;
  padding: 9px 18px;
  background: var(--accent);
  color: #fff;
  border: none;
  border-radius: var(--radius-md);
  font-family: var(--body);
  font-size: var(--text-md);
  font-weight: 600;
  cursor: pointer;
  transition: background 0.12s, transform 0.1s;
}
.kb-annot-save:hover { background: var(--accent-strong, var(--accent)); }
.kb-annot-save:active { transform: scale(0.97); }
.kb-annot-save:disabled { opacity: 0.6; cursor: not-allowed; }

/* Zoom controls row in annotation editor */
.kb-annot-zoom-row {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 0 4px;
}
.kb-annot-zoom-btn {
  width: 34px; height: 34px;
  display: grid; place-items: center;
  background: rgba(255,255,255,0.08);
  border: 1px solid rgba(255,255,255,0.15);
  border-radius: var(--radius-md);
  color: #fff;
  font-size: var(--text-2xl);
  font-weight: 600;
  cursor: pointer;
  transition: background 0.12s;
  touch-action: manipulation;
}
.kb-annot-zoom-btn:hover { background: rgba(255,255,255,0.16); }
.kb-annot-zoom-btn:disabled { opacity: 0.35; cursor: default; }
.kb-annot-zoom-level {
  font-size: var(--text-sm);
  font-weight: 600;
  color: rgba(255,255,255,0.7);
  min-width: 38px;
  text-align: center;
  /* Tap to reset to fit. Subtle visual treatment so it doesn't shout
     but it's clearly tappable when the user wants to zoom out fast. */
  background: transparent;
  border: 1px solid transparent;
  border-radius: var(--radius-md);
  padding: 4px 6px;
  cursor: pointer;
  font-family: var(--body);
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
  transition: background 0.12s, border-color 0.12s, color 0.12s;
}
.kb-annot-zoom-level:hover {
  background: rgba(255,255,255,0.08);
  border-color: rgba(255,255,255,0.15);
  color: #fff;
}
.kb-annot-zoom-level:active { transform: scale(0.96); }

/* Lightbox zoom indicator */
.kb-lightbox-zoom-hint {
  position: absolute;
  bottom: 16px;
  left: 50%;
  transform: translateX(-50%);
  background: rgba(0,0,0,0.65);
  color: rgba(255,255,255,0.85);
  font-size: var(--text-sm);
  font-weight: 600;
  padding: 4px 12px;
  border-radius: var(--radius-pill);
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.3s;
  z-index: 10;
  white-space: nowrap;
}
.kb-lightbox-zoom-hint.visible { opacity: 1; }

/* Lightbox annotate button — sits next to the close button on the photo viewer */
/* Action bar at top of the lightbox — sits next to the close button. Holds
   "Edit" + "Share" pill buttons. We deliberately keep the bar separate from
   the close so the close button keeps its own click target on the right. */
/* Docs lightbox actions — absolutely positioned next to the close button.
   Scoped to .kb-lightbox-overlay so the Quick Entry lightbox (.kb-lightbox)
   can use a different inline-flex layout for its actions. */
.kb-lightbox-overlay .kb-lightbox-actions {
  position: absolute;
  /* Align with the pv-header close button (now floored — see --safe-top). */
  top: var(--safe-top);
  right: calc(env(safe-area-inset-right) + 60px);
  display: inline-flex;
  gap: 8px;
  z-index: 2;
}
.kb-lightbox-overlay .kb-lightbox-action {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 7px 14px 7px 11px;
  background: rgba(255,255,255,0.16);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  border: 1px solid rgba(255,255,255,0.25);
  /* 10px matches the app's standard radius. Previously 18px which
     rendered as a full pill — visually distinct from every other
     button in the app and flagged by Radek as inconsistent. */
  border-radius: var(--radius-md);
  color: #fff;
  font-family: var(--body);
  font-size: var(--text-base);
  font-weight: 600;
  cursor: pointer;
  transition: background 0.12s;
}
.kb-lightbox-overlay .kb-lightbox-action:hover { background: rgba(255,255,255,0.28); }
.kb-lightbox-overlay .kb-lightbox-action svg { width: 14px; height: 14px; flex-shrink: 0; }

/* On narrow screens, hide the text and just show icons so both buttons fit */
@media (max-width: 480px) {
  .kb-lightbox-overlay .kb-lightbox-actions {
    right: calc(env(safe-area-inset-right) + 56px);
    gap: 6px;
  }
  .kb-lightbox-overlay .kb-lightbox-action span { display: none; }
  .kb-lightbox-overlay .kb-lightbox-action {
    padding: 8px;
    width: 36px;
    height: 36px;
    /* Match the desktop variant's 10px radius rather than a full
       circle. Consistent with the rest of the app's button language. */
    border-radius: var(--radius-md);
    justify-content: center;
  }
  .kb-lightbox-overlay .kb-lightbox-action svg { width: 16px; height: 16px; }
}

/* ─── Quick Entry lightbox actions ───
   Lives INSIDE the .kb-lightbox-top flex bar, between .kb-lightbox-info
   and .kb-lightbox-close. Inline-flex layout, NOT absolutely positioned. */
.kb-lightbox .kb-lightbox-actions {
  display: inline-flex;
  gap: 8px;
  pointer-events: auto;
  margin-left: auto;
  margin-right: 10px;
}
.kb-lightbox .kb-lightbox-action {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 8px 14px 8px 11px;
  background: rgba(255,255,255,0.1);
  border: 1px solid rgba(255,255,255,0.18);
  border-radius: var(--radius-md);
  color: #fff;
  font-family: var(--body);
  font-size: var(--text-base);
  font-weight: 600;
  cursor: pointer;
  transition: background 0.15s, transform 0.1s;
  -webkit-tap-highlight-color: transparent;
}
.kb-lightbox .kb-lightbox-action:hover { background: rgba(255,255,255,0.18); }
.kb-lightbox .kb-lightbox-action:active { transform: scale(0.96); }
.kb-lightbox .kb-lightbox-action svg { width: 14px; height: 14px; flex-shrink: 0; stroke-width: 2.2; }

/* Mobile: collapse to icon-only circles to save horizontal space */
@media (max-width: 480px) {
  .kb-lightbox .kb-lightbox-actions {
    gap: 6px;
    margin-right: 6px;
  }
  .kb-lightbox .kb-lightbox-action span { display: none; }
  .kb-lightbox .kb-lightbox-action {
    padding: 0;
    width: 40px;
    height: 40px;
    border-radius: var(--radius-md);
    justify-content: center;
  }
  .kb-lightbox .kb-lightbox-action svg { width: 16px; height: 16px; }
}

/* On narrow screens, drop the toolbar gap and let it stack horizontally still */
@media (max-width: 480px) {
  .kb-annot-toolbar {
    gap: 6px;
    padding: 10px 8px;
  }
  .kb-annot-options + .kb-annot-actions {
    padding-left: 6px;
  }
  .kb-annot-tool, .kb-annot-action {
    width: 36px; height: 36px;
    border-radius: var(--radius-md);
  }
  .kb-annot-colorwell { width: 36px; height: 36px; }
  .kb-annot-color {
    width: 28px; height: 28px;
  }
  .kb-annot-save {
    padding: 8px 14px;
    font-size: var(--text-base);
  }
  .kb-annot-img {
    max-height: calc(100vh - 170px); /* fill the stage like the full-screen viewer */
  }
}

/* ═════════════════════════════════════════════════════════════════════
   STYLED INPUT MODAL — replaces window.prompt()
   ═════════════════════════════════════════════════════════════════════
   Used for: text labels, measurement values, label edits.
   Renders inside the standard modal frame (.kb-modal) so it inherits all
   the existing border/shadow/animation work — we just add field/unit
   styling here.
*/
.kb-input-modal-field {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin-bottom: 14px;
}
.kb-input-modal-label {
  font-family: var(--body);
  font-size: var(--text-xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-muted);
}
/* Unit toggle — pill row of mm / cm / inches buttons */
.kb-input-modal-units {
  display: flex;
  gap: 6px;
  background: var(--bg-elevated);
  padding: 4px;
  border-radius: var(--radius-md);
  border: 1px solid var(--border);
}
.kb-input-modal-unit {
  flex: 1;
  padding: 9px 12px;
  background: transparent;
  border: none;
  border-radius: var(--radius-md);
  font-family: var(--body);
  font-size: var(--text-base);
  font-weight: 600;
  color: var(--text-secondary);
  cursor: pointer;
  transition: background 0.12s, color 0.12s, transform 0.12s;
  -webkit-tap-highlight-color: transparent;
}
.kb-input-modal-unit:hover {
  color: var(--text-primary);
}
.kb-input-modal-unit:active {
  transform: scale(0.97);
}
.kb-input-modal-unit.is-active {
  background: var(--bg-surface);
  color: var(--accent);
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08), 0 0 0 1px var(--border);
}

/* ═════════════════════════════════════════════════════════════════════
   SHARE PHOTO OPTIONS — replaces inline-styled buttons in share menu
   ═════════════════════════════════════════════════════════════════════
*/
.kb-share-options {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.kb-share-option {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 14px 14px 14px 12px;
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  cursor: pointer;
  font-family: var(--body);
  text-align: left;
  transition: background 0.12s, border-color 0.12s, transform 0.1s;
  width: 100%;
}
.kb-share-option:hover {
  background: var(--bg-surface);
  border-color: var(--accent);
}
.kb-share-option:active {
  transform: scale(0.99);
}
.kb-share-option-primary {
  background: var(--accent-soft);
  border-color: var(--accent);
}
.kb-share-option-primary:hover {
  background: var(--accent-soft);
  border-color: var(--accent);
}
.kb-share-option-icon {
  width: 36px;
  height: 36px;
  display: grid;
  place-items: center;
  background: var(--bg-surface);
  border-radius: var(--radius-md);
  color: var(--accent);
  flex-shrink: 0;
}
.kb-share-option-primary .kb-share-option-icon {
  background: var(--accent);
  color: #fff;
}
.kb-share-option-icon svg { width: 18px; height: 18px; }
.kb-share-option-text {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.kb-share-option-title {
  font-size: var(--text-md);
  font-weight: 600;
  color: var(--text-primary);
}
.kb-share-option-primary .kb-share-option-title {
  color: var(--accent);
}
.kb-share-option-sub {
  font-size: var(--text-sm);
  color: var(--text-muted);
  line-height: 1.3;
}
.kb-share-option-chevron {
  width: 20px;
  height: 20px;
  display: grid;
  place-items: center;
  color: var(--text-muted);
  flex-shrink: 0;
}
.kb-share-option-chevron svg { width: 16px; height: 16px; }

/* ═════════════════════════════════════════════════════════════════════
   TREE + PANEL VIEW (desktop folder browser)
   ═════════════════════════════════════════════════════════════════════
   Active only on desktop (≥1024px). On mobile, the existing single-pane
   folder views are used instead.
*/
.kb-tree-layout {
  display: flex;
  align-items: stretch;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--bg-elevated);
  overflow: hidden;
  /* Fill the desktop viewport height instead of stopping short. The old
     calc(100vh - 280px) over-subtracted by ~100px, leaving a dead band of
     wasted desktop below the panel and squeezing the folder tree into a
     short inner-scrolling box. Now the pane reaches near the screen bottom
     (and respects the impersonation banner via --banner-h), so the whole
     tree is visible and the desktop space is actually used. */
  min-height: 480px;
  height: calc(100vh - var(--banner-h, 0px) - 184px);
}

/* ─── LEFT SIDEBAR (the tree) ────────────────────────────────────── */
.kb-tree-sidebar {
  flex: 0 0 280px;
  display: flex;
  flex-direction: column;
  background: var(--bg-surface);
  border-right: 1px solid var(--border);
  min-width: 0;
}

.kb-tree-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 12px 14px;
  border-bottom: 1px solid var(--border);
  background: var(--bg-elevated);
  flex-shrink: 0;
}
.kb-tree-header-label {
  font-family: var(--body);
  font-size: var(--text-xs);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--text-muted);
}
.kb-tree-action {
  width: 28px;
  height: 28px;
  display: grid;
  place-items: center;
  background: var(--bg-surface);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-md);
  color: var(--text-secondary);
  cursor: pointer;
  transition: background 0.12s, color 0.12s, border-color 0.12s;
}
.kb-tree-action:hover {
  background: var(--accent-soft);
  border-color: var(--accent);
  color: var(--accent);
}
.kb-tree-action svg { width: 14px; height: 14px; }

.kb-tree-list {
  flex: 1;
  overflow-y: auto;
  padding: 8px 6px;
  /* Themed scrollbar — no white system bar leaking through */
  scrollbar-width: thin;
  scrollbar-color: var(--border-strong, var(--border)) transparent;
}
.kb-tree-list::-webkit-scrollbar { width: 8px; }
.kb-tree-list::-webkit-scrollbar-track { background: transparent; }
.kb-tree-list::-webkit-scrollbar-thumb {
  background: var(--border-strong, var(--border));
  border-radius: var(--radius-sm);
  border: 2px solid transparent;
  background-clip: content-box;
}
.kb-tree-list::-webkit-scrollbar-thumb:hover {
  background: var(--text-muted);
  background-clip: content-box;
}

/* ─── A SINGLE ROW IN THE TREE ───────────────────────────────────── */
/* The wrapper holds the indent (margin-left) so the row itself can stay
   simple flex content. This means selection backgrounds extend across
   the whole row, but indents still nest visually. */
.kb-tree-row-wrap {
  /* CSS variable used to nudge the row right based on depth */
  --kb-tree-depth: 0;
  position: relative;
  padding-left: calc(var(--kb-tree-depth) * 14px);
}

/* Subtle vertical guide line connecting nested items to their parent.
   Only visible on rows that ARE indented (depth > 0). Drawn very faintly
   so it gives a hint of structure without competing with content. */
.kb-tree-row-wrap::before {
  content: '';
  position: absolute;
  top: 2px;
  bottom: 2px;
  /* Position the guide line aligned with the parent caret column */
  left: calc(var(--kb-tree-depth) * 14px - 8px);
  width: 1px;
  background: var(--border-strong);
  opacity: 0.85;
  /* Hide on top-level rows */
  display: var(--kb-tree-guide, none);
}

.kb-tree-row {
  display: flex;
  align-items: center;
  justify-content: flex-start;
  gap: 4px;
  width: 100%;
  padding: 2px 6px 2px 6px;
  background: transparent;
  border-radius: var(--radius-md);
  font-family: var(--body);
  color: var(--text-primary);
  text-align: left;
  -webkit-tap-highlight-color: transparent;
  transition: background 0.1s;
  flex-wrap: nowrap;
  min-width: 0;
  white-space: nowrap;
}
.kb-tree-row.is-edit-mode {
  flex-wrap: wrap;
  white-space: normal;
  padding-bottom: 6px;
}
.kb-tree-row.is-edit-mode .kb-tree-row-target {
  flex: 0 0 100%;
  white-space: nowrap;
}
.kb-tree-row.is-edit-mode .kb-edit-actions {
  padding-left: calc(var(--kb-tree-depth, 0) * 20px + 28px);
  width: 100%;
  margin-top: 0;
}
.kb-tree-row:hover {
  background: var(--bg-elevated);
}
.kb-tree-row.is-selected {
  background: var(--accent-soft);
  /* Stronger "you are here" marker — an inset accent bar on the leading edge,
     rounded to the row radius, on top of the accent-soft fill. */
  box-shadow: inset 2px 0 0 var(--accent);
}
.kb-tree-row.is-selected .kb-tree-row-target { color: var(--accent); }
.kb-tree-row.is-selected .kb-tree-icon { color: var(--accent); }
.kb-tree-row.is-dragging { opacity: 0.4; }
.kb-tree-row.is-drop-target {
  background: var(--accent-soft);
  outline: 2px solid var(--accent);
  outline-offset: -2px;
}

/* The clickable label area inside each row. Sits next to the caret as a
   sibling — neither is nested inside the other (which would have been
   invalid HTML). */
.kb-tree-row-target {
  display: flex;
  align-items: center;
  gap: 8px;
  flex: 1 1 auto;
  min-width: 0;
  padding: 5px 4px 5px 0;
  background: transparent;
  border: none;
  cursor: pointer;
  text-align: left;
  font-family: var(--body);
  color: inherit;
  -webkit-tap-highlight-color: transparent;
  flex-wrap: nowrap;
  white-space: nowrap;
  border-radius: var(--radius-sm);
}
.kb-tree-row.is-selected .kb-tree-row-target {
  font-weight: 600;
}

/* The "All folders" home row at the top of the tree. Single-button layout
   (no caret), styled identically to folder rows so the sidebar reads as
   one consistent column with one selection style across all entries. */
.kb-tree-row-root {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  padding: 7px 8px;
  background: transparent;
  border: none;
  border-radius: var(--radius-md);
  cursor: pointer;
  text-align: left;
  font-family: var(--body);
  font-weight: 600;
  color: var(--text-secondary);
  -webkit-tap-highlight-color: transparent;
  flex-wrap: nowrap;
  white-space: nowrap;
}
.kb-tree-row-root:hover {
  background: var(--bg-elevated);
  color: var(--text-primary);
}
.kb-tree-row-root.is-selected {
  background: var(--accent-soft);
  color: var(--text-primary);
  box-shadow: inset 2px 0 0 var(--accent);
}
.kb-tree-row-root.is-selected .kb-tree-icon {
  color: var(--accent);
}

/* Caret button — sits at the start of every row, takes a fixed width even
   when there are no children (so labels align across the tree). */
.kb-tree-caret {
  width: 18px;
  height: 18px;
  display: grid;
  place-items: center;
  background: transparent;
  border: none;
  cursor: pointer;
  color: var(--text-muted);
  border-radius: var(--radius-sm);
  flex: 0 0 18px;
  transition: transform 0.15s, color 0.12s, background 0.12s;
}
.kb-tree-caret:hover { background: var(--bg-surface); color: var(--text-primary); }
.kb-tree-caret.is-open { transform: rotate(90deg); }
.kb-tree-caret svg { width: 12px; height: 12px; }

/* Reserved space placeholder so rows without a caret still align with
   rows that have one. Same width as the caret. */
.kb-tree-spacer {
  flex: 0 0 18px;
  height: 18px;
}

.kb-tree-icon {
  flex: 0 0 18px;
  height: 18px;
  display: grid;
  place-items: center;
  /* Calm by default (§4: identifying colour on the icon only when it matters).
     Accent is re-applied on the SELECTED row below and on category nodes that
     carry an inline colour (the collection-browser axis tree); library/captures/
     archive system icons own their own colour classes. */
  color: var(--text-secondary);
}
.kb-tree-icon svg { width: 16px; height: 16px; }

.kb-tree-label {
  flex: 1 1 auto;
  min-width: 0;
  font-size: var(--text-base);
  font-weight: 500;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.kb-tree-row.is-selected .kb-tree-label { font-weight: 600; }

.kb-tree-count {
  flex: 0 0 auto;
  min-width: 20px;
  height: 18px;
  padding: 0 6px;
  display: inline-grid;
  place-items: center;
  background: var(--bg-elevated);
  color: var(--text-muted);
  font-size: var(--text-xs);
  font-weight: 600;
  border-radius: var(--radius-md);
  margin-left: 4px;
  border: 1px solid var(--border);
}
.kb-tree-row.is-selected .kb-tree-count {
  background: var(--accent);
  color: #fff;
  border-color: var(--accent);
}

/* ─── RIGHT PANEL (content) ──────────────────────────────────────── */
.kb-tree-panel {
  flex: 1;
  min-width: 0;
  overflow-y: auto;
  padding: 16px 18px;
  background: var(--bg-elevated);
}

/* NOTE: folder tiles in the panel stay a single-column, full-width list
   (the .kb-folder-list base in css/03) — one card on top of another, like
   the document list. A multi-column grid was tried here but forced the
   cards too narrow and truncated the folder names, so it was reverted
   (Radek, 2026-06-16). Do NOT re-add a grid; the taller .kb-tree-layout
   already makes more cards visible without needing columns. */

/* Drag visual feedback on right-panel cards */
.kb-tree-panel .kb-folder-card[draggable="true"],
.kb-tree-panel .kb-instr-card[draggable="true"],
.kb-tree-panel .entry-card[draggable="true"] {
  cursor: grab;
}
.kb-tree-panel .kb-folder-card.is-dragging,
.kb-tree-panel .kb-instr-card.is-dragging,
.kb-tree-panel .entry-card.is-dragging {
  opacity: 0.4;
  cursor: grabbing;
}

/* Below the desktop breakpoint we don't render the tree+panel layout
   at all. The single-pane folder content view is used directly. */
@media (max-width: 1023px) {
  .kb-tree-layout { display: none; }
}

/* ═════════════════════════════════════════════════════════════════════
   SITE PICKER (KB module header)
   ═════════════════════════════════════════════════════════════════════
   Replaces the static site banner with a tappable picker so users can
   choose which site notes get captured to / filtered by, regardless of
   the URL they entered the KB from.
*/
.kb-site-picker {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 10px 6px 8px;
  background: var(--accent-soft);
  color: var(--accent);
  border: 1px solid var(--accent);
  border-radius: var(--radius-lg);
  font-family: var(--body);
  font-size: var(--text-sm);
  font-weight: 600;
  cursor: pointer;
  transition: background 0.12s, transform 0.1s, box-shadow 0.12s;
  -webkit-tap-highlight-color: transparent;
  margin-bottom: 8px;
}
.kb-site-picker:hover {
  background: var(--accent);
  color: #fff;
}
.kb-site-picker:active {
  transform: scale(0.97);
}
.kb-site-picker svg {
  width: 13px;
  height: 13px;
  stroke-width: 2.4;
  flex-shrink: 0;
}
.kb-site-picker-name {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 200px;
}
.kb-site-picker-caret {
  width: 12px;
  height: 12px;
  opacity: 0.7;
}
.kb-site-picker-empty {
  background: var(--bg-elevated);
  color: var(--text-secondary);
  border-color: var(--border);
}
.kb-site-picker-empty:hover {
  background: var(--bg-surface);
  color: var(--text-primary);
  border-color: var(--text-muted);
}

/* Picker modal — list of sites + "All sites" option, each as a tappable row */
.kb-site-pick-list {
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.kb-site-pick-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 14px;
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  cursor: pointer;
  font-family: var(--body);
  text-align: left;
  transition: background 0.12s, border-color 0.12s, transform 0.1s;
  -webkit-tap-highlight-color: transparent;
  width: 100%;
}
.kb-site-pick-row:hover {
  background: var(--bg-surface);
  border-color: var(--accent);
}
.kb-site-pick-row:active {
  transform: scale(0.99);
}
.kb-site-pick-row.is-current {
  background: var(--accent-soft);
  border-color: var(--accent);
}
.kb-site-pick-icon {
  width: 32px;
  height: 32px;
  display: grid;
  place-items: center;
  background: var(--bg-surface);
  border-radius: var(--radius-md);
  color: var(--accent);
  flex-shrink: 0;
}
.kb-site-pick-icon-all {
  background: var(--bg-elevated);
  color: var(--text-muted);
}
.kb-site-pick-row.is-current .kb-site-pick-icon {
  background: var(--accent);
  color: #fff;
}
.kb-site-pick-icon svg { width: 16px; height: 16px; }
.kb-site-pick-text {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.kb-site-pick-name {
  font-size: var(--text-md);
  font-weight: 600;
  color: var(--text-primary);
}
.kb-site-pick-row.is-current .kb-site-pick-name {
  color: var(--accent);
}
.kb-site-pick-sub {
  font-size: var(--text-xs);
  color: var(--text-muted);
  line-height: 1.4;
}
.kb-site-pick-check {
  width: 24px;
  height: 24px;
  display: grid;
  place-items: center;
  color: var(--accent);
  flex-shrink: 0;
}
.kb-site-pick-check svg { width: 18px; height: 18px; }

/* ═══════════════════════════════════════════════════════════════════════
   SHARED LIST-CARD LOCATION CHIP
   ONE location chip for every list card (Tasks / Call-outs / Assets) so
   "where the job is" reads identically across the app: accent-tinted, pin
   icon, leads the top-left of the card, truncates when long. New modules use
   `.card-loc-chip`; Tasks keeps `.tasks-card-location` as a co-selector so its
   markup (and the Projects plan tree that reuses that class) is untouched.
   The card's classifier (department / category) is pinned to the right by each
   module's own `*-card-top` scoped rule.
   ═══════════════════════════════════════════════════════════════════════ */
.card-loc-chip,
.tasks-card-location {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  min-width: 0;            /* allow truncation inside a flex row */
  flex: 0 1 auto;
  max-width: 100%;
  padding: 4px 9px;
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  color: var(--text-secondary);
  font: 600 var(--text-xs) / 1 var(--body);
  letter-spacing: 0.01em;
}
/* Pin keeps the accent colour — a small cue so location is instantly
   recognisable while the chip body stays calm (the two-tier card-chip rule:
   neutral context chips, colour reserved for priority/status signals). */
.card-loc-chip svg,
.tasks-card-location svg { width: 13px; height: 13px; flex-shrink: 0; color: var(--accent); }
.card-loc-chip-text,
.tasks-card-location-text { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
/* Faint "inherited" variant (audit builder): a question that inherits its
   section's location rather than setting its own. Dashed + muted so "inherited,
   not set here" reads at a glance without competing with an explicit chip. */
.card-loc-chip--ghost { background: transparent; border-style: dashed; color: var(--text-muted); }
.card-loc-chip--ghost svg { color: var(--text-muted); }

/* ═══════════════════════════════════════════════════════════════════════
   MAINTENANCE "ON DUTY TODAY" CARD (dashboard)
   Calm, consistent with the dashboard surface. One row per maintenance site:
   site name + on-duty avatars + a self-toggle.
   ═══════════════════════════════════════════════════════════════════════ */
.duty-card { background: var(--bg-surface); border: 1px solid var(--border); border-radius: var(--radius-lg); overflow: hidden; }
.duty-loading { padding: 16px; color: var(--text-muted); font: 500 var(--text-sm)/1 var(--body); }
.duty-row { display: flex; align-items: center; gap: 12px; padding: 14px 16px; }
.duty-row + .duty-row { border-top: 1px solid var(--border); }
.duty-row-main { flex: 1; min-width: 0; display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.duty-site { font: 700 var(--text-sm)/1.2 var(--display, var(--body)); color: var(--text-primary); }
.duty-people { display: flex; align-items: center; }
.duty-av { display: grid; place-items: center; width: 28px; height: 28px; border-radius: 50%; background: var(--av, #0891b2); color: #fff; font: 700 11px/1 var(--body); border: 2px solid var(--bg-surface); }
.duty-av + .duty-av { margin-left: -8px; }
.duty-none { font: 500 var(--text-xs)/1 var(--body); color: var(--text-muted); }
/* Read-only "who's on duty" rows (department dashboard): names under the avatars
   so a viewer who can't toggle still sees who's in charge. */
.duty-readonly-names { width: 100%; margin-top: 2px; font: 500 var(--text-xs)/1.4 var(--body); color: var(--text-secondary); }
.duty-toggle { flex-shrink: 0; padding: 8px 14px; border-radius: 999px; border: 1px solid var(--border); background: var(--bg-base); color: var(--text-secondary); font: 600 var(--text-sm)/1 var(--body); cursor: pointer; transition: background .12s, color .12s, border-color .12s; -webkit-tap-highlight-color: transparent; }
.duty-toggle:hover { border-color: var(--accent); color: var(--text-primary); }
.duty-toggle:active { transform: scale(0.97); }
.duty-toggle.is-on { background: color-mix(in srgb, var(--accent) 16%, transparent); border-color: var(--accent); color: var(--accent); }

/* Shift-end picker — shown when going on duty. Picking a finish time auto-clocks
   you off, so nobody forgets to turn duty off and gets pinged on their night off.
   A calm bottom-sheet; reuses the app surface/accent vars (no parallel styles). */
.duty-shift-overlay { position: fixed; inset: 0; z-index: 4000; background: rgba(0,0,0,.45); display: flex; align-items: flex-end; justify-content: center; animation: dutyShiftFade .15s ease; }
@keyframes dutyShiftFade { from { opacity: 0; } to { opacity: 1; } }
.duty-shift-sheet { width: 100%; max-width: 440px; background: var(--bg-surface); border: 1px solid var(--border); border-bottom: none; border-radius: var(--radius-lg) var(--radius-lg) 0 0; padding: 20px 18px calc(18px + env(safe-area-inset-bottom)); box-shadow: 0 -8px 32px rgba(0,0,0,.28); animation: dutyShiftUp .2s cubic-bezier(.22,1,.36,1); }
@keyframes dutyShiftUp { from { transform: translateY(18px); opacity: .6; } to { transform: translateY(0); opacity: 1; } }
.duty-shift-title { font: 700 var(--text-lg)/1.2 var(--display, var(--body)); color: var(--text-primary); }
.duty-shift-sub { margin-top: 4px; font: 500 var(--text-sm)/1.4 var(--body); color: var(--text-secondary); }
/* Shift-length stepper — the fast path (default 8h, ±30 min). The big value is
   the length; the muted line under it is the finish clock time it works out to. */
.duty-step { display: flex; align-items: center; gap: 12px; margin-top: 16px; padding: 10px 12px; border: 1px solid var(--border); border-radius: var(--radius-md); background: var(--bg-base); }
.duty-step-btn { flex: 0 0 auto; width: 44px; height: 44px; border-radius: var(--radius-md); border: 1px solid var(--accent); background: color-mix(in srgb, var(--accent) 12%, transparent); color: var(--accent); font: 700 22px/1 var(--body); cursor: pointer; transition: transform .08s, opacity .12s; -webkit-tap-highlight-color: transparent; }
.duty-step-btn:active { transform: scale(.94); }
.duty-step-btn:disabled { opacity: .38; cursor: default; border-color: var(--border); color: var(--text-muted); background: transparent; }
.duty-step-read { flex: 1; min-width: 0; text-align: center; }
.duty-step-value { font: 700 var(--text-xl)/1.1 var(--display, var(--body)); color: var(--text-primary); }
.duty-step-finish { margin-top: 2px; font: 500 var(--text-xs)/1 var(--body); color: var(--text-secondary); }
/* Primary confirm — matches .tasks-btn-primary (accent fill, brightness on hover). */
.duty-shift-primary { width: 100%; margin-top: 12px; padding: 14px; border-radius: var(--radius-md); border: 1px solid var(--accent); background: var(--accent); color: var(--accent-text, #fff); font: 700 var(--text-md)/1 var(--body); cursor: pointer; transition: transform .08s, filter .12s; -webkit-tap-highlight-color: transparent; }
.duty-shift-primary:hover { filter: brightness(1.1); }
.duty-shift-primary:active { transform: scale(.99); }
/* "Until I turn it off" — a full-width secondary chip below the primary CTA. */
.duty-shift-chip { padding: 13px 14px; border-radius: var(--radius-md); border: 1px solid var(--border); background: var(--bg-base); color: var(--text-primary); font: 600 var(--text-sm)/1 var(--body); cursor: pointer; transition: border-color .12s, background .12s, transform .08s; -webkit-tap-highlight-color: transparent; }
.duty-shift-chip:hover { border-color: var(--accent); }
.duty-shift-chip:active { transform: scale(.98); }
.duty-shift-open { display: block; width: 100%; margin-top: 8px; color: var(--text-secondary); }
.duty-shift-exact { display: flex; align-items: center; gap: 8px; margin-top: 14px; }
.duty-shift-exact label { font: 600 var(--text-xs)/1 var(--body); color: var(--text-muted); white-space: nowrap; }
.duty-shift-time { flex: 1; min-width: 0; padding: 10px 12px; border-radius: var(--radius-md); border: 1px solid var(--border); background: var(--bg-base); color: var(--text-primary); font: 600 var(--text-sm)/1 var(--body); }
.duty-shift-go { padding: 10px 16px; border-radius: var(--radius-md); border: 1px solid var(--accent); background: color-mix(in srgb, var(--accent) 16%, transparent); color: var(--accent); font: 700 var(--text-sm)/1 var(--body); cursor: pointer; }
.duty-shift-go:active { transform: scale(.98); }
.duty-shift-cancel { width: 100%; margin-top: 14px; padding: 12px; border-radius: var(--radius-md); border: none; background: transparent; color: var(--text-muted); font: 600 var(--text-sm)/1 var(--body); cursor: pointer; }
.duty-shift-cancel:hover { color: var(--text-secondary); }

/* ── "On duty" KPI accordion ──────────────────────────────────────────────────
   The "On duty" stat card (renderStatGrid, toggle:'duty') unfolds its rosters into
   #dashDutyMount, mirroring the My-tasks / Sites accordions — only ONE open at a
   time (wireStatFolds_). The rosters hydrate on mount even while collapsed, so the
   KPI shows a live count of who's on (updateDutyCount_). Radek 2026-06-30. */
.duty-group-label { padding: 8px 8px 4px; font: 600 var(--text-xs)/1 var(--body); letter-spacing: .03em; text-transform: uppercase; color: var(--text-muted); }
.duty-fold { display: flex; flex-direction: column; gap: 8px; }
/* Desktop: lay the department groups out in columns so the unfolded list stays
   short rather than stacking deep. */
@media (min-width: 768px) {
  .duty-fold { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 8px 10px; align-items: start; }
}

/* Mobile: tighten the unfolded rosters so they fit in less height. */
@media (max-width: 767px) {
  .duty-row { padding: 9px 12px; gap: 10px; }
  .duty-row-main { gap: 8px; }
  .duty-av { width: 24px; height: 24px; font-size: 10px; }
  .duty-toggle { padding: 6px 12px; font-size: var(--text-xs); }
  .duty-readonly-names { font-size: 11px; }
  .duty-loading { padding: 11px 12px; }
}

/* Mobile width pass (2026-06-25): tighten horizontal padding on mobile so content
   uses the screen width. Appended at end-of-file so it beats the base rules AND any
   wider-breakpoint (600/640/767px) blocks at equal specificity (later source wins).
   Desktop (>=600px) untouched. */
@media (max-width: 599px) {
  .dashboard-empty-block { padding: 24px 16px; }
  .duty-shift-sheet { padding: 16px 12px calc(12px + env(safe-area-inset-bottom)); }
  .kb-tree-panel { padding: 12px 10px; }
  .kb-tree-header { padding: 10px 10px; }
  .kb-annot-topbar { padding: 10px 12px; }
  .kb-site-pick-row { padding: 10px 10px; }
}

/* ─────────────────────────────────────────────────────────────────────────
   PHOTO ANNOTATION EDITOR — DESKTOP LAYOUT (2026-07-12)
   The editor is mobile-tuned, which wastes vertical space on a real desktop:
   (1) the overlay reserves --safe-top (54px floor) to clear the iPhone
       notch/status bar — a pure black band on a desktop that has no notch; and
   (2) the toolbar forces its options group onto its OWN full-width line
       (.kb-annot-options flex-basis:100%), so the bottom chrome runs THREE rows
       tall (tools / options / actions+zoom+save). Both eat the working area.
   Desktop-only reclaim — this is the SAME query that drives the overlay's
   net-1.0 unzoom in css/01, so it fires exactly where the editor runs at 1:1
   (wide viewport + mouse); mobile and touch tablets are untouched. Save's
   margin-left:auto already right-pins it, so dropping the forced options break
   collapses the toolbar to one clean row (flex-wrap stays on — the 4-chip Arrow
   group still wraps gracefully rather than clipping). The photo then fills the
   freed space (the img cap was tuned for the tall 3-row toolbar; retune it to
   the new, slim chrome so the stage governs — WYSIWYG vs the full-screen viewer
   only improves as the two sizes converge). Appended at end-of-file so it beats
   the base kb-annot rules at equal specificity (§4 source-order law); the
   max-width:599px block above is mutually exclusive, so order is moot there. */
@media (min-width: 1024px) and (pointer: fine) {
  /* No notch on a desktop → reclaim the status-bar safe gap above the header. */
  .kb-annot-overlay { padding-top: 0; }
  /* Slimmer, right-sized header instead of a tall mobile bar. */
  .kb-annot-topbar { padding: 8px 16px; }
  .kb-annot-title { font-size: var(--text-lg); }
  /* One-row toolbar: stop the options group claiming its own full-width line. */
  .kb-annot-toolbar { padding: 8px 16px; }
  .kb-annot-options { flex-basis: auto; }
  /* Give the photo the space the slimmed chrome freed. */
  .kb-annot-img { max-height: calc(100vh - 96px); }
}

