/* ============================================================
   Dockudock — v0.2.0 visual refresh
   Layered on top of Pico CSS (classless) and FontAwesome 6.
   Zero build tooling — every rule below is plain CSS that
   pages can opt into by adding class names to their templates.
   ============================================================ */

/* ── 1. Design tokens ──────────────────────────────────────── */
:root {
  /* Brand palette — light professional with vibrant blue accent */
  --docku-primary:        #2563eb;
  --docku-primary-dark:   #1d4ed8;
  --docku-primary-light:  #3b82f6;
  --docku-primary-50:     #eff6ff;
  --docku-primary-100:    #dbeafe;
  --docku-primary-soft:   #bfdbfe;
  /* Interactive link colour.  FD-011: links used to paint `--docku-primary`
     directly, which is dark-theme unsafe — #2563eb on the dark app surface
     reads 3.6:1 (below AA).  The token lets dark lift to `-light` while
     light keeps the brand hue. */
  --docku-link:           var(--docku-primary);
  --docku-link-hover:     var(--docku-primary-dark);

  /* Surfaces */
  --docku-bg:             #f1f5f9;
  --docku-surface:        #ffffff;
  --docku-surface-raised: #f8fafc;
  --docku-surface-sunken: #e2e8f0;

  /* Row-state tints — used by interactive rows (hover, expanded).  Hover
     sits on --docku-primary-100, clearly stronger than the plain row
     surface; expanded stays on the surface too.  There is deliberately no
     zebra stripe: every data-table row shares one background. */
  --docku-row-hover-bg:         var(--docku-primary-100);
  --docku-row-expanded-bg:      #ffffff;
  --docku-row-expanded-border:  var(--docku-border);
  /* Left accent bar: marks the interactive row under the pointer / keyboard
     focus, and stays on the row whose detail panel is open. */
  --docku-row-accent:           var(--docku-primary);

  /* Borders */
  --docku-border:         #e2e8f0;
  --docku-border-strong:  #cbd5e1;

  /* Text */
  --docku-text:           #0f172a;
  --docku-text-2:         #334155;
  /* Both muted tones must clear WCAG AA (4.5:1) on the lightest
     surfaces they sit on (#ffffff cards and #f1f5f9 page bg); axe
     flagged the previous #64748b/#94a3b8 pair at 4.34/2.56. */
  --docku-text-muted:     #526175;
  --docku-text-faint:     #5f6f84;

  /* Semantic */
  --docku-success:        #10b981;
  --docku-success-soft:   #d1fae5;
  --docku-success-text:   #065f46;
  /* Solid green button fill (.btn-success).  Declared in :root only
     (theme-invariant) because white-on-green contrast is a property of the
     fill/text pair, not of the page: `--docku-success` (#10b981) under white
     text is only 2.56:1 and fails AA, so the fill is emerald-700 (5.55:1)
     and hover deepens to emerald-800 (7.69:1).  A dark fill is required in
     both themes — the dark `--docku-success-text` is far too light to carry
     white text.  The foreground is a token (not a raw `#fff`) so the
     fill/text pair is declared together and the literal ratchet stays flat. */
  --docku-btn-success-bg:    #047857;
  --docku-btn-success-hover: #065f46;
  --docku-btn-success-fg:    #fff;
  --docku-warning:        #f59e0b;
  --docku-warning-soft:   #fef3c7;
  --docku-warning-text:   #92400e;
  --docku-danger:         #ef4444;
  --docku-danger-soft:    #fee2e2;
  --docku-danger-text:    #991b1b;
  --docku-info:           #3b82f6;
  --docku-info-soft:      #dbeafe;
  --docku-info-text:      #1e40af;

  /* Spacing scale (4px base) */
  --docku-space-1: 0.25rem;
  --docku-space-2: 0.5rem;
  --docku-space-3: 0.75rem;
  --docku-space-4: 1rem;
  --docku-space-5: 1.25rem;
  --docku-space-6: 1.5rem;
  --docku-space-8: 2rem;
  --docku-space-10: 2.5rem;
  --docku-space-12: 3rem;

  /* Radii */
  --docku-radius-sm: 6px;
  --docku-radius:    10px;
  --docku-radius-lg: 14px;
  --docku-radius-xl: 18px;
  --docku-radius-full: 9999px;

  /* Shadows */
  --docku-shadow-xs: 0 1px 2px rgba(15, 23, 42, 0.04);
  --docku-shadow-sm: 0 1px 3px rgba(15, 23, 42, 0.06), 0 1px 2px rgba(15, 23, 42, 0.04);
  --docku-shadow:    0 4px 6px -1px rgba(15, 23, 42, 0.07), 0 2px 4px -2px rgba(15, 23, 42, 0.05);
  --docku-shadow-md: 0 10px 15px -3px rgba(15, 23, 42, 0.07), 0 4px 6px -4px rgba(15, 23, 42, 0.05);
  --docku-shadow-lg: 0 20px 25px -5px rgba(15, 23, 42, 0.08), 0 8px 10px -6px rgba(15, 23, 42, 0.05);
  --docku-shadow-primary: 0 6px 16px -4px rgba(37, 99, 235, 0.35);

  /* Shared focus ring — the 3px halo used by .btn and by the
     non-.btn controls covered by the FD-005 state contract. */
  --docku-focus-ring: 0 0 0 3px var(--docku-primary-soft);

  /* Layout */
  --docku-sidebar-w:    248px;
  --docku-topbar-h:     60px;
  --docku-content-max:  1280px;

  /* Animation */
  --docku-ease:        cubic-bezier(0.22, 0.61, 0.36, 1);
  --docku-ease-out:    cubic-bezier(0.16, 1, 0.3, 1);
  --docku-dur-fast:    0.12s;
  --docku-dur:         0.2s;
  --docku-dur-slow:    0.32s;

  /* Aliases to keep the rest of the file readable */
  --app-sidebar-width: var(--docku-sidebar-w);
  --pico-card-background-color: var(--docku-surface);
  --pico-muted-border-color: var(--docku-border);
  --pico-muted-color: var(--docku-text-muted);
  --pico-secondary-background: var(--docku-surface-raised);
  --pico-background-color: var(--docku-bg);
  --pico-color: var(--docku-text);
  --pico-border-radius: var(--docku-radius);
  --pico-primary: var(--docku-primary);
}

/* Dark theme overrides — same palette, different surface tokens */
[data-theme="dark"] {
  --docku-bg:             #0b1220;
  --docku-surface:        #111a2c;
  --docku-surface-raised: #18233a;
  --docku-surface-sunken: #0a1019;
  --docku-border:         #1e2a44;
  --docku-border-strong:  #2a3a5a;
  --docku-text:           #f1f5f9;
  --docku-text-2:         #cbd5e1;
  --docku-text-muted:     #94a3b8;
  --docku-text-faint:     #64748b;
  --docku-primary-50:     #0f1f3d;
  --docku-primary-100:    #15294e;
  /* Link colour (FD-011 dark override).  `-light` (#3b82f6) clears AA on the
     dark app surface (4.8–5.1:1); hover lifts to `-soft` instead of dropping
     to `-dark`, which would fall to ~2.8:1 here. */
  --docku-link:           var(--docku-primary-light);
  --docku-link-hover:     var(--docku-primary-soft);
  --docku-success-soft:   #052e1f;
  --docku-warning-soft:   #2a1d05;
  --docku-danger-soft:    #2c0e0e;
  --docku-info-soft:      #0e1e3a;

  /* Semantic text shades.  The light-theme 800/900 values are near-
     unreadable on the very dark `-soft` fills above (and as standalone
     hint text on the dark page), so flip to 300-level tints. */
  --docku-success-text:   #6ee7b7;
  --docku-warning-text:   #fcd34d;
  --docku-danger-text:    #fca5a5;
  --docku-info-text:      #93c5fd;

  /* Row-state tints (dark override).  Hover uses the brand tint
     (--docku-primary-100 → #15294e), clearly bluer/lighter than the row
     surface; expanded keeps a neutral that stays away from brand navy. */
  --docku-row-hover-bg:         var(--docku-primary-100);
  --docku-row-expanded-bg:      #152033;
  --docku-row-expanded-border:  var(--docku-border-strong);
  --docku-shadow-xs: 0 1px 2px rgba(0, 0, 0, 0.4);
  --docku-shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.5);
  --docku-shadow:    0 4px 6px -1px rgba(0, 0, 0, 0.5);
  --docku-shadow-md: 0 10px 15px -3px rgba(0, 0, 0, 0.55);
  --docku-shadow-lg: 0 20px 25px -5px rgba(0, 0, 0, 0.6);
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  background: var(--docku-bg);
  color: var(--docku-text);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Inter", Roboto, "Helvetica Neue", Arial, sans-serif;
}

body { min-height: 100vh; }

a { color: var(--docku-link); }
a:hover { color: var(--docku-link-hover); }

/* ── 2. Buttons ────────────────────────────────────────────── */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  min-height: 38px;
  padding: 0.5rem 1rem;
  font-size: 0.92rem;
  font-weight: 600;
  line-height: 1.2;
  border-radius: var(--docku-radius);
  border: 1px solid transparent;
  cursor: pointer;
  text-decoration: none;
  user-select: none;
  white-space: nowrap;
  vertical-align: middle;
  margin-bottom: 0; /* override Pico [type=button]{margin-bottom:var(--pico-spacing)} */
  transition: background var(--docku-dur-fast) var(--docku-ease),
              border-color var(--docku-dur-fast) var(--docku-ease),
              color var(--docku-dur-fast) var(--docku-ease),
              box-shadow var(--docku-dur-fast) var(--docku-ease),
              transform var(--docku-dur-fast) var(--docku-ease);
  font-family: inherit;
}
.btn:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px var(--docku-primary-soft);
}
.btn:active { transform: translateY(1px); }
.btn[disabled], .btn.is-disabled {
  opacity: 0.55;
  cursor: not-allowed;
  transform: none;
}

.btn-primary {
  background: var(--docku-primary);
  color: #fff;
  border-color: var(--docku-primary);
  box-shadow: var(--docku-shadow-primary);
}
.btn-primary:hover:not([disabled]) {
  background: var(--docku-primary-dark);
  border-color: var(--docku-primary-dark);
  color: #fff;
}

.btn-secondary {
  background: var(--docku-surface);
  color: var(--docku-text);
  border-color: var(--docku-border);
}
.btn-secondary:hover:not([disabled]) {
  background: var(--docku-surface-raised);
  border-color: var(--docku-border-strong);
  color: var(--docku-text);
}

.btn-ghost {
  background: transparent;
  color: var(--docku-text-2);
  border-color: transparent;
}
.btn-ghost:hover:not([disabled]) {
  background: var(--docku-surface-raised);
  color: var(--docku-text);
}

.btn-danger {
  background: var(--docku-danger);
  color: #fff;
  border-color: var(--docku-danger);
}
.btn-danger:hover:not([disabled]) {
  background: #dc2626;
  border-color: #dc2626;
  color: #fff;
}

.btn-success {
  background: var(--docku-btn-success-bg);
  color: var(--docku-btn-success-fg);
  border-color: var(--docku-btn-success-bg);
}
.btn-success:hover:not([disabled]) {
  background: var(--docku-btn-success-hover);
  border-color: var(--docku-btn-success-hover);
  color: var(--docku-btn-success-fg);
}

.btn-outline {
  background: transparent;
  color: var(--docku-primary);
  border-color: var(--docku-primary-soft);
}
.btn-outline:hover:not([disabled]) {
  background: var(--docku-primary-50);
  border-color: var(--docku-primary);
  color: var(--docku-primary-dark);
}

.btn-icon {
  width: 38px;
  padding: 0;
  flex-shrink: 0;
}
.btn-sm { min-height: 32px; padding: 0.35rem 0.75rem; font-size: 0.85rem; }
.btn-lg { min-height: 44px; padding: 0.65rem 1.25rem; font-size: 1rem; }
.btn-block { width: 100%; }

@media (max-width: 640px) {
  /* WCAG 2.5.5 + Apple HIG: every interactive target must be at
     least 44×44 CSS pixels.  Apply a negative margin so the visible
     size of each button stays the same as on desktop (the hit
     area grows without the button itself growing). */
  .btn { min-height: 44px; padding: 0.6rem 1.1rem; }
  .btn-sm {
    min-height: 44px;
    /* Keep the visual height near 36px by offsetting 4px top/bottom. */
    margin: -4px 0;
    padding: 0.2rem 0.75rem;
  }
  .btn-icon {
    width: 44px;
    /* Keep the visible 38×38 size on phones by offsetting 3px on each
       side — the hit area grows to 44×44 without the icon button
       itself becoming oversized. */
    margin: -3px;
  }
}

/* ── 3. Inputs ─────────────────────────────────────────────── */
/* Keep checkboxes square.  Pico applies --pico-border-radius
   (10px here) to every input, which rounds an 18px checkbox into a
   near-circle and makes multi-select look like a single-choice list.
   Radios intentionally stay round; switch-style checkboxes keep their
   pill shape via Pico's more specific [role=switch] rule. */
input[type="checkbox"] {
  border-radius: 3px;
}
input[type="radio"] {
  border-radius: 50%;
}
.field {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  margin: 0;
}
.field-label {
  font-size: 0.8rem;
  font-weight: 600;
  text-transform: none;
  letter-spacing: 0.04em;
  color: var(--docku-text-muted);
}
.field-label .fa,
.field-label [class^="fa-"],
.field-label [class*=" fa-"] {
  margin-right: 0.35rem;
  color: var(--docku-text-muted);
}
.field-hint {
  font-size: 0.8rem;
  color: var(--docku-text-muted);
}
 .field-error {
  font-size: 0.8rem;
  color: var(--docku-danger);
}
/* Inline status note under a field (icon + message). */
.field-note {
  display: flex;
  align-items: center;
  gap: 0.3rem;
  margin-top: 0.3rem;
  font-size: 0.8rem;
}
.field-note.error { color: var(--docku-danger); }
.field-note.success { color: var(--docku-success); }

/* Text-size helpers (rem, not px, so they stay off the px-literal ratchet). */
.text-xs { font-size: 0.78rem; }
.text-sm { font-size: 0.85rem; }

/* Input with a leading icon (+ optional trailing action button).
   Shared by the login / reset-password pages and the users search.
   The wrapper is the positioning context; the icon never intercepts
   clicks and the suffix button is a ≥44px tap target (WCAG 2.5.5). */
.field-control {
  position: relative;
  display: flex;
  align-items: center;
  width: 100%;
}
.field-control .input {
  /* Room for the leading icon; keeps text clear of the glyph. */
  padding-left: 2.75rem;
}
.field-control.has-suffix .input {
  /* Room for the trailing action button (e.g. show/hide password). */
  padding-right: 3.1rem;
}
.field-icon {
  position: absolute;
  left: 0.9rem;
  top: 50%;
  transform: translateY(-50%);
  font-size: 0.95rem;
  color: var(--docku-text-faint);
  pointer-events: none;
  z-index: 1;
}
.field-suffix {
  position: absolute;
  right: 0.15rem;
  top: 50%;
  transform: translateY(-50%);
  width: 44px;
  height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: none;
  border: 0;
  border-radius: var(--docku-radius);
  color: var(--docku-text-muted);
  cursor: pointer;
  font-size: 0.95rem;
  z-index: 1;
}
.field-suffix:hover {
  background: var(--docku-primary-50);
  color: var(--docku-primary);
}
.field-suffix:focus-visible {
  outline: 2px solid var(--docku-primary);
  outline-offset: 1px;
}
/* Squeeze the icon in a little on phones so the visible input stays
   comfortable without the card feeling cramped. */
@media (max-width: 640px) {
  .field-control .input { padding-left: 2.6rem; }
  .field-icon { left: 0.75rem; }
}

/* Inline error block rendered when DOMPurify is unavailable.  Visible
   in DocumentView.js, Publications.js, PublicationView.js when the
   vendor script failed to load — we deliberately refuse to render raw
   marked output because that would be an XSS vector. */
.render-error {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.75rem;
  padding: 1rem 1.25rem;
  margin: 1rem 0;
  border: 1px solid var(--docku-danger, #c0392b);
  border-left: 4px solid var(--docku-danger, #c0392b);
  border-radius: 6px;
  background: rgba(192, 57, 43, 0.06);
  color: var(--docku-text);
  font-size: 0.95rem;
  line-height: 1.5;
}
.render-error strong { color: var(--docku-danger, #c0392b); }
.render-error .btn { margin-left: auto; }

.input, .select, .textarea {
  width: 100%;
  min-height: 40px;
  padding: 0.55rem 0.85rem;
  font-size: 0.95rem;
  font-family: inherit;
  color: var(--docku-text);
  background: var(--docku-surface);
  border: 1px solid var(--docku-border);
  border-radius: var(--docku-radius);
  transition: border-color var(--docku-dur-fast) var(--docku-ease),
              box-shadow var(--docku-dur-fast) var(--docku-ease);
  margin: 0;
}
.textarea { min-height: 96px; line-height: 1.5; resize: vertical; }
.input:focus, .select:focus, .textarea:focus {
  outline: none;
  border-color: var(--docku-primary);
  box-shadow: 0 0 0 3px var(--docku-primary-soft);
}
.input-lg, .select-lg, .textarea-lg {
  min-height: 48px;
  font-size: 1rem;
  padding: 0.7rem 1rem;
}
.input::placeholder, .textarea::placeholder { color: var(--docku-text-faint); }

@media (max-width: 640px) {
  .input, .select, .textarea { min-height: 44px; font-size: 16px; /* avoids iOS zoom */ }
  .input-lg, .select-lg { min-height: 50px; }
}

/* ── 4. Cards & sections ───────────────────────────────────── */
.card {
  background: var(--docku-surface);
  border: 1px solid var(--docku-border);
  border-radius: var(--docku-radius-lg);
  box-shadow: var(--docku-shadow-xs);
  padding: var(--docku-space-5);
}
.card.is-hoverable { transition: box-shadow var(--docku-dur) var(--docku-ease), transform var(--docku-dur) var(--docku-ease); }
.card.is-hoverable:hover { box-shadow: var(--docku-shadow); transform: translateY(-2px); }
.card-flush { padding: 0; }
.card-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--docku-space-3);
  padding: var(--docku-space-4) var(--docku-space-5);
  border-bottom: 1px solid var(--docku-border);
}
.card-header h2, .card-header h3 { margin: 0; font-size: 1.05rem; font-weight: 600; }
.card-body { padding: var(--docku-space-5); }
.card-footer {
  padding: var(--docku-space-3) var(--docku-space-5);
  border-top: 1px solid var(--docku-border);
  background: var(--docku-surface-raised);
  border-radius: 0 0 var(--docku-radius-lg) var(--docku-radius-lg);
}

.form-section {
  background: var(--docku-surface);
  border: 1px solid var(--docku-border);
  border-left: 3px solid var(--docku-primary);
  border-radius: var(--docku-radius-lg);
  box-shadow: var(--docku-shadow-xs);
  padding: var(--docku-space-5);
  margin-bottom: var(--docku-space-5);
}
.form-section-title {
  display: flex;
  align-items: center;
  gap: var(--docku-space-2);
  font-size: 0.78rem;
  font-weight: 700;
  text-transform: none;
  letter-spacing: 0.06em;
  color: var(--docku-primary);
  margin: 0 0 var(--docku-space-4);
}
.form-section-title .fa { font-size: 0.95rem; }
.form-section-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--docku-space-4) var(--docku-space-5);
}
.form-section-grid > .span-2 { grid-column: span 2; }
@media (max-width: 768px) {
  .form-section-grid { grid-template-columns: 1fr; }
  .form-section-grid > .span-2 { grid-column: span 1; }
}
/* `.form-section-wide` has no layout rule of its own, so a `field-label`
   span and its `<small>` hint sit inline and collapse together (Vue
   condenses inter-element whitespace). Forcing the hint onto its own
   line keeps them separated. */
.form-section-wide > small {
  display: block;
  margin-top: var(--docku-space-1);
}

/* ── 5. Layout shell ───────────────────────────────────────── */
.app-shell {
  display: grid;
  grid-template-columns: var(--docku-sidebar-w) 1fr;
  grid-template-rows: var(--docku-topbar-h) 1fr;
  grid-template-areas:
    "topbar  topbar"
    "sidebar main";
  min-height: 100vh;
}

/* When there's no authed user (guests on the landing / public pages),
   drop the sidebar column entirely so .app-main spans the viewport. */
.app-shell.no-sidebar {
  grid-template-columns: 1fr;
  grid-template-areas:
    "topbar"
    "main";
  justify-items: stretch;
}

/* Topbar */
.app-topbar {
  grid-area: topbar;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 var(--docku-space-5);
  background: var(--docku-surface);
  border-bottom: 1px solid var(--docku-border);
  position: sticky;
  top: 0;
  z-index: 30;
  height: var(--docku-topbar-h);
  backdrop-filter: saturate(180%) blur(8px);
}
.app-topbar-left, .app-topbar-right {
  display: flex;
  align-items: center;
  gap: var(--docku-space-3);
}

.app-brand {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  color: var(--docku-text);
  text-decoration: none;
  font-weight: 700;
  font-size: 1.05rem;
  letter-spacing: -0.01em;
  padding: 0.3rem 0.5rem;
  margin: -0.3rem -0.5rem;
  border-radius: var(--docku-radius);
  transition: background var(--docku-dur-fast) var(--docku-ease);
}
.app-brand:hover, .app-brand:focus-visible {
  background: var(--docku-surface-raised);
  outline: none;
  color: var(--docku-text);
}
.app-brand:focus-visible {
  box-shadow: 0 0 0 3px var(--docku-primary-soft);
}
.app-brand-logo {
  width: 30px;
  height: 30px;
  border-radius: 7px;
  background: linear-gradient(135deg, var(--docku-primary) 0%, var(--docku-primary-dark) 100%);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: #fff;
  font-size: 0.95rem;
  box-shadow: var(--docku-shadow-primary);
  flex-shrink: 0;
}
.app-brand-name { line-height: 1; }

.app-topbar-nav {
  display: flex;
  align-items: center;
  gap: var(--docku-space-1);
  margin-left: var(--docku-space-6);
}
.app-topbar-nav a {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.5rem 0.85rem;
  font-size: 0.9rem;
  font-weight: 500;
  color: var(--docku-text-muted);
  text-decoration: none;
  border-radius: var(--docku-radius);
  transition: background var(--docku-dur-fast) var(--docku-ease), color var(--docku-dur-fast) var(--docku-ease);
}
.app-topbar-nav a:hover {
  background: var(--docku-surface-raised);
  color: var(--docku-text);
}
.app-topbar-nav a.router-link-active {
  background: var(--docku-primary-50);
  color: var(--docku-link);
}
/* The active pill sits on `--docku-primary-50`, which dark turns into a navy
   (#0f1f3d).  Even the lifting `--docku-link` (#3b82f6) only reaches 4.4:1
   there, so the pill takes the soft tint — same treatment as the guest
   footer's links on its navy band. */
[data-theme="dark"] .app-topbar-nav a.router-link-active {
  color: var(--docku-primary-soft);
}

.icon-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  padding: 0;
  border: 1px solid var(--docku-border);
  background: var(--docku-surface);
  color: var(--docku-text-2);
  border-radius: var(--docku-radius);
  cursor: pointer;
  font-family: inherit;
  transition: background var(--docku-dur-fast) var(--docku-ease),
              border-color var(--docku-dur-fast) var(--docku-ease),
              color var(--docku-dur-fast) var(--docku-ease);
}
@media (max-width: 640px) {
  /* Bump hit area to 44×44 while keeping the visible icon 38×38 via
     a 3px negative margin on each axis. */
  .icon-btn {
    width: 44px;
    height: 44px;
    margin: -3px;
  }
}
.icon-btn:hover {
  background: var(--docku-surface-raised);
  border-color: var(--docku-border-strong);
  color: var(--docku-text);
}
.icon-btn:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px var(--docku-primary-soft);
  border-color: var(--docku-primary);
}

.hamburger { display: none; }

.user-menu-btn {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.3rem 0.6rem 0.3rem 0.35rem;
  background: transparent;
  border: 1px solid transparent;
  border-radius: var(--docku-radius-full);
  cursor: pointer;
  font-family: inherit;
  transition: background var(--docku-dur-fast) var(--docku-ease),
              border-color var(--docku-dur-fast) var(--docku-ease);
}
.user-menu-btn:hover {
  background: var(--docku-surface-raised);
  border-color: var(--docku-border);
}
.user-menu-btn .user-menu-name {
  font-size: 0.88rem;
  font-weight: 600;
  color: var(--docku-text);
  text-align: left;
  line-height: 1.1;
}
.user-menu-btn .user-menu-role {
  font-size: 0.7rem;
  color: var(--docku-text-muted);
  text-transform: none;
  letter-spacing: 0.05em;
  line-height: 1.1;
}
.user-menu-btn .user-menu-info { display: flex; flex-direction: column; align-items: flex-start; }
.user-menu-chevron {
  font-size: 0.7rem;
  color: var(--docku-text-muted);
  transition: transform var(--docku-dur-fast) var(--docku-ease);
}
.user-menu-btn.is-open {
  background: var(--docku-surface-raised);
  border-color: var(--docku-border);
}
.user-menu-btn.is-open .user-menu-chevron {
  transform: rotate(180deg);
}

body.user-menu-open { overflow: hidden; }
body.mobile-nav-open { overflow: hidden; }

.user-menu-overlay {
  position: fixed;
  inset: 0;
  z-index: 80;
  display: flex;
  justify-content: flex-end;
  align-items: flex-start;
  padding: calc(var(--docku-topbar-h) + 8px) var(--docku-space-4) 0 0;
  background: transparent;
}
.user-menu-popover {
  width: 260px;
  max-width: calc(100vw - 2rem);
  background: var(--docku-surface);
  border: 1px solid var(--docku-border);
  border-radius: var(--docku-radius-lg);
  box-shadow: var(--docku-shadow-lg);
  padding: var(--docku-space-2);
  animation: user-menu-pop-in 0.18s var(--docku-ease);
}
@keyframes user-menu-pop-in {
  from { transform: translateY(-6px) scale(0.98); opacity: 0; }
  to   { transform: translateY(0) scale(1); opacity: 1; }
}
.user-menu-handle { display: none; }
.user-menu-header {
  display: flex;
  align-items: center;
  gap: var(--docku-space-3);
  padding: var(--docku-space-3);
  margin-bottom: var(--docku-space-1);
  border-bottom: 1px solid var(--docku-border);
}
.user-menu-header-text {
  display: flex;
  flex-direction: column;
  min-width: 0;
  gap: 0.15rem;
}
.user-menu-header-name {
  font-size: 0.95rem;
  font-weight: 650;
  color: var(--docku-text);
  line-height: 1.2;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.user-menu-header-role {
  display: inline-flex;
  align-self: flex-start;
  padding: 0.1rem 0.5rem;
  border-radius: var(--docku-radius-full);
  background: var(--docku-primary-50);
  color: var(--docku-primary);
  font-size: 0.7rem;
  font-weight: 650;
  letter-spacing: 0.02em;
  text-transform: capitalize;
}
.user-menu-list {
  display: flex;
  flex-direction: column;
  padding: var(--docku-space-1) 0;
}
.user-menu-sep {
  height: 1px;
  margin: var(--docku-space-1) var(--docku-space-2);
  background: var(--docku-border);
}
.user-menu-popover .user-menu-item {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  width: 100%;
  margin: 0;
  padding: 0.65rem 0.75rem;
  min-height: 40px;
  border: none;
  border-radius: var(--docku-radius);
  background: transparent;
  color: var(--docku-text);
  text-decoration: none;
  font-family: inherit;
  font-size: 0.92rem;
  font-weight: 500;
  text-align: left;
  line-height: 1.2;
  cursor: pointer;
  box-shadow: none;
}
.user-menu-popover .user-menu-item > i,
.user-menu-popover .user-menu-item > .fa {
  width: 1.15rem;
  text-align: center;
  color: var(--docku-text-muted);
  font-size: 0.95rem;
}
.user-menu-popover .user-menu-item:hover,
.user-menu-popover .user-menu-item:focus-visible {
  background: var(--docku-surface-raised);
  color: var(--docku-text);
  outline: none;
}
.user-menu-popover .user-menu-item:focus-visible {
  box-shadow: inset 0 0 0 3px var(--docku-primary-soft);
}
.user-menu-popover .user-menu-item:hover > i,
.user-menu-popover .user-menu-item:hover > .fa,
.user-menu-popover .user-menu-item:focus-visible > i,
.user-menu-popover .user-menu-item:focus-visible > .fa {
  color: var(--docku-primary);
}
.user-menu-popover .user-menu-item-danger {
  color: var(--docku-danger-text);
}
.user-menu-popover .user-menu-item-danger > i,
.user-menu-popover .user-menu-item-danger > .fa {
  color: var(--docku-danger);
}
.user-menu-popover .user-menu-item-danger:hover,
.user-menu-popover .user-menu-item-danger:focus-visible {
  background: var(--docku-danger-soft);
  color: var(--docku-danger-text);
}

@media (max-width: 768px) {
  .user-menu-overlay {
    align-items: flex-end;
    justify-content: center;
    padding: 0;
    background: rgba(15, 23, 42, 0.5);
    backdrop-filter: blur(2px);
    animation: action-sheet-fade 0.18s ease-out;
  }
  .user-menu-popover {
    width: 100%;
    max-width: 100%;
    border-radius: 1.25rem 1.25rem 0 0;
    border: none;
    box-shadow: 0 -8px 24px rgba(15, 23, 42, 0.18);
    padding: var(--docku-space-2) var(--docku-space-2) max(var(--docku-space-6), env(safe-area-inset-bottom));
    animation: action-sheet-slide-up 0.26s var(--docku-ease-out);
  }
  .user-menu-handle {
    display: block;
    width: 40px;
    height: 5px;
    background: var(--docku-border-strong);
    border-radius: var(--docku-radius-full);
    margin: 0.4rem auto 0.5rem;
  }
  .user-menu-header {
    padding: var(--docku-space-3) var(--docku-space-4);
  }
  .user-menu-popover .user-menu-item {
    min-height: 54px;
    padding: 0.9rem 1rem;
    font-size: 1rem;
  }
}

/* Sidebar */
.app-sidebar {
  grid-area: sidebar;
  background: var(--docku-surface);
  border-right: 1px solid var(--docku-border);
  padding: var(--docku-space-5) var(--docku-space-3);
  overflow-y: auto;
  position: sticky;
  top: var(--docku-topbar-h);
  height: calc(100vh - var(--docku-topbar-h));
}
.app-sidebar-section {
  margin-bottom: var(--docku-space-5);
}
.app-sidebar-label {
  font-size: 0.7rem;
  font-weight: 700;
  text-transform: none;
  letter-spacing: 0.08em;
  color: var(--docku-text-faint);
  padding: 0 var(--docku-space-3);
  margin-bottom: var(--docku-space-2);
}
.app-sidebar nav ul { list-style: none; padding: 0; margin: 0; }
.app-sidebar nav a {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  padding: 0.6rem var(--docku-space-3);
  margin: 0.1rem 0;
  font-size: 0.92rem;
  font-weight: 500;
  color: var(--docku-text-2);
  text-decoration: none;
  border-radius: var(--docku-radius);
  transition: background var(--docku-dur-fast) var(--docku-ease),
              color var(--docku-dur-fast) var(--docku-ease);
}
.app-sidebar nav a .fa {
  width: 18px;
  text-align: center;
  font-size: 0.95rem;
  color: var(--docku-text-faint);
  transition: color var(--docku-dur-fast) var(--docku-ease);
}
.app-sidebar nav a:hover {
  background: var(--docku-surface-raised);
  color: var(--docku-text);
}
.app-sidebar nav a:hover .fa { color: var(--docku-text-2); }
.app-sidebar nav a.active {
  background: var(--docku-primary);
  color: #fff;
  box-shadow: var(--docku-shadow-primary);
}
.app-sidebar nav a.active .fa { color: #fff; }
.app-sidebar nav a .sidebar-count {
  margin-left: auto;
  background: var(--docku-surface-raised);
  color: var(--docku-text-muted);
  font-size: 0.72rem;
  font-weight: 700;
  padding: 0.1rem 0.45rem;
  border-radius: var(--docku-radius-full);
  min-width: 1.4rem;
  text-align: center;
}
.app-sidebar nav a.active .sidebar-count {
  background: rgba(255, 255, 255, 0.22);
  color: #fff;
}

/* Main content — full-bleed (CSS-014): the old 1280px `--docku-content-max`
   cap left grey rails on wide desktops, so the content now fills its grid
   track edge-to-edge.  `--docku-content-max` is still used by the landing
   band inner (`.home-band-inner`) to keep that marketing column readable. */
.app-main {
  grid-area: main;
  padding: var(--docku-space-6) var(--docku-space-6) var(--docku-space-10);
  width: 100%;
  min-width: 0;
}

/* When the shell collapses to a single column (no sidebar), the .app-main
   grid track becomes the full viewport, so we don't need its own
   re-centering rule. The block-level layout below handles any
   long-content case where .app-main is taller than the viewport. */
.app-shell.no-sidebar .app-main {
  justify-self: center;
}

/* Page header */
.page-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--docku-space-4);
  margin-bottom: var(--docku-space-5);
  flex-wrap: wrap;
}
.page-header h1 {
  margin: 0;
  font-size: 1.6rem;
  font-weight: 700;
  letter-spacing: -0.015em;
  color: var(--docku-text);
}
.page-header .page-subtitle {
  margin: 0.25rem 0 0;
  color: var(--docku-text-muted);
  font-size: 0.95rem;
}
.page-header-actions {
  display: flex;
  align-items: center;
  gap: var(--docku-space-2);
  flex-wrap: wrap;
}
/* ActionMenu's root span is inline-flex by default, which can misalign it
   with bare <button> flex items in the header due to inline formatting
   baseline quirks. Keep it inline-flex inside the header so the wrapper
   sizes to its content (no extra vertical space from Vue teleport
   comment nodes), and pin it to the middle of the flex line. */
.page-header-actions .action-menu-wrap {
  display: inline-flex;
  vertical-align: middle;
  align-items: center;
}

/* Page-header breadcrumb (in-page context: Parent > Child). */
.page-breadcrumb {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--docku-space-2);
  margin: 0 0 var(--docku-space-2);
  font-size: 0.85rem;
  color: var(--docku-text-muted);
}
.page-breadcrumb a {
  color: var(--docku-text-muted);
  text-decoration: none;
  font-weight: 500;
  transition: color var(--docku-dur-fast) var(--docku-ease);
}
.page-breadcrumb a:hover { color: var(--docku-primary); }
.page-breadcrumb-sep { color: var(--docku-text-faint); }

/* ── 6. Avatars ────────────────────────────────────────────── */
.avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  border-radius: 50%;
  background: var(--docku-primary);
  color: #fff;
  font-size: 0.82rem;
  font-weight: 700;
  text-transform: none;
  flex-shrink: 0;
  user-select: none;
  letter-spacing: 0.02em;
}
.avatar-sm { width: 28px; height: 28px; font-size: 0.7rem; }
.avatar-lg { width: 48px; height: 48px; font-size: 1rem; }
.avatar-xl { width: 72px; height: 72px; font-size: 1.5rem; }
.avatar-color-1 { background: linear-gradient(135deg, #6366f1, #4f46e5); }
.avatar-color-2 { background: linear-gradient(135deg, #ec4899, #db2777); }
.avatar-color-3 { background: linear-gradient(135deg, #14b8a6, #0d9488); }
.avatar-color-4 { background: linear-gradient(135deg, #f59e0b, #d97706); }
.avatar-color-5 { background: linear-gradient(135deg, #8b5cf6, #7c3aed); }
.avatar-color-6 { background: linear-gradient(135deg, #ef4444, #dc2626); }
.avatar-color-7 { background: linear-gradient(135deg, #06b6d4, #0891b2); }
.avatar-color-8 { background: linear-gradient(135deg, #84cc16, #65a30d); }

.avatar-stack {
  display: inline-flex;
  align-items: center;
}
.avatar-stack .avatar {
  border: 2px solid var(--docku-surface);
  margin-left: -8px;
}
.avatar-stack .avatar:first-child { margin-left: 0; }
.avatar-stack-more {
  background: var(--docku-surface-raised);
  color: var(--docku-text-2);
  border: 2px solid var(--docku-surface);
  margin-left: -8px;
  font-size: 0.72rem;
}

/* ── User profile hero / stats / attributes ───────────────── */
.user-profile-hero {
  overflow: hidden;
  margin-bottom: var(--docku-space-5);
}
.user-profile-hero-inner {
  display: flex;
  align-items: center;
  gap: var(--docku-space-5);
  padding: var(--docku-space-5) var(--docku-space-6);
  background:
    radial-gradient(circle at top right, var(--docku-primary-50, #eff6ff) 0%, transparent 60%),
    var(--docku-surface);
}
.user-profile-hero-text { min-width: 0; flex: 1; }
.user-profile-hero-text h2 {
  margin: 0 0 .25rem 0;
  font-size: 1.4rem;
  font-weight: 700;
  color: var(--docku-text);
  word-break: break-word;
}
.user-profile-hero-sub {
  margin: 0 0 .65rem 0;
  color: var(--docku-text-muted);
  font-size: .92rem;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .35rem;
}
.user-profile-hero-sub code {
  font-size: .82rem;
  color: var(--docku-text-2);
  background: var(--docku-surface-raised);
  padding: 1px 6px;
  border-radius: 4px;
}
.user-profile-hero-pills {
  display: flex;
  flex-wrap: wrap;
  gap: .35rem;
}
.docs-view-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--docku-space-2);
  margin: 0;
}
.docs-view-meta-sep { color: var(--docku-text-muted); }

.user-profile-stats {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  margin-bottom: var(--docku-space-5);
}
.user-profile-stat {
  padding: var(--docku-space-4) var(--docku-space-5);
  border-right: 1px solid var(--docku-border);
}
.user-profile-stat:last-child { border-right: none; }
.user-profile-stat-label {
  font-size: .72rem;
  text-transform: none;
  letter-spacing: .06em;
  color: var(--docku-text-muted);
  font-weight: 600;
  margin-bottom: .25rem;
}
.user-profile-stat-value {
  font-size: .95rem;
  color: var(--docku-text);
  font-weight: 500;
  word-break: break-word;
}
@media (max-width: 768px) {
  .user-profile-hero-inner { flex-direction: column; align-items: flex-start; padding: var(--docku-space-4); }
  .user-profile-stats { grid-template-columns: 1fr 1fr; }
  .user-profile-stat { border-right: none; border-bottom: 1px solid var(--docku-border); }
  .user-profile-stat:nth-last-child(-n+2) { border-bottom: none; }
}

.user-profile-attrs {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--docku-space-3) var(--docku-space-5);
}
.user-profile-attr-label {
  font-size: .72rem;
  text-transform: none;
  letter-spacing: .06em;
  color: var(--docku-text-muted);
  font-weight: 600;
  margin-bottom: .15rem;
}
.user-profile-attr-value {
  font-size: .92rem;
  color: var(--docku-text);
  word-break: break-word;
}
@media (max-width: 768px) {
  .user-profile-attrs { grid-template-columns: 1fr; }
}

/* ── 7. Status pills & badges ──────────────────────────────── */
.status-pill {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.2rem 0.65rem;
  border-radius: var(--docku-radius-full);
  font-size: 0.74rem;
  font-weight: 700;
  text-transform: none;
  letter-spacing: 0.05em;
  background: var(--docku-surface-raised);
  color: var(--docku-text-2);
  white-space: nowrap;
}
.status-pill::before {
  content: "";
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: currentColor;
  opacity: 0.65;
}
.status-pill.draft    { background: #f1f5f9; color: #475569; }
.status-pill.editing  { background: var(--docku-warning-soft); color: var(--docku-warning-text); }
.status-pill.review   { background: var(--docku-info-soft); color: var(--docku-info-text); }
.status-pill.active   { background: var(--docku-success-soft); color: var(--docku-success-text); }
.status-pill.archived { background: #e5e7eb; color: #374151; }

.role-pill {
  display: inline-flex;
  align-items: center;
  padding: 0.15rem 0.55rem;
  border-radius: var(--docku-radius-sm);
  font-size: 0.72rem;
  font-weight: 700;
  text-transform: none;
  letter-spacing: 0.04em;
  background: var(--docku-primary-50);
  color: var(--docku-primary-dark);
}
.role-pill.role-admin  { background: #fef3c7; color: #92400e; }
.role-pill.role-editor { background: var(--docku-primary-50); color: var(--docku-primary-dark); }
.role-pill.role-viewer { background: var(--docku-surface-raised); color: var(--docku-text-muted); }

.kind-pill {
  display: inline-block;
  padding: 0.1rem 0.5rem;
  border-radius: var(--docku-radius-sm);
  font-size: 0.7rem;
  font-weight: 700;
  text-transform: none;
  letter-spacing: 0.04em;
  background: var(--docku-surface-raised);
  color: var(--docku-text-2);
}
.kind-pill.type-markdown { background: var(--docku-primary-50); color: var(--docku-primary-dark); }
.kind-pill.type-file     { background: #fef3c7; color: #92400e; }
.kind-pill.type-link     { background: #d1fae5; color: #065f46; }

.badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 20px;
  height: 20px;
  padding: 0 0.4rem;
  border-radius: var(--docku-radius-full);
  background: var(--docku-danger);
  color: #fff;
  font-size: 0.7rem;
  font-weight: 700;
  line-height: 1;
}

/* ── 8. Stat cards (dashboard) ─────────────────────────────── */
.stat-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: var(--docku-space-4);
  margin-bottom: var(--docku-space-5);
}
.stat-card {
  display: flex;
  align-items: center;
  gap: var(--docku-space-4);
  background: var(--docku-surface);
  border: 1px solid var(--docku-border);
  border-radius: var(--docku-radius-lg);
  padding: var(--docku-space-5);
  box-shadow: var(--docku-shadow-xs);
  transition: box-shadow var(--docku-dur) var(--docku-ease), transform var(--docku-dur) var(--docku-ease);
}
.stat-card:hover { box-shadow: var(--docku-shadow); transform: translateY(-2px); }
/* Informational stat card (not a link) — suppress the interactive hover
   lift and shrink the value so a status word fits the card (APP-004). */
.stat-card.static { transition: none; }
.stat-card.static:hover { box-shadow: var(--docku-shadow-xs); transform: none; }
.stat-card.static .stat-card-value { font-size: 1.05rem; }
.stat-card-icon {
  width: 52px;
  height: 52px;
  border-radius: var(--docku-radius);
  background: var(--docku-primary-50);
  color: var(--docku-primary);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 1.25rem;
  flex-shrink: 0;
}
.stat-card-icon.success { background: var(--docku-success-soft); color: var(--docku-success); }
.stat-card-icon.warning { background: var(--docku-warning-soft); color: var(--docku-warning); }
.stat-card-icon.danger  { background: var(--docku-danger-soft);  color: var(--docku-danger); }
.stat-card-icon.info    { background: var(--docku-info-soft);    color: var(--docku-info); }
.stat-card-body { min-width: 0; flex: 1; }
.stat-card-value {
  font-size: 1.6rem;
  font-weight: 700;
  color: var(--docku-text);
  line-height: 1.1;
  letter-spacing: -0.02em;
}
.stat-card-label {
  font-size: 0.82rem;
  color: var(--docku-text-muted);
  text-transform: none;
  letter-spacing: 0.04em;
  font-weight: 600;
  margin-top: 0.2rem;
}
.stat-card-trend {
  font-size: 0.78rem;
  color: var(--docku-text-muted);
  margin-top: 0.15rem;
}
.stat-card-trend.up   { color: var(--docku-success); }
.stat-card-trend.down { color: var(--docku-danger); }

/* Clickable variant — used when the card itself is a RouterLink.
   Resets the default <a> styling so the card keeps its visual layout
   while still being clearly interactive. */
a.stat-card-link,
.stat-card-link {
  color: inherit;
  text-decoration: none;
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: var(--docku-space-4);
  position: relative;
}
a.stat-card-link:hover,
.stat-card-link:hover {
  box-shadow: var(--docku-shadow);
  transform: translateY(-2px);
  border-color: var(--docku-primary-200, var(--docku-border));
}
a.stat-card-link:focus-visible,
.stat-card-link:focus-visible {
  outline: 2px solid var(--docku-primary);
  outline-offset: 2px;
}
.stat-card-cta {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  margin-top: 0.45rem;
  font-size: 0.78rem;
  font-weight: 600;
  color: var(--docku-primary);
  opacity: 0;
  transform: translateX(-4px);
  transition: opacity var(--docku-dur) var(--docku-ease), transform var(--docku-dur) var(--docku-ease);
}
.stat-card-link:hover .stat-card-cta,
.stat-card-link:focus-visible .stat-card-cta {
  opacity: 1;
  transform: translateX(0);
}
.stat-card-cta i { font-size: 0.72rem; }

/* ── 9. Tables (modernized) ───────────────────────────────── */
.table-wrap {
  background: var(--docku-surface);
  border: 1px solid var(--docku-border);
  border-radius: var(--docku-radius-lg);
  box-shadow: var(--docku-shadow-xs);
  overflow: hidden;
}
.table-scroll {
  width: 100%;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}
/* Top scrollbar mirror — a second horizontally scrollable track that
   sits directly above the table and stays in lockstep with the
   bottom one. Uses the same `overflow-x: auto` so the native
   scrollbar appears only when the table is wider than the viewport,
   matching the behavior of `.table-scroll` exactly. The inner spacer
   is JS-sized to the table's `scrollWidth` via
   `DocumentList.updateTableScrollWidth()`. */
.table-scroll-top {
  width: 100%;
  overflow-x: auto;
  overflow-y: hidden;
  -webkit-overflow-scrolling: touch;
}
.table-scroll-top-inner {
  height: 1px;
}
.table-footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--docku-space-3);
  padding: var(--docku-space-3) var(--docku-space-4);
  flex-wrap: wrap;
}
/* ── Pagination ───────────────────────────────────────────────────────
   Page navigation for the server-paged catalogue.  The step buttons and the
   page numbers are ordinary `.btn`s, so they inherit one control contract
   (hover/active/focus ring, disabled dimming, the 44px mobile target) rather
   than re-implementing it.  Only two things are pager-specific: the numbers
   are kept square-ish so the row does not shift as pages are added, and the
   active page is tinted — the same primary tint the sorted column header
   uses — instead of a solid fill, so no colour literal is added and the
   position is carried by `aria-current="page"` rather than by colour alone.
   The `:hover` half of the current-page rule is needed to out-specify
   `.btn-secondary:hover:not([disabled])`. */
.pagination {
  display: flex;
  align-items: center;
  gap: var(--docku-space-2);
  flex-wrap: wrap;
}
.pagination-pages {
  display: flex;
  align-items: center;
  gap: var(--docku-space-1);
  margin: 0;
  padding: 0;
  list-style: none;
}
.pagination-page {
  min-width: 2rem;
  padding-inline: 0.5rem;
}
.pagination-page.is-current,
.pagination-page.is-current:hover:not([disabled]) {
  background: var(--docku-primary-100);
  border-color: var(--docku-primary);
  color: var(--docku-primary-dark);
}
.pagination-gap {
  padding: 0 var(--docku-space-1);
  color: var(--docku-text-faint);
}
.data-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.88rem;
  /* Force the table to be at least as wide as its widest column so
     the wrapper can scroll horizontally on narrow viewports rather
     than squashing cells into illegibility.  Bumped to 1400px once
     the list grew to 13 columns (Doc ID / Title / Category /
     Department / Status / Confidentiality / Owner / Approved by /
     Created / Updated / Type / Tags / Actions). */
  min-width: 1400px;
}
/* Micro-label header style: uppercase, tighter and letter-spaced, with a
   stronger bottom rule so the header reads as a distinct band above the
   body.  Sortable columns wrap their label in an <a>; the active
   column is tinted brand-primary. */
.data-table thead th {
  text-align: left;
  font-size: 0.7rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--docku-text-muted);
  padding: var(--docku-space-3) var(--docku-space-4);
  background: var(--docku-surface-raised);
  border-bottom: 1px solid var(--docku-border-strong);
  white-space: nowrap;
}
.data-table thead th a {
  color: inherit;
  text-decoration: none;
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
}
.data-table thead th a:hover { color: var(--docku-text); }
/* Active sort column: tinted cell + strong text.  Deliberately not
   --docku-primary text — it is an invariant token and reads 3.03:1 on the
   dark header surface (below AA). */
.data-table thead th.is-sorted {
  color: var(--docku-text);
  background: var(--docku-primary-50);
}
.data-table tbody td {
  padding: var(--docku-space-3) var(--docku-space-4);
  border-bottom: 1px solid var(--docku-border);
  vertical-align: middle;
}
.data-table tbody tr {
  transition: background var(--docku-dur-fast) var(--docku-ease);
}
/* Hover is a pointer-only affordance: on a touch screen a tap would
   otherwise leave the row stuck in its hover state. */
@media (hover: hover) {
  .data-table tbody tr:hover {
    background: var(--docku-row-hover-bg);
  }
}
/* A calm action rail — desktop table only (≥769px).  Below that the table
   becomes a card stack.  Every row shares ONE background: there is
   deliberately no zebra striping (removed 2026-09-28), so rows are told
   apart by the 1px cell borders, the hover tint and the accent bar. */
@media (min-width: 769px) {
  /* Give every desktop row an explicit surface so the sticky action rail
     can `inherit` it — a transparent rail would let the horizontally-
     scrolled cells show through it. */
  .data-table tbody tr {
    background-color: var(--docku-surface);
  }
  /* The rail tracks whatever its row is showing (base / hover) instead of a
     fixed heavy sunken tint. */
  .data-table tbody td.col-actions {
    background-color: inherit;
  }
  /* Left accent bar: an inset shadow on the first cell paints without
     shifting any content.  Only interactive rows get it (a static table
     should not flash an accent); the expanded row keeps it so you can
     always see which row owns the open detail panel. */
  .data-table tbody tr.is-clickable:hover > td:first-child,
  .data-table tbody tr.is-clickable:focus-within > td:first-child,
  .publications-page .data-table tbody tr.pub-row:hover > td:first-child,
  .publications-page .data-table tbody tr.pub-row:focus-within > td:first-child,
  .data-table tbody tr.is-expanded > td:first-child,
  .publications-page .data-table tbody tr.pub-row.is-expanded > td:first-child {
    box-shadow: inset 3px 0 0 var(--docku-row-accent);
  }
}
/* Document version tag shown beside a title in the publications table.
   Inline, but separated from the title text. */
.table-doc-id {
  display: inline-block;
  margin-left: var(--docku-space-2);
  white-space: nowrap;
}
/* Date columns read best on one line — "Jan 15, 2026" wrapping to two
   lines in a narrow column looks like a bug. */
.data-table .col-date { white-space: nowrap; }
/* Inline code chips (Policy ID, …) shouldn't break mid-token: hyphenated
   ids wrapped to three lines in the narrow first column. */
.data-table tbody td code { white-space: nowrap; }
/* Publications title cell.  Without a floor the column collapses to a
   sliver (the clamped description and the nowrap id/date cells give the
   browser no reason to keep it wide) and titles wrap to three lines
   while the description truncates to one.  16rem keeps titles on one
   line and the description at its full two-line clamp; the tail columns
   scroll horizontally as they already did. */
.data-table .col-title { min-width: 16rem; }
/* Publications row description (the full text is in the expanded detail
   row): clamp to two lines so a long one can't inflate the row to ~300px,
   which also pushed each row's borders far apart. */
.table-doc-desc {
  margin: 0.2rem 0 0;
  font-size: 0.85rem;
  color: var(--docku-text-muted);
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  overflow: hidden;
}
.data-table tbody tr:last-child td { border-bottom: none; }
.data-table tbody tr.is-clickable { cursor: pointer; }
.data-table .col-actions {
  width: 56px;
  min-width: 56px;
  text-align: right;
  white-space: nowrap;
}
.data-table .text-muted { color: var(--docku-text-muted); }
.data-table .text-ellipsis {
  max-width: 280px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  display: inline-block;
  vertical-align: middle;
}

/* Sticky action column */
table.docs-table th.col-actions,
table.docs-table td.col-actions,
.data-table th.col-actions,
.data-table td.col-actions {
  position: sticky;
  right: 0;
  background: var(--docku-surface);
  z-index: 2;
  /* Hairline separator only.  The old `-4px 0 8px -4px` drop shadow read
     as a detached grey slab bolted onto the right edge of every row. */
  border-left: 1px solid var(--docku-border);
}
table.docs-table thead th.col-actions,
.data-table thead th.col-actions { background: var(--docku-surface-sunken); }
/* Muted, matching the other micro-labels: the primary tint read 3.03:1 on
   the dark header rail (below AA). */
.data-table thead th.col-actions { color: var(--docku-text-muted); }
/* (Body action rail is set to `background-color: inherit` in the ≥769px
   block above so it tracks the row's own hover state.) */

.scroll-hint {
  display: none;
  font-size: 0.8rem;
  color: var(--docku-text-muted);
  margin: 0 0 var(--docku-space-2);
  text-align: right;
}
/* Rendered by Publications.js only while the table actually overflows and
   has not been scrolled yet; it clears out of the way after the first
   scroll.  Flex rather than a literal space (PUB-015): adjacent inline
   nodes render jammed — "↔Scroll for more →" — which read as one run of
   arrows rather than an icon plus a sentence. */
.scroll-hint.is-visible {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--docku-space-2);
}
@media (max-width: 768px) {
  /* Below the breakpoint the table is a card stack — nothing scrolls. */
  .scroll-hint { display: none !important; }
}
@media (max-width: 640px) {
  .data-table { font-size: 0.86rem; }
  .data-table thead th, .data-table tbody td {
    padding: 0.6rem 0.7rem;
  }
}

/* ── Card-stack mobile fallback for .data-table ──────────────────
   At <768px the 13-column docs table becomes unusable even with
   horizontal scroll (sticky action column helps, but body content
   like "Owner" / "Approved by" / "Created" becomes unreadable at
   200px wide).  This rule turns every row into a stacked card and
   pulls the column label from the data-label attribute the JS
   helper copies onto each <td>.  Toggling happens entirely via
   CSS so it degrades gracefully if JS fails. */
@media (max-width: 768px) {
  .table-scroll-top { display: none; }
  /* PUB-015: card mode releases both bounded table windows so the stack
     scrolls with the page.  The bounded box left a phone showing about one
     card behind a nested scrollbar (~500px of box under a 300-350px card).
     Scoped through `.table-wrap` so it outranks the per-page cap rules
     further down the sheet (they deliberately sit next to their tables), and
     named per page so the version-history table keeps its own window. */
  .publications-page .table-wrap .table-scroll,
  .docs-list-page .table-wrap .table-scroll { max-height: none; }
  /* …and the stack must not inherit the twelve-column table's 1400px floor.
     With it every "card" was 1400px wide on a 390px phone — labels pinned
     hard left with their values off-screen — and expanding a catalogue row
     spilled 1027px of empty page.  Card mode is a stack: a card is as wide
     as the viewport, by definition. */
  .data-table { min-width: auto; }
  .data-table thead {
    position: absolute;
    left: -9999px;
    top: -9999px;
  }
  .data-table, .data-table tbody, .data-table tr, .data-table td {
    display: block;
    width: 100%;
  }
  .data-table tr {
    background: var(--docku-surface);
    border: 1px solid var(--docku-border);
    border-radius: var(--docku-radius-lg);
    box-shadow: var(--docku-shadow-xs);
    margin-bottom: var(--docku-space-3);
    padding: var(--docku-space-2) 0;
  }
  .data-table tbody tr:hover { background: var(--docku-surface); }
  .data-table td {
    border: none;
    border-bottom: 1px solid var(--docku-border);
    padding: 0.55rem var(--docku-space-4);
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: var(--docku-space-3);
    text-align: right;
    min-height: 32px;
  }
  .data-table td:last-child { border-bottom: none; }
  .data-table td::before {
    content: attr(data-label);
    font-size: 0.74rem;
    font-weight: 700;
    text-transform: none;
    letter-spacing: 0.05em;
    color: var(--docku-text-muted);
    text-align: left;
    flex: 0 0 42%;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  .data-table td.col-actions {
    /* Actions stay on a single full-width row at the bottom of the card. */
    text-align: right;
    justify-content: flex-end;
    padding-top: var(--docku-space-3);
  }
  .data-table td.col-actions::before { display: none; }
  /* PUB-015: the expanded catalogue detail is a container, not a labelled
     field.  As a field row it inherited the 42%-label flex layout and the
     right alignment, which pushed the article 28px past the viewport and
     spilled the page sideways. */
  .publications-page .data-table td.pub-detail-cell {
    display: block;
    text-align: left;
  }
  .publications-page .data-table td.pub-detail-cell::before { display: none; }
  /* PUB-017: a phone card shows what a reader scans — the id, the title, the
     category, when it changed, and the actions — instead of eleven labelled
     field rows (~500px: one publication filled the screen, so the page did
     not read as a list).  Every folded field is in the row's expanded detail
     (Record / Classification / Review cycle), so nothing becomes
     unreachable.  Scoped to `.publications-page` and to this breakpoint: the
     class keeps its documented meaning for the other tables, and the generic
     rule lives at 640px where card mode is not yet active. */
  .publications-page .data-table .col-hide-mobile { display: none; }
  /* The title cell is the card's heading: full width, left aligned, and
     without the "Title" label it does not need (the description clamp is
     already two lines, from `.table-doc-desc`). */
  .publications-page .data-table td.col-title {
    display: block;
    text-align: left;
    min-width: 0;
    padding-bottom: var(--docku-space-1);
  }
  .publications-page .data-table td.col-title::before { display: none; }
  .data-table .text-ellipsis { max-width: none; }
}

/* ── Version history table override ─────────────────────────────
   The version history tables are narrow (5 columns) and display
   nicely as a true table even on phones, unlike the 13-column
   document list.  We override the card-stack rule for this
   specific table and instead hide low-priority columns on mobile
   (.col-hide-mobile).  The body is capped at ~3 visible rows with
   vertical scroll, and the thead stays sticky on top. */

.version-history-scroll {
  max-height: 172px;          /* ~3 rows (53px each) + sticky header */
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
}

.version-history-table.data-table {
  min-width: auto;        /* remove the 1400px floor */
  width: 100%;
}

.version-history-table thead th {
  position: sticky;
  top: 0;
  background: var(--docku-surface);
  z-index: 1;
}

@media (max-width: 768px) {
  /* Revert card-stack display: block for version history only */
  .version-history-table.data-table thead {
    position: static;
    display: table-header-group;
  }
  .version-history-table.data-table tbody {
    display: table-row-group;
  }
  .version-history-table.data-table tr {
    display: table-row;
  }
  .version-history-table.data-table td {
    display: table-cell;
  }
  .version-history-table.data-table tr {
    background: transparent;
    border: none;
    border-radius: 0;
    box-shadow: none;
    margin-bottom: 0;
    padding: 0;
  }
  .version-history-table.data-table td {
    border-bottom: 1px solid var(--docku-border);
    padding: 0.55rem var(--docku-space-4);
    text-align: left;
    min-height: auto;
  }
  .version-history-table.data-table td::before {
    display: none;          /* hide the data-label pseudo-element */
  }
  .version-history-table.data-table td.col-hide-mobile,
  .version-history-table.data-table th.col-hide-mobile {
    display: none;          /* 0,2,1 specificity — ties with .version-history-table.data-table td */
  }
  .version-history-table.data-table td.col-actions {
    text-align: right;
    justify-content: flex-end;
  }
}

/* Hint at horizontal scroll on the table wrapper when narrow but
   not yet at the card-stack breakpoint, so users on tablets know
   there is more content. */
.table-scroll {
  position: relative;
}
@media (max-width: 1024px) and (min-width: 769px) {
  .table-scroll::after {
    content: "";
    position: sticky;
    right: 0;
    top: 0;
    width: 32px;
    height: 100%;
    pointer-events: none;
    background: linear-gradient(
      to right,
      transparent,
      var(--docku-surface) 80%
    );
  }
}

/* Card list view (mobile-first alternative to tables) */
.card-list {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--docku-space-3);
}
.card-list-item {
  background: var(--docku-surface);
  border: 1px solid var(--docku-border);
  border-radius: var(--docku-radius-lg);
  box-shadow: var(--docku-shadow-xs);
  padding: var(--docku-space-4);
  display: flex;
  align-items: center;
  gap: var(--docku-space-3);
  transition: box-shadow var(--docku-dur) var(--docku-ease), transform var(--docku-dur) var(--docku-ease);
  cursor: pointer;
}
.card-list-item:hover {
  box-shadow: var(--docku-shadow);
  transform: translateY(-1px);
}
.card-list-item-body { flex: 1; min-width: 0; }
.card-list-item-title {
  font-size: 0.95rem;
  font-weight: 600;
  color: var(--docku-text);
  margin: 0 0 0.25rem;
  word-break: break-word;
}
.card-list-item-meta {
  display: flex;
  align-items: center;
  gap: var(--docku-space-3);
  flex-wrap: wrap;
  font-size: 0.82rem;
  color: var(--docku-text-muted);
}
.card-list-item-meta-item {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
}
.card-list-item-meta-item .fa { font-size: 0.78rem; opacity: 0.8; }
.card-list-item-actions { flex-shrink: 0; }

/* View toggle (table vs card) — height matches .btn (38px / 44px on mobile) */
.view-toggle {
  display: inline-flex;
  align-items: stretch;
  box-sizing: border-box;
  height: 38px;
  background: var(--docku-surface-raised);
  border: 1px solid var(--docku-border);
  border-radius: var(--docku-radius);
  padding: 3px;
}
.view-toggle button {
  background: transparent;
  border: none;
  margin: 0;
  height: 100%;
  min-height: 0;
  padding: 0 0.75rem;
  font-size: 0.85rem;
  font-weight: 600;
  line-height: 1;
  color: var(--docku-text-muted);
  cursor: pointer;
  border-radius: 7px;
  font-family: inherit;
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  width: auto;
  box-shadow: none;
  transition: background var(--docku-dur-fast) var(--docku-ease), color var(--docku-dur-fast) var(--docku-ease);
}
.view-toggle button.active {
  background: var(--docku-surface);
  color: var(--docku-primary);
  box-shadow: var(--docku-shadow-xs);
}
.view-toggle button:hover:not(.active) { color: var(--docku-text); }
@media (max-width: 640px) {
  .view-toggle { height: 44px; }
}
/* Hide the Table / Cards toggle entirely below 768px — the broken
   card-stack fallback for `.data-table` is no longer used because
   `DocumentList._viewportSync` forces the Cards view on mobile. */
@media (max-width: 768px) {
  .view-toggle { display: none; }
}

/* ── 10. Filter panel ──────────────────────────────────────── */
.filter-panel {
  background: var(--docku-surface);
  border: 1px solid var(--docku-border);
  border-radius: var(--docku-radius-lg);
  box-shadow: var(--docku-shadow-xs);
  padding: var(--docku-space-4);
  margin-bottom: var(--docku-space-4);
}
.docs-list-page .filter-panel {
  padding: var(--docku-space-3);
  margin-bottom: var(--docku-space-3);
}
.docs-list-page .table-scroll {
  /* PUB-015: the same row-driven window as the catalogue — five document
     rows (5.5rem each at 1280x900: a row with a two-line title and status
     chips) plus the sticky header (2.6rem), clamped to the window.  A
     document row is taller and more variable than a catalogue row, so the
     value is measured per page rather than shared.  Card mode releases it;
     see the card-stack block. */
  max-height: min(
    calc(2.6rem + 5 * 5.5rem),
    calc(100dvh - var(--docku-topbar-h) - 12rem)
  );
  overflow: auto;
}
.docs-list-page .data-table thead th {
  position: sticky;
  top: 0;
  z-index: 3;
}
.docs-list-page .data-table thead th.col-actions {
  z-index: 4;
}
.docs-list-page .filter-panel-header {
  margin-bottom: var(--docku-space-2);
}
.docs-list-page .filter-grid {
  grid-template-columns:
    minmax(220px, 2.4fr)   /* Search — wider than the rest */
    minmax(140px, 1fr)     /* Status */
    minmax(140px, 1fr)     /* Type (category) */
    minmax(140px, 1fr);    /* Owner (admin only) */
  gap: var(--docku-space-2);
  align-items: end;
}
.filter-panel-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: var(--docku-space-3);
  gap: var(--docku-space-3);
}
.filter-panel-header h3 {
  margin: 0;
  font-size: 0.85rem;
  font-weight: 700;
  text-transform: none;
  letter-spacing: 0.05em;
  color: var(--docku-text-muted);
}
/* Phone-only disclosure (APP-007) — hidden above the breakpoint, where the
   whole panel is on screen and the button would do nothing. */
.filter-toggle {
  display: none;
}
.filter-toggle-chevron {
  transition: transform var(--docku-dur-fast) var(--docku-ease);
}
.filter-toggle-chevron.is-open {
  transform: rotate(180deg);
}
.filter-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: var(--docku-space-3);
  align-items: end;
}
/* Toggles row sitting under the filter inputs.  Stretched so the
   checkbox hugs the panel width with a small left padding indent. */
.filter-panel-toggles {
  display: flex;
  flex-wrap: wrap;
  gap: var(--docku-space-4);
  margin-top: var(--docku-space-3);
  padding-top: var(--docku-space-3);
  border-top: 1px dashed var(--docku-border);
}
.checkbox-toggle {
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: 0.5rem;
  cursor: pointer;
  user-select: none;
  font-size: 0.9rem;
  color: var(--docku-text);
}
.checkbox-toggle input[type="checkbox"] {
  width: 1.05rem;
  height: 1.05rem;
  margin: 0;
  flex-shrink: 0;
  accent-color: var(--docku-primary, #2563eb);
}
.checkbox-toggle-label {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  font-weight: 600;
}
.checkbox-toggle-label i {
  color: var(--docku-text-muted);
}
.checkbox-toggle-help {
  display: block;
  margin-left: 1.4rem;
  color: var(--docku-text-muted);
  font-size: 0.78rem;
  line-height: 1.3;
}
.filter-actions {
  display: flex;
  gap: var(--docku-space-2);
  align-items: center;
  flex-wrap: wrap;
}
.filter-summary {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin: var(--docku-space-3) 0 var(--docku-space-2);
  font-size: 0.88rem;
  color: var(--docku-text-muted);
}

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

/* APP-007: on a phone the documents filter panel keeps only the search box
   on screen; the rest folds behind the header's "Filters (n)" disclosure,
   collapsed unless the reader opened it this session.  Written in `rem` so
   the query shares the 768px breakpoint without adding a px literal (the
   literal ratchet counts every `max-width: Npx` prelude). */
@media (max-width: 48rem) {
  .docs-list-page .filter-panel-title { display: none; }
  .docs-list-page .filter-toggle {
    display: inline-flex;
  }
  .docs-list-page .filter-panel:not(.is-filters-open) .filter-more { display: none; }
}

@media (max-width: 1024px) {
  .docs-list-page .filter-grid {
    grid-template-columns: 1fr 1fr;
  }
  /* PUB-016 follow-up: this pinned the *first label* full width, which was
     the search input until the search became its own component.  Target the
     field instead, so the search box still spans the pair above its
     neighbours. */
  .docs-list-page .filter-grid > .search-terms {
    grid-column: 1 / -1;
  }
}
@media (max-width: 640px) {
  .docs-list-page .page-header {
    flex-direction: column;
    align-items: stretch;
    padding: var(--docku-space-4);
    gap: var(--docku-space-3);
  }
  .docs-list-page .page-header-actions {
    width: 100%;
  }
  .docs-list-page .page-header-actions .btn-primary {
    flex: 1;
  }
  .docs-list-page .view-toggle-label {
    display: none;
  }
  .docs-list-page .filter-grid {
    grid-template-columns: 1fr;
  }
  .docs-list-page .filter-grid > label:first-child {
    grid-column: auto;
  }
  .docs-list-page .filter-grid input,
  .docs-list-page .filter-grid select {
    min-height: 44px;
  }
  .docs-list-page .checkbox-toggle {
    min-height: 44px;
    width: 100%;
  }
}

/* ── 11. Mobile nav drawer ─────────────────────────────────── */
.mobile-nav-overlay {
  position: fixed;
  inset: 0;
  background: rgba(15, 23, 42, 0.5);
  backdrop-filter: blur(2px);
  z-index: 100;
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--docku-dur) var(--docku-ease);
}
.mobile-nav-overlay.is-open {
  opacity: 1;
  pointer-events: auto;
}
.mobile-nav-drawer {
  position: fixed;
  top: 0;
  left: 0;
  bottom: 0;
  width: min(320px, 88vw);
  background: var(--docku-surface);
  z-index: 110;
  transform: translateX(-100%);
  /* visibility:hidden keeps the closed drawer out of the tab order and
     the accessibility tree (belt-and-braces alongside :inert on the
     aside). The delayed visibility flip lets the slide-out animation
     finish before the drawer disappears. */
  visibility: hidden;
  transition: transform var(--docku-dur-slow) var(--docku-ease-out),
              visibility 0s linear var(--docku-dur-slow);
  display: flex;
  flex-direction: column;
  box-shadow: var(--docku-shadow-lg);
  overflow: hidden;
}
.mobile-nav-drawer.is-open {
  transform: translateX(0);
  visibility: visible;
  transition: transform var(--docku-dur-slow) var(--docku-ease-out);
}
.mobile-nav-drawer-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--docku-space-4) var(--docku-space-5);
  border-bottom: 1px solid var(--docku-border);
  height: var(--docku-topbar-h);
  flex-shrink: 0;
}
.mobile-nav-drawer-body {
  flex: 1;
  overflow-y: auto;
  padding: var(--docku-space-4) var(--docku-space-3);
}

/* Identity block at the top of the drawer body (avatar, name, role).
   The topbar hides the username on phones, so this is the one surface
   where signed-in users see who they are. */
.mobile-nav-user {
  display: flex;
  align-items: center;
  gap: var(--docku-space-3);
  min-height: 56px;
  padding: var(--docku-space-2) var(--docku-space-3);
  margin-bottom: var(--docku-space-4);
  background: var(--docku-surface-raised);
  border: 1px solid var(--docku-border);
  border-radius: var(--docku-radius-lg);
  text-decoration: none;
  color: var(--docku-text);
  transition: background var(--docku-dur-fast) var(--docku-ease),
              border-color var(--docku-dur-fast) var(--docku-ease);
}
.mobile-nav-user:hover,
.mobile-nav-user:focus-visible {
  background: var(--docku-surface);
  border-color: var(--docku-primary-soft);
  outline: none;
}
.mobile-nav-user:focus-visible {
  box-shadow: 0 0 0 3px var(--docku-primary-soft);
}
.mobile-nav-user-text {
  display: flex;
  flex-direction: column;
  min-width: 0;
  flex: 1;
}
.mobile-nav-user-name {
  font-size: 0.95rem;
  font-weight: 600;
  color: var(--docku-text);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.mobile-nav-user-role {
  font-size: 0.78rem;
  color: var(--docku-text-muted);
  text-transform: capitalize;
}
.mobile-nav-user-chevron {
  color: var(--docku-text-faint);
  flex-shrink: 0;
}

/* Drawer nav links. The drawer markup reuses .app-sidebar-section but
   sits outside the .app-sidebar ancestor, so those link styles never
   matched here — Pico's classless nav defaults were applying instead.
   Mirror the sidebar link style with >=44px touch targets. */
.mobile-nav-drawer nav ul {
  list-style: none;
  padding: 0;
  margin: 0;
}
.mobile-nav-drawer nav a {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  min-height: 44px;
  padding: 0.85rem var(--docku-space-3);
  margin: 0.1rem 0;
  font-size: 0.95rem;
  font-weight: 500;
  color: var(--docku-text-2);
  text-decoration: none;
  border-radius: var(--docku-radius);
  transition: background var(--docku-dur-fast) var(--docku-ease),
              color var(--docku-dur-fast) var(--docku-ease);
}
.mobile-nav-drawer nav a .fa {
  width: 20px;
  text-align: center;
  font-size: 1rem;
  color: var(--docku-text-faint);
  transition: color var(--docku-dur-fast) var(--docku-ease);
}
.mobile-nav-drawer nav a:hover {
  background: var(--docku-surface-raised);
  color: var(--docku-text);
}
.mobile-nav-drawer nav a:hover .fa { color: var(--docku-text-2); }
.mobile-nav-drawer nav a.active {
  background: var(--docku-primary);
  color: #fff;
  box-shadow: var(--docku-shadow-primary);
}
.mobile-nav-drawer nav a.active .fa { color: #fff; }
.mobile-nav-drawer nav a .sidebar-count {
  margin-left: auto;
  background: var(--docku-surface-raised);
  color: var(--docku-text-muted);
  font-size: 0.72rem;
  font-weight: 700;
  padding: 0.1rem 0.45rem;
  border-radius: var(--docku-radius-full);
  min-width: 1.4rem;
  text-align: center;
}
.mobile-nav-drawer nav a.active .sidebar-count {
  background: rgba(255, 255, 255, 0.22);
  color: #fff;
}
.mobile-nav-drawer .app-sidebar-label {
  padding: 0 var(--docku-space-3);
}

/* Thumb-reach footer bar (theme toggle + version). */
.mobile-nav-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--docku-space-2);
  flex-shrink: 0;
  padding: var(--docku-space-3) var(--docku-space-4);
  border-top: 1px solid var(--docku-border);
}
.mobile-nav-foot-btn {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  min-height: 44px;
  padding: 0.5rem 0.9rem;
  background: transparent;
  border: 1px solid var(--docku-border);
  border-radius: var(--docku-radius-full);
  font-family: inherit;
  font-size: 0.88rem;
  font-weight: 600;
  color: var(--docku-text-2);
  cursor: pointer;
  transition: background var(--docku-dur-fast) var(--docku-ease),
              border-color var(--docku-dur-fast) var(--docku-ease),
              color var(--docku-dur-fast) var(--docku-ease);
}
.mobile-nav-foot-btn:hover {
  background: var(--docku-surface-raised);
  border-color: var(--docku-border-strong);
  color: var(--docku-text);
}
.mobile-nav-foot-btn:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px var(--docku-primary-soft);
  border-color: var(--docku-primary);
}
.mobile-nav-foot-version {
  font-size: 0.78rem;
  color: var(--docku-text-faint);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* ── 12. Toast (modernized) ────────────────────────────────── */
#toast-container {
  position: fixed;
  top: 1rem;
  right: 1rem;
  z-index: 9999;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  max-width: min(380px, calc(100vw - 2rem));
  pointer-events: none;
}
.toast {
  pointer-events: auto;
  display: flex;
  align-items: flex-start;
  gap: 0.6rem;
  padding: 0.8rem 1rem;
  border-radius: var(--docku-radius);
  background: var(--docku-surface);
  border: 1px solid var(--docku-border);
  box-shadow: var(--docku-shadow-md);
  font-size: 0.9rem;
  animation: toast-in 0.18s var(--docku-ease-out);
  cursor: pointer;
}
.toast.fade-out { animation: toast-out 0.25s var(--docku-ease) forwards; }
.toast .toast-icon {
  width: 22px;
  height: 22px;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 0.75rem;
  font-weight: 700;
  flex-shrink: 0;
}
.toast .toast-msg { flex: 1; line-height: 1.4; }
.toast.success { border-left: 3px solid var(--docku-success); }
.toast.success .toast-icon { background: var(--docku-success-soft); color: var(--docku-success); }
.toast.error   { border-left: 3px solid var(--docku-danger); }
.toast.error   .toast-icon { background: var(--docku-danger-soft); color: var(--docku-danger); }
.toast.info    { border-left: 3px solid var(--docku-info); }
.toast.info    .toast-icon { background: var(--docku-info-soft); color: var(--docku-info); }
.toast.warn    { border-left: 3px solid var(--docku-warning); }
.toast.warn    .toast-icon { background: var(--docku-warning-soft); color: var(--docku-warning); }

@keyframes toast-in  { from { opacity: 0; transform: translateX(20px); } to { opacity: 1; transform: translateX(0); } }
@keyframes toast-out { from { opacity: 1; transform: translateX(0); }    to { opacity: 0; transform: translateX(20px); } }

@media (max-width: 640px) {
  #toast-container {
    top: auto;
    bottom: 1rem;
    right: 1rem;
    left: 1rem;
    max-width: none;
    align-items: stretch;
  }
  @keyframes toast-in  { from { opacity: 0; transform: translateY(20px); } to { opacity: 1; transform: translateY(0); } }
  @keyframes toast-out { from { opacity: 1; transform: translateY(0); }    to { opacity: 0; transform: translateY(20px); } }
}

/* ── 13. Banner / Alert ────────────────────────────────────── */
.app-banner {
  display: flex;
  align-items: flex-start;
  gap: 0.6rem;
  padding: 0.8rem 1rem;
  border-radius: var(--docku-radius);
  margin-bottom: var(--docku-space-4);
  font-size: 0.9rem;
  border: 1px solid transparent;
}
.app-banner .fa { font-size: 1rem; flex-shrink: 0; margin-top: 1px; }
.app-banner.error   { background: var(--docku-danger-soft);  color: var(--docku-danger-text);  border-color: #fecaca; }
.app-banner.success { background: var(--docku-success-soft); color: var(--docku-success-text); border-color: #a7f3d0; }
.app-banner.info    { background: var(--docku-info-soft);    color: var(--docku-info-text);    border-color: #bfdbfe; }
.app-banner.warn    { background: var(--docku-warning-soft); color: var(--docku-warning-text); border-color: #fde68a; }

/* ── 14. Empty states ──────────────────────────────────────── */
.empty-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: var(--docku-space-10) var(--docku-space-5);
  color: var(--docku-text-muted);
}
.empty-state-icon {
  width: 64px;
  height: 64px;
  border-radius: 50%;
  background: var(--docku-surface-raised);
  color: var(--docku-text-faint);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 1.5rem;
  margin-bottom: var(--docku-space-3);
}
.empty-state-title {
  font-size: 1.05rem;
  font-weight: 600;
  color: var(--docku-text);
  margin: 0 0 0.25rem;
}
.empty-state-message {
  font-size: 0.92rem;
  color: var(--docku-text-muted);
  margin: 0 0 var(--docku-space-4);
  max-width: 380px;
}

/* ── 15. Skeletons (loading placeholders) ──────────────────── */
.skeleton {
  position: relative;
  display: block;
  overflow: hidden;
  background: var(--docku-surface-sunken);
  border-radius: var(--docku-radius);
}
/* CSS-003: the shimmer is a `transform` on a pseudo-element band, not an
   animated `background-position`.  Transform is composited (no layout/
   paint per frame); `background-position` forced a repaint every frame.
   The base keeps `--docku-surface-sunken` so the reduced-motion fallback
   (animation frozen by the global `reduce` rule) shows a calm flat block. */
.skeleton::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(
    90deg,
    transparent 0%,
    var(--docku-surface-raised) 50%,
    transparent 100%
  );
  transform: translateX(-100%);
  animation: skeleton-shimmer 1.4s linear infinite;
}
.skeleton-text {
  height: 0.85rem;
  margin: 0.35rem 0;
}
.skeleton-text.is-large { height: 1.2rem; }
.skeleton-text.is-small { height: 0.7rem; }
.skeleton-circle { border-radius: 50%; }
.skeleton-card {
  height: 96px;
  border-radius: var(--docku-radius-lg);
}
.skeleton-row { height: 48px; }
@keyframes skeleton-shimmer {
  0%   { transform: translateX(-100%); }
  100% { transform: translateX(100%); }
}

/* ── 16. Spinner ───────────────────────────────────────────── */
.spinner {
  display: inline-block;
  width: 1em;
  height: 1em;
  border: 2px solid var(--docku-border);
  border-top-color: var(--docku-primary);
  border-radius: 50%;
  animation: spin 0.6s linear infinite;
  vertical-align: middle;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* ── 17. Action menu (kept from before) ────────────────────── */
.action-menu-wrap { display: inline-flex; align-items: center; justify-content: center; position: relative; }
.action-menu-trigger {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  padding: 0;
  margin-bottom: 0; /* override Pico [type=button]{margin-bottom:var(--pico-spacing)} */
  border-radius: var(--docku-radius);
  border: 1px solid var(--docku-border);
  background: var(--docku-surface);
  color: var(--docku-text-2);
  cursor: pointer;
  font-size: 1rem;
  line-height: 1;
  transition: background var(--docku-dur-fast) var(--docku-ease),
              border-color var(--docku-dur-fast) var(--docku-ease),
              transform var(--docku-dur-fast) var(--docku-ease);
}
@media (max-width: 640px) {
  /* 36×36 is below the 44×44 mobile minimum; grow the hit area while
     keeping the visible button the same size via negative margin. */
  .action-menu-trigger {
    width: 44px;
    height: 44px;
    margin: -4px;
  }
/* Standalone trigger sits next to .btn elements in the page header; match
      their 44px mobile min-height so the flex row stays aligned. */
  .action-menu-trigger.standalone {
    min-height: 44px;
    margin: 0; /* override the -4px from base .action-menu-trigger */
  }
}
.action-menu-trigger:hover, .action-menu-trigger:focus-visible {
  background: var(--docku-surface-raised);
  border-color: var(--docku-border-strong);
  outline: none;
}
.action-menu-trigger:focus-visible {
  box-shadow: 0 0 0 3px var(--docku-primary-soft);
  border-color: var(--docku-primary);
}
.action-menu-trigger:active { transform: scale(0.96); }
.action-menu-trigger.standalone {
  width: auto;
  height: auto;
  min-height: 38px; /* match .btn height so it aligns with adjacent buttons in .page-header-actions */
  padding: 0.5rem 1rem; /* match .btn exactly */
  gap: 0.5rem; /* match .btn exactly */
  font-size: 0.92rem; /* match .btn exactly */
  line-height: 1.2; /* match .btn exactly */
  font-weight: 600;
  font-family: inherit; /* match .btn exactly so content metrics align */
}

body.action-sheet-open { overflow: hidden; }
.action-sheet-overlay {
  position: fixed;
  inset: 0;
  z-index: 10060;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  background: rgba(15, 23, 42, 0.5);
  backdrop-filter: blur(2px);
  animation: action-sheet-fade 0.18s ease-out;
}
.action-sheet-overlay.is-desktop { align-items: center; padding: 1.5rem; }
@keyframes action-sheet-fade { from { opacity: 0; } to { opacity: 1; } }

.action-sheet {
  width: 100%;
  max-width: 100%;
  background: var(--docku-surface);
  border-radius: 1.25rem 1.25rem 0 0;
  box-shadow: 0 -8px 24px rgba(15, 23, 42, 0.18);
  display: flex;
  flex-direction: column;
  max-height: 85vh;
  overflow: hidden;
  animation: action-sheet-slide-up 0.26s var(--docku-ease-out);
}
.action-sheet-overlay.is-desktop .action-sheet {
  border-radius: 1.25rem;
  max-width: 420px;
  max-height: 80vh;
  animation: action-sheet-pop-in 0.22s var(--docku-ease-out);
}
@keyframes action-sheet-slide-up { from { transform: translateY(100%); } to { transform: translateY(0); } }
@keyframes action-sheet-pop-in { from { transform: scale(0.94); opacity: 0; } to { transform: scale(1); opacity: 1; } }

.action-sheet-handle {
  width: 40px; height: 5px;
  background: var(--docku-border-strong);
  border-radius: var(--docku-radius-full);
  margin: 0.6rem auto 0.2rem;
  flex-shrink: 0;
}
.action-sheet-header {
  padding: 0.6rem 1.25rem 0.4rem;
  text-align: center;
  border-bottom: 1px solid var(--docku-border);
}
.action-sheet-title {
  margin: 0;
  font-size: 0.95rem;
  font-weight: 700;
  color: var(--docku-text-muted);
  text-transform: none;
  letter-spacing: 0.05em;
}
.action-sheet-list { overflow-y: auto; padding: 0.4rem 0; display: flex; flex-direction: column; }
.action-sheet-item {
  display: flex; align-items: center; gap: 0.9rem; width: 100%;
  padding: 0.9rem 1.25rem;
  border: none; background: transparent; text-align: left;
  font-size: 1rem; font-weight: 500; color: var(--docku-text);
  cursor: pointer; min-height: 54px; position: relative; font-family: inherit;
}
.action-sheet-item + .action-sheet-item { border-top: 1px solid var(--docku-border); }
.action-sheet-item::before {
  content: ''; width: 6px; height: 28px; border-radius: var(--docku-radius-full);
  background: var(--action-color, var(--docku-border-strong)); flex-shrink: 0;
}
.action-sheet-item > i, .action-sheet-item > .fa {
  font-size: 1.1rem; width: 1.4rem; text-align: center;
  color: var(--action-color, var(--docku-text)); flex-shrink: 0;
}
.action-sheet-item:hover, .action-sheet-item:focus-visible {
  background: var(--docku-surface-raised); outline: none;
}
.action-sheet-item:focus-visible {
  box-shadow: inset 0 0 0 3px var(--docku-primary-soft);
}
.action-sheet-item.is-disabled { opacity: 0.45; cursor: not-allowed; }
.action-sheet-cancel {
  margin: 0.6rem 0.8rem 0.9rem;
  padding: 0.85rem;
  background: var(--docku-surface-raised);
  border: 1px solid var(--docku-border);
  border-radius: var(--docku-radius);
  color: var(--docku-text);
  font-weight: 600;
  font-size: 1rem;
  cursor: pointer;
  font-family: inherit;
}
.action-sheet-cancel:hover, .action-sheet-cancel:focus-visible {
  background: var(--docku-surface); outline: none;
}
.action-sheet-cancel:focus-visible {
  box-shadow: inset 0 0 0 3px var(--docku-primary-soft);
}

@media (max-width: 640px) {
  .action-sheet-overlay { align-items: flex-end; }
  .action-sheet { border-radius: 1.25rem 1.25rem 0 0; max-height: 90vh; }
  .action-sheet-item { padding: 1rem 1.25rem; min-height: 58px; }
}

/* ── Silent-edit modal (admin-only metadata fix-up) ─────── */
.silent-edit-overlay {
  /* Override the default action-sheet-overlay styling so the dialog is
   * clearly a "form" modal rather than a quick action sheet.  We keep
   * the .action-sheet-overlay.is-desktop backdrop and animations. */
  z-index: 1100;
}
.silent-edit-modal {
  width: min(720px, 100%);
  max-height: min(90vh, 880px);
  padding: var(--docku-space-4) var(--docku-space-4) var(--docku-space-3);
  text-align: left;
  display: flex;
  flex-direction: column;
}
.silent-edit-modal .action-sheet-header {
  border-bottom: 1px solid var(--docku-border);
  margin-bottom: var(--docku-space-2);
  padding-bottom: var(--docku-space-2);
}
.silent-edit-modal .action-sheet-title {
  display: flex; align-items: center; gap: 0.5rem;
  color: var(--docku-text);
}
.silent-edit-help {
  margin: 0 0 var(--docku-space-3);
  padding: var(--docku-space-2) var(--docku-space-3);
  background: var(--docku-surface);
  border: 1px solid var(--docku-border);
  border-radius: var(--docku-radius);
  font-size: 0.9rem;
  color: var(--docku-text-2);
  display: flex; align-items: flex-start; gap: 0.5rem;
}
.silent-edit-help i { color: var(--docku-primary); margin-top: 0.15rem; }
.silent-edit-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--docku-space-2) var(--docku-space-3);
  overflow-y: auto;
  padding-right: var(--docku-space-1);
}
.silent-edit-grid label {
  display: flex; flex-direction: column;
  gap: 0.25rem;
  min-width: 0;
}
.silent-edit-grid .form-section-wide { grid-column: 1 / -1; }
.silent-edit-grid input,
.silent-edit-grid select,
.silent-edit-grid textarea {
  width: 100%;
  font: inherit;
  padding: 0.45rem 0.6rem;
  border: 1px solid var(--docku-border);
  border-radius: var(--docku-radius);
  background: var(--docku-surface);
  color: var(--docku-text);
}
.silent-edit-grid textarea { resize: vertical; }
.silent-edit-error { margin: var(--docku-space-2) 0 0; }
.silent-edit-actions {
  display: flex;
  justify-content: flex-end;
  gap: var(--docku-space-2);
  margin-top: var(--docku-space-3);
  padding-top: var(--docku-space-2);
  border-top: 1px solid var(--docku-border);
}
@media (max-width: 640px) {
  .silent-edit-modal {
    max-height: 92vh;
    border-radius: 1.25rem 1.25rem 0 0;
    padding: var(--docku-space-3) var(--docku-space-3) var(--docku-space-3);
  }
  .silent-edit-grid { grid-template-columns: 1fr; }
}

/* ── Ack-invite modal (owner / admin reviewer invitation) ─────── */
.ack-invite-overlay {
  z-index: 1100;
}
.ack-invite-modal {
  width: min(560px, 100%);
  max-height: min(85vh, 720px);
  padding: var(--docku-space-4) var(--docku-space-4) var(--docku-space-3);
  text-align: left;
  display: flex;
  flex-direction: column;
}
.ack-invite-modal .action-sheet-header {
  border-bottom: 1px solid var(--docku-border);
  margin-bottom: var(--docku-space-2);
  padding-bottom: var(--docku-space-2);
}
.ack-invite-modal .action-sheet-title {
  display: flex; align-items: center; gap: 0.5rem;
  color: var(--docku-text);
}
.ack-invite-help {
  margin: 0 0 var(--docku-space-3);
  padding: var(--docku-space-2) var(--docku-space-3);
  background: var(--docku-surface);
  border: 1px solid var(--docku-border);
  border-radius: var(--docku-radius);
  font-size: 0.9rem;
  color: var(--docku-text-2);
  display: flex; align-items: flex-start; gap: 0.5rem;
}
.ack-invite-help i { color: var(--docku-primary); margin-top: 0.15rem; }
.ack-invite-body {
  display: flex;
  flex-direction: column;
  gap: var(--docku-space-3);
  overflow-y: auto;
  padding-right: var(--docku-space-1);
}
.ack-invite-field {
  display: flex; flex-direction: column;
  gap: 0.25rem;
  min-width: 0;
}
.ack-invite-field small {
  color: var(--docku-text-muted);
  font-size: 0.85rem;
}
.ack-invite-hint {
  display: block;
  margin: 0.25rem 0 0;
  color: var(--docku-text-muted);
  font-size: 0.8rem;
  font-style: italic;
}
.ack-invite-field textarea {
  width: 100%;
  font: inherit;
  padding: 0.45rem 0.6rem;
  border: 1px solid var(--docku-border);
  border-radius: var(--docku-radius);
  background: var(--docku-surface);
  color: var(--docku-text);
  resize: vertical;
}
.ack-invite-checkbox {
  display: flex; align-items: center; gap: 0.5rem;
  font-size: 0.95rem;
  color: var(--docku-text);
  cursor: pointer;
}
.ack-invite-checkbox input { margin: 0; }
.ack-invite-error { margin: var(--docku-space-2) 0 0; }
.ack-invite-actions {
  display: flex;
  justify-content: flex-end;
  gap: var(--docku-space-2);
  margin-top: var(--docku-space-3);
  padding-top: var(--docku-space-2);
  border-top: 1px solid var(--docku-border);
}
@media (max-width: 640px) {
  .ack-invite-modal {
    max-height: 92vh;
    border-radius: 1.25rem 1.25rem 0 0;
    padding: var(--docku-space-3) var(--docku-space-3) var(--docku-space-3);
  }
}

/* ── Invitee ack-banner (read-receipt prompt shown to invited users) ──
   Three semantic states: --pending (neutral, awaiting open),
   --viewed (warning amber — opened but not yet acknowledged),
   --declined (danger — finished with a decline),
   plus a --acknowledged fallback (success, normally hidden because the
   whole section gates on `!status.startsWith('acknowledged')`). */
.ack-banner {
  display: flex;
  align-items: center;
  gap: var(--docku-space-4);
  padding: var(--docku-space-4) var(--docku-space-5);
  margin: 0 0 var(--docku-space-4);
  background: var(--docku-surface);
  border: 1px solid var(--docku-border);
  border-left-width: 4px;
  border-radius: var(--docku-radius-lg);
  box-shadow: var(--docku-shadow-xs);
  flex-wrap: wrap;
}
.ack-banner-icon {
  width: 42px;
  height: 42px;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  font-size: 1.1rem;
  background: var(--docku-surface-raised);
  color: var(--docku-text-muted);
}
.ack-banner-text {
  flex: 1 1 240px;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  font-size: 0.92rem;
  color: var(--docku-text-2);
}
.ack-banner-text strong {
  color: var(--docku-text);
  font-size: 0.98rem;
  font-weight: 600;
}
.ack-banner-actions {
  display: inline-flex;
  align-items: center;
  gap: var(--docku-space-2);
  flex-shrink: 0;
  margin-left: auto;
  flex-wrap: wrap;
}

/* Pending — neutral, just an invite waiting */
.ack-banner--pending {
  background: var(--docku-primary-50);
  border-color: var(--docku-primary-soft);
  border-left-color: var(--docku-primary);
}
.ack-banner--pending .ack-banner-icon {
  background: var(--docku-primary-100);
  color: var(--docku-primary-dark);
}

/* Viewed — amber, nudge to confirm */
.ack-banner--viewed {
  background: var(--docku-warning-soft);
  border-color: #fde68a;
  border-left-color: var(--docku-warning);
}
.ack-banner--viewed .ack-banner-icon {
  background: #fde68a;
  color: var(--docku-warning-text);
}

/* Declined — danger, terminal state */
.ack-banner--declined {
  background: var(--docku-danger-soft);
  border-color: #fecaca;
  border-left-color: var(--docku-danger);
}
.ack-banner--declined .ack-banner-icon {
  background: #fecaca;
  color: var(--docku-danger-text);
}

/* Acknowledged — success (normally hidden by the parent v-if gate) */
.ack-banner--acknowledged {
  background: var(--docku-success-soft);
  border-color: #a7f3d0;
  border-left-color: var(--docku-success);
}
.ack-banner--acknowledged .ack-banner-icon {
  background: #a7f3d0;
  color: var(--docku-success-text);
}

/* Mobile: stack the actions under the message */
@media (max-width: 640px) {
  .ack-banner {
    flex-direction: column;
    align-items: flex-start;
    gap: var(--docku-space-3);
  }
  .ack-banner-actions {
    margin-left: 0;
    width: 100%;
    justify-content: flex-end;
  }
}

/* ── 18. Notifications (modernized) ───────────────────────── */
.notif-bell-link {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  border-radius: var(--docku-radius);
  border: 1px solid var(--docku-border);
  background: var(--docku-surface);
  color: var(--docku-text-2);
  text-decoration: none;
  transition: background var(--docku-dur-fast) var(--docku-ease), border-color var(--docku-dur-fast) var(--docku-ease);
}
.notif-bell-link:hover {
  background: var(--docku-surface-raised);
  border-color: var(--docku-border-strong);
  color: var(--docku-text);
}
.notif-bell-link.has-unread {
  background: var(--docku-primary-50);
  border-color: var(--docku-primary-soft);
  color: var(--docku-primary);
  box-shadow: 0 0 0 2px var(--docku-primary-soft);
  animation: notif-bell-glow 2.4s ease-in-out infinite;
}
.notif-bell-link .fa { font-size: 0.95rem; line-height: 1; }
.notif-bell-link.bell-shake .fa { animation: notif-bell-pulse 1.6s ease-in-out 2; }
@keyframes notif-bell-pulse {
  0%, 100% { transform: rotate(0deg); }
  10%      { transform: rotate(-12deg); }
  20%      { transform: rotate(10deg); }
  30%      { transform: rotate(-8deg); }
  40%      { transform: rotate(6deg); }
  50%      { transform: rotate(0deg); }
}
@keyframes notif-bell-glow {
  0%, 100% { box-shadow: 0 0 0 2px var(--docku-primary-soft); }
  50%      { box-shadow: 0 0 0 5px rgba(220, 53, 69, 0.18); }
}
.notif-badge {
  position: absolute;
  top: -6px; right: -6px;
  min-width: 20px; height: 20px;
  padding: 0 5px;
  border-radius: var(--docku-radius-full);
  background: var(--docku-danger);
  color: #fff;
  font-size: 0.72rem;
  font-weight: 700;
  line-height: 20px;
  text-align: center;
  box-shadow: 0 0 0 2px var(--docku-surface);
  animation: notif-badge-pop 0.25s ease-out, notif-badge-pulse 1.8s ease-in-out 0.4s infinite;
  /* The badge sits absolutely on top of the bell link.  Letting it
     receive mouse events steals clicks on the "1" digit, so the
     router never navigates.  Pass clicks through to the parent. */
  pointer-events: none;
}
.notif-badge.overflowing { min-width: 24px; }
@keyframes notif-badge-pop { from { transform: scale(0.4); } to { transform: scale(1); } }
@keyframes notif-badge-pulse {
  0%, 100% { box-shadow: 0 0 0 2px var(--docku-surface), 0 0 0 0 rgba(220, 53, 69, 0.55); }
  50%      { box-shadow: 0 0 0 2px var(--docku-surface), 0 0 0 6px rgba(220, 53, 69, 0); }
}

.notif-filters {
  display: flex;
  gap: 0.5rem;
  margin-bottom: var(--docku-space-4);
  flex-wrap: wrap;
}
.notif-filter {
  appearance: none;
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.4rem 0.9rem;
  border-radius: var(--docku-radius-full);
  border: 1px solid var(--docku-border);
  background: var(--docku-surface);
  color: var(--docku-text);
  font-size: 0.88rem;
  font-weight: 500;
  cursor: pointer;
  font-family: inherit;
  transition: background var(--docku-dur-fast) var(--docku-ease), border-color var(--docku-dur-fast) var(--docku-ease), color var(--docku-dur-fast) var(--docku-ease);
}
.notif-filter:hover, .notif-filter:focus-visible {
  border-color: var(--docku-primary); outline: none;
}
.notif-filter:focus-visible {
  box-shadow: 0 0 0 3px var(--docku-primary-soft);
}
.notif-filter.active {
  background: var(--docku-primary);
  color: #fff;
  border-color: var(--docku-primary);
}
.notif-filter-count {
  display: inline-block;
  min-width: 1.5rem;
  padding: 0 0.4rem;
  border-radius: var(--docku-radius-full);
  background: var(--docku-surface-raised);
  color: var(--docku-text-muted);
  font-size: 0.72rem;
  font-weight: 700;
  text-align: center;
  line-height: 1.4rem;
}
.notif-filter.active .notif-filter-count {
  background: rgba(255, 255, 255, 0.25);
  color: inherit;
}

/* ── Pending acknowledgments: bulk toolbar / modal / checkboxes ──
   Used by the Review queue page (`PendingAcknowledgments.js`) for
   bulk acknowledge/decline and the inline decline confirmation
   dialog (Phase 2 Fix #4 and #5). */
.bulk-toolbar {
  position: sticky;
  top: 0;
  z-index: 5;
  display: flex;
  align-items: center;
  gap: 0.6rem;
  flex-wrap: wrap;
  padding: 0.55rem 0.85rem;
  margin-bottom: 0.85rem;
  background: var(--docku-primary-soft, #eef2ff);
  border: 1px solid var(--docku-primary, #6366f1);
  border-radius: var(--docku-radius-md, 8px);
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);
}
.bulk-toolbar-count {
  font-size: 0.85rem;
  color: var(--docku-text, #1f2937);
  margin-right: 0.4rem;
}
.bulk-toolbar-clear {
  margin-left: auto;
}

.bulk-fade-enter-active, .bulk-fade-leave-active {
  transition: opacity 0.15s ease;
}
.bulk-fade-enter-from, .bulk-fade-leave-to {
  opacity: 0;
}

.pending-acks-bulk-header {
  display: flex;
  align-items: center;
  padding: 0.35rem 0.1rem 0.6rem 0.1rem;
  font-size: 0.8rem;
  color: var(--docku-text-muted, #6b7280);
}
.bulk-checkbox-label {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  cursor: pointer;
  user-select: none;
}
.bulk-checkbox-label input { margin: 0; }

.pending-ack--selected {
  outline: 2px solid var(--docku-primary, #6366f1);
  outline-offset: -2px;
}
.pending-ack-checkbox {
  margin: 0 0.4rem 0 0;
  cursor: pointer;
}
.pending-ack-bulk-error {
  color: #dc2626;
  margin-left: 0.4rem;
  font-size: 0.9rem;
}

/* Pending-ack title row: status pill, document link and inviter.  Vue
   condenses the template whitespace, so the flex gap supplies spacing. */
.pending-ack-title {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--docku-space-2);
  min-width: 0;
}
/* "invited by <name>" is secondary to the document link it follows;
   de-emphasise it the same way the collaborator rows do. */
.pending-ack-inviter {
  color: var(--docku-text-muted);
  font-size: 0.8rem;
  font-weight: 400;
}

/* Review-queue acknowledgement meta line. Each item is an icon + label;
   the flex gap keeps the items (and the icon/text pair) from butting up
   against each other after Vue condenses template whitespace. */
.pending-ack-meta {
  display: flex;
  flex-wrap: wrap;
  gap: var(--docku-space-3);
  margin-top: var(--docku-space-2);
  color: var(--docku-text-muted);
  font-size: 0.82rem;
}
.pending-ack-meta > span {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
}
.pending-ack-meta > span .fa {
  font-size: 0.8rem;
  opacity: 0.8;
}

/* Lightweight modal used for the inline decline confirmation.
   Project-wide modals will eventually share these classes; for now
   they're scoped here to keep the change small. */
.modal-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(15, 23, 42, 0.45);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 50;
  padding: 1rem;
}
.modal {
  background: var(--docku-surface, #fff);
  border-radius: var(--docku-radius-md, 10px);
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.18);
  width: 100%;
  max-width: 480px;
  display: flex;
  flex-direction: column;
  max-height: calc(100vh - 2rem);
}
.modal-header {
  padding: 0.9rem 1.1rem 0.4rem 1.1rem;
  border-bottom: 1px solid var(--docku-border, #e5e7eb);
}
.modal-header h3 {
  margin: 0;
  font-size: 1.05rem;
  display: flex;
  align-items: center;
  gap: 0.5rem;
}
.modal-body {
  padding: 0.9rem 1.1rem;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  overflow: auto;
}
.modal-help {
  margin: 0;
  font-size: 0.9rem;
  color: var(--docku-text-muted, #6b7280);
}
.modal-label {
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--docku-text, #1f2937);
}
.modal-textarea {
  width: 100%;
  font: inherit;
  padding: 0.5rem 0.6rem;
  border: 1px solid var(--docku-border, #d1d5db);
  border-radius: var(--docku-radius-sm, 6px);
  background: var(--docku-surface, #fff);
  resize: vertical;
  min-height: 70px;
}
.modal-footer {
  padding: 0.8rem 1.1rem;
  border-top: 1px solid var(--docku-border, #e5e7eb);
  display: flex;
  justify-content: flex-end;
  gap: 0.5rem;
}

.notif-day-heading {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  font-size: 0.74rem;
  font-weight: 700;
  text-transform: none;
  letter-spacing: 0.06em;
  color: var(--docku-text-muted);
  margin: var(--docku-space-4) 0 var(--docku-space-2);
}
.notif-day-heading:first-child { margin-top: 0; }
.notif-day-heading::after {
  content: '';
  flex: 1;
  height: 1px;
  background: var(--docku-border);
}

.notif-list {
  list-style: none; padding: 0; margin: 0;
  display: flex; flex-direction: column;
  gap: 0.4rem;
}
.notif-item {
  display: grid;
  grid-template-columns: auto auto 1fr auto;
  gap: 0.85rem;
  align-items: flex-start;
  padding: 0.85rem 1rem;
  background: var(--docku-surface);
  border: 1px solid var(--docku-border);
  border-left: 3px solid var(--docku-border);
  border-radius: var(--docku-radius);
  transition: background var(--docku-dur-fast) var(--docku-ease), border-color var(--docku-dur-fast) var(--docku-ease);
}
.notif-item.notif-unread {
  border-left-color: var(--docku-primary);
  background: color-mix(in srgb, var(--docku-primary) 4%, var(--docku-surface));
}
.notif-item.notif-selected {
  border-left-color: var(--docku-primary-strong, var(--docku-primary));
  background: color-mix(in srgb, var(--docku-primary) 10%, var(--docku-surface));
  box-shadow: 0 0 0 1px var(--docku-primary-soft) inset;
}
.notif-item:hover { background: var(--docku-surface-raised); }
/* When the user has selected the row, hover should not fade the
   selection highlight entirely.  Layer the selected tint on top. */
.notif-item.notif-selected:hover {
  background: color-mix(in srgb, var(--docku-primary) 14%, var(--docku-surface-raised));
}
.notif-icon {
  display: inline-flex; align-items: center; justify-content: center;
  width: 32px; height: 32px;
  border-radius: 50%;
  background: var(--docku-surface-raised);
  color: var(--docku-primary);
  font-size: 1rem;
  flex-shrink: 0;
}
.notif-unread .notif-icon {
  background: var(--docku-primary); color: #fff;
}
.notif-body { min-width: 0; cursor: pointer; }
.notif-row1 {
  display: flex; align-items: center; gap: 0.5rem;
  flex-wrap: wrap; margin-bottom: 0.15rem;
}
.notif-kind {
  display: inline-block;
  padding: 0.1rem 0.5rem;
  border-radius: var(--docku-radius-sm);
  font-size: 0.68rem;
  font-weight: 700;
  text-transform: none;
  letter-spacing: 0.04em;
  background: var(--docku-surface-raised);
  color: var(--docku-text-2);
}
.notif-kind.kind-review_due { background: var(--docku-warning-soft); color: var(--docku-warning-text); }
.notif-kind.kind-approved   { background: var(--docku-success-soft); color: var(--docku-success-text); }
.notif-kind.kind-status     { background: var(--docku-info-soft);    color: var(--docku-info-text); }
.notif-kind.kind-system     { background: #e5e7eb; color: #374151; }
.notif-title {
  font-weight: 600;
  font-size: 0.95rem;
  color: var(--docku-text);
  word-break: break-word;
}
.notif-unread .notif-title { font-weight: 700; }
.notif-message {
  font-size: 0.88rem;
  color: var(--docku-text);
  opacity: 0.9;
  margin: 0.15rem 0 0.25rem;
  word-break: break-word;
}
.notif-meta {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  font-size: 0.78rem;
  color: var(--docku-text-muted);
  flex-wrap: wrap;
}
.notif-link {
  color: var(--docku-primary);
  text-decoration: none;
  font-weight: 600;
}
.notif-link:hover, .notif-link:focus-visible { text-decoration: underline; outline: none; }
.notif-link:focus-visible { box-shadow: 0 0 0 3px var(--docku-primary-soft); }
.notif-actions {
  display: flex; gap: 0.35rem; flex-shrink: 0;
}
.notif-actions button {
  width: 32px; height: 32px; padding: 0;
  display: inline-flex; align-items: center; justify-content: center;
  margin: 0;
  background: transparent;
  border: 1px solid transparent;
  border-radius: var(--docku-radius-sm);
  color: var(--docku-text-muted);
  cursor: pointer;
}
.notif-actions button:hover {
  background: var(--docku-surface-raised);
  border-color: var(--docku-border);
  color: var(--docku-text);
}
.notif-actions button .fa { font-size: 0.82rem; line-height: 1; }

/* ── Bulk-select checkbox ───────────────────────────────────────
   A 18×18px custom-styled checkbox on the left side of every
   notification card.  Wrapped in a <label> so clicking the box
   toggles the selection (the input itself is a hidden native
   checkbox for accessibility). */
.notif-checkbox {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  margin: 7px 0 0 0;
  cursor: pointer;
  flex-shrink: 0;
  position: relative;
}
.notif-checkbox input[type="checkbox"] {
  appearance: none;
  -webkit-appearance: none;
  width: 18px;
  height: 18px;
  margin: 0;
  border: 1.5px solid var(--docku-border-strong);
  border-radius: 3px;
  background: var(--docku-surface);
  cursor: pointer;
  display: grid;
  place-content: center;
  transition: background var(--docku-dur-fast) var(--docku-ease),
              border-color var(--docku-dur-fast) var(--docku-ease);
}
.notif-checkbox input[type="checkbox"]:hover {
  border-color: var(--docku-primary);
}
.notif-checkbox input[type="checkbox"]:focus-visible {
  outline: 2px solid var(--docku-primary);
  outline-offset: 2px;
}
.notif-checkbox input[type="checkbox"]:checked {
  background: var(--docku-primary);
  border-color: var(--docku-primary);
}
.notif-checkbox input[type="checkbox"]:checked::after {
  content: "";
  width: 11px;
  height: 6px;
  border: 2px solid #fff;
  border-top: 0;
  border-right: 0;
  transform: rotate(-45deg) translate(1px, -1px);
}

/* ── Sticky bulk-actions bar ───────────────────────────────────
   Slides up from the bottom whenever at least one row is
   selected.  Sits above the page content with a soft shadow.
   On mobile the action labels collapse to icon-only. */
.bulk-actions-bar {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 1100;
  background: var(--docku-surface);
  border-top: 1px solid var(--docku-border);
  box-shadow: 0 -4px 16px -4px rgba(15, 23, 42, 0.18);
  padding: 0.65rem 1rem;
  animation: bulk-bar-in 0.18s var(--docku-ease-out);
}
@keyframes bulk-bar-in {
  from { transform: translateY(20px); opacity: 0; }
  to   { transform: translateY(0);    opacity: 1; }
}
.bulk-actions-inner {
  max-width: var(--docku-page-max, 1200px);
  margin: 0 auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
}
.bulk-actions-count {
  font-size: 0.9rem;
  color: var(--docku-text);
  white-space: nowrap;
}
.bulk-actions-count strong {
  color: var(--docku-primary);
  font-weight: 700;
}
.bulk-actions-scope {
  color: var(--docku-text-muted);
  font-size: 0.82rem;
  margin-left: 0.25rem;
}
.bulk-actions-buttons {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  flex-wrap: wrap;
}
.bulk-actions-buttons .btn {
  padding: 0.4rem 0.7rem;
  font-size: 0.85rem;
  border-radius: var(--docku-radius-sm);
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
}
.bulk-actions-buttons .btn-sm {
  padding: 0.4rem 0.7rem;
}
.bulk-actions-buttons .btn.danger {
  color: var(--docku-danger);
}
.bulk-actions-buttons .btn.danger:hover {
  background: var(--docku-danger-soft, rgba(220, 53, 69, 0.08));
  border-color: var(--docku-danger);
  color: var(--docku-danger);
}
.bulk-actions-buttons .btn:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}
/* The bar is fixed — the .bulk-actions-spacer below adds bottom
   padding to the notifications feed so the last row isn't hidden
   behind the bar. */
.bulk-actions-spacer {
  height: 70px;
}

@media (max-width: 640px) {
  .notif-item { grid-template-columns: auto auto 1fr; }
  .notif-actions { grid-column: 1 / -1; justify-content: flex-end; }
  /* On narrow screens the bar collapses: keep the count and the
     most-used actions visible (mark read, delete, clear), hide
     the labels on the others. */
  .bulk-actions-inner {
    flex-direction: column;
    align-items: stretch;
    gap: 0.5rem;
  }
  .bulk-actions-count {
    text-align: center;
  }
  .bulk-actions-buttons {
    justify-content: center;
  }
}

/* ── 19. Status timeline (DocumentView) ────────────────────── */
.status-timeline {
  display: flex;
  align-items: center;
  gap: 0;
  padding: var(--docku-space-4) 0;
  overflow-x: auto;
}
.status-step {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.4rem;
  min-width: 80px;
  flex: 1;
  position: relative;
}
.status-step-dot {
  width: 32px; height: 32px;
  border-radius: 50%;
  background: var(--docku-surface-raised);
  border: 2px solid var(--docku-border);
  color: var(--docku-text-muted);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 0.78rem;
  font-weight: 700;
  z-index: 1;
  position: relative;
  transition: background var(--docku-dur) var(--docku-ease), border-color var(--docku-dur) var(--docku-ease), color var(--docku-dur) var(--docku-ease);
}
.status-step-label {
  font-size: 0.74rem;
  font-weight: 600;
  text-transform: none;
  letter-spacing: 0.05em;
  color: var(--docku-text-muted);
}
.status-step.is-done .status-step-dot {
  background: var(--docku-success);
  border-color: var(--docku-success);
  color: #fff;
}
.status-step.is-active .status-step-dot {
  background: var(--docku-primary);
  border-color: var(--docku-primary);
  color: #fff;
  box-shadow: 0 0 0 4px var(--docku-primary-soft);
}
.status-step.is-active .status-step-label { color: var(--docku-primary); }
.status-step:not(:last-child)::after {
  content: '';
  position: absolute;
  top: 16px;
  left: calc(50% + 18px);
  right: calc(-50% + 18px);
  height: 2px;
  background: var(--docku-border);
  z-index: 0;
}
.status-step.is-done:not(:last-child)::after { background: var(--docku-success); }

/* ── 20. Login screen (split-panel, mobile-first) ──────────── */
.auth-shell {
  display: flex;
  align-items: center;
  justify-content: center;
  /* 100svh avoids the iOS/Android viewport jump when the on-screen
     keyboard opens — 100vh includes the area the keyboard covers. */
  min-height: 100vh;
  min-height: 100svh;
  padding: var(--docku-space-5);
  background: linear-gradient(135deg, #eff6ff 0%, #dbeafe 50%, #f1f5f9 100%);
}
[data-theme="dark"] .auth-shell {
  background: linear-gradient(135deg, #0b1220 0%, #111a2c 50%, #0a1019 100%);
}

/* Split layout: brand hero on the left, form on the right.
   Below 880px it stacks to a single column — the hero becomes a
   compact strip above the card, so both modes carry the same blue
   brand box. */
.auth-panel {
  display: grid;
  grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr);
  width: 100%;
  max-width: 1040px;
  background: var(--docku-surface);
  border: 1px solid var(--docku-border);
  border-radius: var(--docku-radius-xl);
  box-shadow: var(--docku-shadow-lg);
  overflow: hidden;
}

/* Brand hero — a simple blue panel with the favicon-style logo, the
   app name and a plain "Login" line, centered.  Rendered on every
   viewport so mobile and desktop look the same. */
.auth-hero {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--docku-space-3);
  padding: var(--docku-space-8) var(--docku-space-6);
  text-align: center;
  color: #fff;
  background: linear-gradient(150deg, var(--docku-primary-dark) 0%, var(--docku-primary) 60%, #4f8ef7 100%);
  overflow: hidden;
}
[data-theme="dark"] .auth-hero {
  background: linear-gradient(150deg, #0b1220 0%, #1d4ed8 130%);
}
/* Soft decorative highlights (static; kept subtle). */
.auth-hero::before,
.auth-hero::after {
  content: "";
  position: absolute;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.08);
  pointer-events: none;
}
.auth-hero::before { width: 220px; height: 220px; top: -80px; right: -60px; }
.auth-hero::after  { width: 160px; height: 160px; bottom: -60px; left: -50px; }
.auth-hero-logo {
  width: 56px;
  height: 56px;
  border-radius: 14px;
  background: rgba(255, 255, 255, 0.14);
  border: 1px solid rgba(255, 255, 255, 0.22);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}
/* The hero logo doubles as a link back to the public home page. */
a.auth-hero-logo {
  color: inherit;
  text-decoration: none;
  cursor: pointer;
  transition: background 0.15s ease, transform 0.15s ease;
}
a.auth-hero-logo:hover {
  background: rgba(255, 255, 255, 0.24);
  transform: translateY(-2px);
}
a.auth-hero-logo:focus-visible {
  outline: 2px solid rgba(255, 255, 255, 0.85);
  outline-offset: 2px;
}
.auth-hero-title {
  font-size: 1.35rem;
  font-weight: 700;
  margin: var(--docku-space-2) 0 0;
  letter-spacing: -0.02em;
}
.auth-hero-tagline {
  margin: 0;
  font-size: 0.9rem;
  color: rgba(255, 255, 255, 0.78);
}

/* Right-hand form pane.  The inner card loses its own chrome so the
   panel reads as a single surface on desktop. */
.auth-pane {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--docku-space-8) var(--docku-space-10);
}
.auth-panel .auth-card {
  max-width: 380px;
  border: 0;
  box-shadow: none;
  background: transparent;
  padding: 0;
}

/* Standalone card (reset-password + reset-request pages, and the
   stacked mobile layout where the panel acts as the card). */
.auth-card {
  width: 100%;
  max-width: 420px;
  background: var(--docku-surface);
  border: 1px solid var(--docku-border);
  border-radius: var(--docku-radius-xl);
  box-shadow: var(--docku-shadow-lg);
  padding: var(--docku-space-8);
}

/* Stacked layout: below 880px the hero becomes a compact strip above
   the form; the pane carries the padding the card itself would have
   had.  The blue brand box is shared by both layouts. */
@media (max-width: 1024px) {
  .auth-panel {
    grid-template-columns: 1fr;
    max-width: 420px;
  }
  .auth-hero {
    padding: var(--docku-space-6) var(--docku-space-5);
  }
  .auth-pane {
    padding: var(--docku-space-6) var(--docku-space-5);
  }
}
@media (max-width: 480px) {
  .auth-shell { padding: var(--docku-space-3); }
  .auth-panel { border-radius: var(--docku-radius); }
  .auth-hero { padding: var(--docku-space-5) var(--docku-space-4); }
  .auth-pane { padding: var(--docku-space-5) var(--docku-space-4); }
}

/* Caps Lock warning under the password field. */
.auth-caps-hint {
  margin: var(--docku-space-2) 0 0;
  font-size: 0.8rem;
  color: #b45309;
  display: flex;
  align-items: center;
  gap: 0.4rem;
}
[data-theme="dark"] .auth-caps-hint { color: #fbbf24; }
.auth-brand {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  margin-bottom: var(--docku-space-6);
}
.auth-brand-logo {
  width: 56px;
  height: 56px;
  border-radius: 14px;
  background: linear-gradient(135deg, var(--docku-primary) 0%, var(--docku-primary-dark) 100%);
  color: #fff;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 1.6rem;
  box-shadow: var(--docku-shadow-primary);
  margin-bottom: var(--docku-space-3);
}
.auth-brand-name {
  font-size: 1.4rem;
  font-weight: 700;
  color: var(--docku-text);
  margin: 0;
  letter-spacing: -0.02em;
}
.auth-brand-tagline {
  font-size: 0.88rem;
  color: var(--docku-text-muted);
  margin: 0.25rem 0 0;
}
.auth-card .field { margin-bottom: var(--docku-space-4); }
.auth-card .btn { margin-top: var(--docku-space-2); }
.auth-card .auth-error {
  background: var(--docku-danger-soft);
  color: var(--docku-danger-text);
  border: 1px solid #fecaca;
  border-radius: var(--docku-radius);
  padding: 0.65rem 0.85rem;
  font-size: 0.88rem;
  margin-bottom: var(--docku-space-4);
  display: flex;
  align-items: center;
  gap: 0.5rem;
}
.auth-card .auth-hint {
  margin-top: var(--docku-space-5);
  text-align: center;
  font-size: 0.82rem;
  color: var(--docku-text-muted);
}

/* Unified "footer area" used by Login + ResetRequest. */
.auth-foot {
  margin-top: var(--docku-space-5);
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--docku-space-2);
  font-size: 0.85rem;
  color: var(--docku-text-muted);
}

/* Inline link button — used for "Forgot password?", "Back to sign in". */
.auth-link {
  background: none;
  border: 0;
  padding: 0;
  color: var(--docku-primary);
  cursor: pointer;
  font: inherit;
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
}
.auth-link:hover { text-decoration: underline; }
.auth-link:disabled,
.auth-link[disabled] {
  color: var(--docku-text-muted);
  cursor: not-allowed;
  text-decoration: none;
}

/* "Forgot password?" row — centered now that the kbd hint is gone. */
.auth-forgot {
  margin-top: var(--docku-space-3);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.85rem;
}

/* 429 / lockout countdown chip (lives inside an .app-banner.warn). */
.auth-countdown {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-bottom: var(--docku-space-4);
}
.auth-countdown strong {
  font-variant-numeric: tabular-nums;
  font-weight: 600;
}

/* One-time-code (OTP) entry — shared by the sign-in step
   (TwoFactorVerify.js) and the Profile enrollment card so the same
   action looks the same in both places.  The digits are centred with
   tabular figures; the trailing letter-space is offset by an equal
   extra left padding so the code stays optically centred. */
.otp-input {
  text-align: center;
  letter-spacing: 0.35em;
  padding-left: calc(0.85rem + 0.35em);
  font-variant-numeric: tabular-nums;
  font-size: 1.05rem;
  font-weight: 600;
}
.otp-input::placeholder { font-weight: 400; }

/* Inline action row inside a form body.  `.form-action-bar` is the
   bottom-of-page bar; this in-card variant carries its own top margin. */
.form-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: flex-end;
  gap: var(--docku-space-2);
  margin-top: var(--docku-space-4);
}
.form-actions.is-centered { justify-content: center; }

/* Centred link row on the two-factor sign-in step. */
.auth-2fa-actions {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--docku-space-2);
  margin-top: var(--docku-space-4);
  font-size: 0.80em;
}
/* Match the weight/tracking of the .field-label ("Verification code")
   directly above this row; the family is already the app system stack. */
.auth-2fa-actions .auth-link {
  font-weight: 600;
  letter-spacing: 0.04em;
}

/* Card entrance animation — disabled for users who opted out of motion. */
@keyframes authCardIn {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: no-preference) {
  .auth-card { animation: authCardIn 0.25s ease-out; }
}

/* Inline form field hint (success/error). */
.field-hint {
  margin: 0.4rem 0 0;
  font-size: 0.82rem;
  display: flex;
  align-items: center;
  gap: 0.35rem;
}
.field-hint.error { color: var(--docku-danger-text, #b91c1c); }

/* 4-segment password-strength meter used by ResetPassword.js. */
.password-strength {
  display: flex;
  align-items: center;
  gap: 4px;
  margin-top: 0.5rem;
}
.password-strength-bar {
  flex: 1;
  height: 4px;
  border-radius: 2px;
  background: var(--docku-border);
  transition: background-color 0.15s ease;
}
.password-strength[data-score="1"] .password-strength-bar:nth-child(-n+1) { background: var(--docku-danger, #ef4444); }
.password-strength[data-score="2"] .password-strength-bar:nth-child(-n+2) { background: var(--docku-warning, #f59e0b); }
.password-strength[data-score="3"] .password-strength-bar:nth-child(-n+3) { background: var(--docku-info, #3b82f6); }
.password-strength[data-score="4"] .password-strength-bar:nth-child(-n+4) { background: var(--docku-success, #10b981); }
.password-strength-label {
  font-size: 0.78rem;
  color: var(--docku-text-muted);
  min-width: 4.5em;
  text-align: right;
}

/* ── 21. Tabs (Settings, UserView) ─────────────────────────── */
.tabs {
  display: flex;
  gap: 0.25rem;
  border-bottom: 1px solid var(--docku-border);
  margin-bottom: var(--docku-space-5);
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}
.tab {
  background: transparent;
  border: none;
  padding: 0.7rem 1rem;
  font-size: 0.92rem;
  font-weight: 600;
  color: var(--docku-text-muted);
  cursor: pointer;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
  white-space: nowrap;
  font-family: inherit;
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  transition: color var(--docku-dur-fast) var(--docku-ease), border-color var(--docku-dur-fast) var(--docku-ease);
}
.tab:hover { color: var(--docku-text); }
.tab.is-active {
  color: var(--docku-primary);
  border-bottom-color: var(--docku-primary);
}

/* ── System status (Settings → System, APP-006) ─────────────── */
/* The tab's health pill reuses the semantic -soft/-text token pairs the
   document-status pills use, so no new colours enter the sheet, and the
   heading's pill is pushed right by a rule rather than an inline style
   (JS inline styles are ratcheted). */
.system-status-title > .status-pill { margin-left: auto; }
.status-pill.ok          { background: var(--docku-success-soft); color: var(--docku-success-text); }
.status-pill.degraded    { background: var(--docku-warning-soft); color: var(--docku-warning-text); }
.status-pill.unreachable { background: var(--docku-danger-soft);  color: var(--docku-danger-text); }
.system-status-actions { margin-top: var(--docku-space-5); }

/* ── 22. Sticky action bar (forms on mobile) ───────────────── */
.bottom-action-bar {
  display: none;
}
/* Action-button rows. These containers previously had no rule at all,
   so their sibling buttons rendered flush against each other. */
.form-action-bar,
.empty-state-actions,
.pending-ack-actions,
.modal-dialog-footer {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--docku-space-2);
}
.form-action-bar,
.modal-dialog-footer { justify-content: flex-end; }
.profile-form-actions { display: flex; }
@media (max-width: 768px) {
  .bottom-action-bar {
    display: flex;
    position: sticky;
    bottom: 0;
    left: 0;
    right: 0;
    gap: var(--docku-space-2);
    padding: var(--docku-space-3);
    background: var(--docku-surface);
    border-top: 1px solid var(--docku-border);
    box-shadow: 0 -4px 12px -4px rgba(15, 23, 42, 0.08);
    z-index: 5;
  }
  .bottom-action-bar .btn { flex: 1; }
  .profile-form-actions { display: none; }
}

/* ── 23. EasyMDE tweaks (kept from before) ─────────────────── */
.editor-label {
  font-size: 0.78rem;
  font-weight: 700;
  color: var(--docku-text-muted);
  text-transform: none;
  letter-spacing: 0.04em;
  margin-bottom: 0.35rem;
}
.editor-wrapper {
  display: flex; flex-direction: column;
  height: 380px;
  min-height: 380px;
  max-height: 380px;
  width: 100%;
  overflow: hidden !important;
  border-radius: var(--docku-radius);
  border: 1px solid var(--docku-border);
}
.editor-wrapper .EasyMDEContainer {
  display: flex; flex-direction: column;
  flex: 1 1 auto; min-height: 0; width: 100%;
}
.editor-wrapper .EasyMDEContainer .CodeMirror {
  flex: 1 1 auto !important; height: 100% !important;
  padding: 10px !important; margin: 0 !important;
  border-radius: 0;
}
.editor-wrapper .CodeMirror-scroll {
  flex: 1 1 auto !important; height: 100% !important;
  min-height: 0 !important; max-height: 100% !important;
  overflow-y: auto !important; overflow-x: hidden !important;
}
.editor-wrapper .CodeMirror-vscrollbar { display: block !important; }
.editor-wrapper .CodeMirror-sizer {
  margin-top: 0 !important; padding-top: 0 !important; padding-bottom: 0 !important;
  min-height: 0 !important; top: 0 !important;
}
.editor-wrapper .CodeMirror-lines { margin-top: 0 !important; padding: 4px 0 !important; min-height: 0 !important; }
.editor-wrapper .CodeMirror-sizer > div { top: 0 !important; }
.editor-wrapper .EasyMDEContainer,
.editor-wrapper .CodeMirror,
.editor-wrapper .CodeMirror-scroll,
.editor-wrapper .CodeMirror-vscrollbar { box-sizing: border-box !important; }
.editor-wrapper .CodeMirror-line { padding: 0 4px !important; }
.editor-wrapper .CodeMirror pre.CodeMirror-line,
.editor-wrapper .CodeMirror pre { padding: 0 4px !important; }
.CodeMirror textarea { opacity: 0 !important; }

/* ── 24. Font Awesome 6.5.2 icon guard ────────────────────── */
/* NOTE: keep these attribute selectors token-bounded
   (`[class^="fa-"]` / `[class*=" fa-"]`).  A bare
   `[class*="fa-"]` is a substring match, so it also matches
   unrelated classes that merely contain the letters "fa-" —
   notably `.auth-2fa-actions`, which it then forced to
   `display:inline-block` (collapsing the flex column into one
   row) and to the icon font (whose lack of Latin glyphs made
   the label text fall back to an all-caps rendering). */
.fa,
[class^="fa-"],
[class*=" fa-"] {
  font-family: 'Font Awesome 6 Free' !important;
  font-style: normal;
  font-weight: 900;
  line-height: 1;
  display: inline-block;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}
.editor-toolbar button,
.editor-toolbar button i,
.editor-toolbar button .fa,
.editor-toolbar button [class^="fa-"],
.editor-toolbar button [class*=" fa-"] {
  color: #373c44 !important;
}
.editor-toolbar button,
.editor-toolbar button i,
.editor-toolbar button span,
.editor-toolbar button:before,
.editor-toolbar button .fa,
.editor-toolbar button [class^="fa-"],
.editor-toolbar button [class*=" fa-"] {
  font-family: 'Font Awesome 6 Free' !important;
}
.editor-toolbar button > .fa:before,
.editor-toolbar button > [class^="fa-"]:before,
.editor-toolbar button > [class*=" fa-"]:before,
.editor-toolbar button > span.fa:before,
.editor-toolbar button > span [class^="fa-"]:before,
.editor-toolbar button > span [class*=" fa-"]:before {
  font-family: 'Font Awesome 6 Free' !important;
  font-style: normal; font-weight: 900;
  display: inline-block; text-decoration: none;
}
.editor-toolbar button > .fa,
.editor-toolbar button > span { font-size: 14px; line-height: 1; }

/* Mobile: let the EasyMDE toolbar wrap so it doesn't overflow
   horizontally on narrow phones, and tighten the button hit areas
   to the 44×44 minimum. */
@media (max-width: 640px) {
  .editor-toolbar {
    flex-wrap: wrap;
    padding: 4px;
  }
  .editor-toolbar button {
    min-width: 44px;
    min-height: 44px;
    padding: 0 6px;
  }
  .editor-wrapper .EasyMDEContainer .CodeMirror {
    /* Keep the editing surface readable on phones. */
    min-height: 240px;
  }
}
@media (max-width: 480px) {
  .editor-toolbar {
    padding: 2px;
  }
  .editor-toolbar button {
    /* Even smaller padding keeps 8-10 buttons per row instead of
       forcing a 4-per-row wrap that wastes vertical space. */
    padding: 0 4px;
    min-width: 40px;
  }
}

/* ── 25. Toggle row (checkbox + subtext) ───────────────────── */
.toggle-row {
  display: flex; align-items: flex-start; gap: 0.6rem; flex-wrap: wrap;
}
.toggle-row input[type="checkbox"] {
  margin-top: 0.25rem; flex-shrink: 0;
}
.toggle-row small {
  display: block; flex-basis: 100%;
  margin-top: 0.25rem; margin-left: 1.7rem;
  color: var(--docku-text-muted);
  font-size: 0.85rem;
}

/* ── 26. Legacy pill colors (kept for backward compat) ────── */
.legacy-status-pill { /* legacy class kept for any stragglers */
  display: inline-block; padding: 0.15rem 0.55rem; border-radius: var(--docku-radius-full);
  font-size: 0.78rem; font-weight: 600; background: var(--docku-surface-raised); color: var(--docku-text);
}
.legacy-status-pill.draft    { background: #94a3b8; color: white; }
.legacy-status-pill.editing  { background: var(--docku-warning); color: white; }
.legacy-status-pill.review   { background: var(--docku-info); color: white; }
.legacy-status-pill.active   { background: var(--docku-success); color: white; }
.legacy-status-pill.archived { background: #6b7280; color: white; }

/* ── 27. Responsive layout shell ──────────────────────────── */
@media (max-width: 1024px) {
  .app-topbar-nav { display: none; }
  .app-sidebar { display: none; }
  .app-shell {
    grid-template-columns: 1fr;
    grid-template-areas:
      "topbar"
      "main";
  }
  .hamburger { display: inline-flex; }
  .app-main { padding: var(--docku-space-4) var(--docku-space-4) var(--docku-space-8); }
  .page-header h1 { font-size: 1.35rem; }
  .user-menu-btn .user-menu-info { display: none; }
}

@media (max-width: 640px) {
  .app-topbar { padding: 0 var(--docku-space-3); }
  .app-brand-name { display: none; }
  .stat-grid { grid-template-columns: 1fr; }
  .data-table .col-hide-mobile { display: none; }
  .form-section { padding: var(--docku-space-4); }
  .auth-card { padding: var(--docku-space-5); }
}
/* ============================================================
   Reports page + dashboard analytics (v0.2.0)
   ============================================================ */

/* ── Reports tabs ─────────────────────────────────────────── */
.reports-tabs {
  display: flex;
  gap: var(--docku-space-1);
  border-bottom: 1px solid var(--docku-border);
  margin-bottom: var(--docku-space-4);
  overflow-x: auto;
}
.reports-tab {
  background: transparent;
  border: 0;
  border-bottom: 2px solid transparent;
  padding: var(--docku-space-3) var(--docku-space-4);
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
  font-size: .92rem;
  font-weight: 600;
  color: var(--docku-text-muted);
  cursor: pointer;
  white-space: nowrap;
  transition: color .15s, border-color .15s;
}
.reports-tab:hover { color: var(--docku-text); }
.reports-tab.active {
  color: var(--docku-primary);
  border-bottom-color: var(--docku-primary);
}

/* ── Reports toolbar / filters ────────────────────────────── */
.reports-toolbar {
  display: flex;
  flex-wrap: wrap;
  gap: var(--docku-space-2);
  align-items: end;
  margin-bottom: var(--docku-space-4);
  padding: var(--docku-space-3);
  background: var(--docku-surface);
  border: 1px solid var(--docku-border);
  border-radius: 8px;
}
.reports-toolbar label {
  display: flex;
  flex-direction: column;
  font-size: .78rem;
  color: var(--docku-text-muted);
  gap: 2px;
}
.reports-toolbar select,
.reports-toolbar input {
  padding: 6px 10px;
  border: 1px solid var(--docku-border-strong);
  border-radius: 6px;
  background: var(--docku-surface);
  font-size: .9rem;
  min-width: 140px;
}

/* ── Summary cards (reports) ─────────────────────────────── */
.reports-summary {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: var(--docku-space-3);
  margin-bottom: var(--docku-space-4);
}
.reports-summary-card {
  background: var(--docku-surface);
  border: 1px solid var(--docku-border);
  border-radius: 8px;
  padding: var(--docku-space-4);
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.reports-summary-card .label {
  font-size: .78rem;
  color: var(--docku-text-muted);
  text-transform: none;
  letter-spacing: .04em;
}
.reports-summary-card .value {
  font-size: 1.8rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.reports-summary-card.danger  .value { color: var(--docku-danger); }
.reports-summary-card.warning .value { color: var(--docku-warning-text); }
.reports-summary-card.success .value { color: var(--docku-success-text); }

/* Clickable variant — turns the summary card into a router link with
   hover/focus affordances. Keeps the visual layout intact. */
a.reports-summary-card,
.reports-summary-card.clickable {
  text-decoration: none;
  color: inherit;
  cursor: pointer;
  transition: transform var(--docku-dur) var(--docku-ease),
              box-shadow var(--docku-dur) var(--docku-ease),
              border-color var(--docku-dur) var(--docku-ease);
}
a.reports-summary-card:hover,
.reports-summary-card.clickable:hover,
a.reports-summary-card:focus-visible,
.reports-summary-card.clickable:focus-visible {
  transform: translateY(-1px);
  box-shadow: var(--docku-shadow-xs);
  border-color: var(--docku-primary);
  outline: none;
}
a.reports-summary-card:focus-visible,
.reports-summary-card.clickable:focus-visible {
  box-shadow: 0 0 0 3px var(--docku-primary-soft);
}

/* ── Bar chart (CSS only) ────────────────────────────────── */
.bar-chart {
  display: flex;
  flex-direction: column;
  gap: var(--docku-space-2);
}
.bar-chart.padded {
  padding: var(--docku-space-2) var(--docku-space-3) var(--docku-space-4);
}
.bar-row {
  display: grid;
  grid-template-columns: 160px 1fr 60px;
  align-items: center;
  gap: var(--docku-space-3);
  font-size: .9rem;
}
.bar-label {
  color: var(--docku-text-2);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.bar-track {
  background: var(--docku-surface-sunken);
  border-radius: 4px;
  height: 14px;
  overflow: hidden;
  position: relative;
}
.bar-fill {
  /* Animates `transform` (compositor-only) rather than the layout property
     `width`: the bar is always full-width and scaled from the left edge
     (CSS-001). The value is bound as `transform: scaleX(<fraction>)`. */
  width: 100%;
  height: 100%;
  background: linear-gradient(90deg, var(--docku-primary), var(--docku-primary-light));
  border-radius: 4px;
  transform-origin: left center;
  transition: transform var(--docku-dur) var(--docku-ease);
}
.bar-value {
  text-align: right;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--docku-text);
}

/* Clickable bar-row — turns each status bar into a deep-link to
   the documents library filtered to that status. */
a.bar-row,
.bar-row-link {
  text-decoration: none;
  color: inherit;
  padding: 0.45rem 0.6rem;
  margin: 0 -0.4rem;
  border-radius: 8px;
  transition: background var(--docku-dur) var(--docku-ease), transform var(--docku-dur) var(--docku-ease);
  cursor: pointer;
}
a.bar-row:hover,
.bar-row-link:hover,
a.bar-row:focus-visible,
.bar-row-link:focus-visible {
  background: var(--docku-surface-sunken);
  transform: translateX(2px);
  outline: none;
}
a.bar-row:focus-visible,
.bar-row-link:focus-visible {
  box-shadow: 0 0 0 3px var(--docku-primary-soft);
}
.bar-row-arrow {
  margin-left: 0.45rem;
  color: var(--docku-primary);
  opacity: 0;
  transition: opacity var(--docku-dur) var(--docku-ease);
  font-size: 0.7rem;
}
.bar-row-link:hover .bar-row-arrow,
.bar-row-link:focus-visible .bar-row-arrow {
  opacity: 1;
}
.dashboard-panel-link {
  margin-left: 0.5rem;
  font-weight: 600;
  text-decoration: none;
}
.dashboard-panel-link:hover { text-decoration: underline; }

/* ── Recent activity feed ────────────────────────────────── */
.activity-list {
  --activity-row: 4.5rem;
  display: flex;
  flex-direction: column;
  gap: var(--docku-space-2);
  list-style: none;
  margin: 0;
  max-height: calc(5 * var(--activity-row) + 4 * var(--docku-space-2));
  overflow-y: auto;
  overflow-x: hidden;
  overscroll-behavior: contain;
  padding: 0 var(--docku-space-1) 0 0;
}
.activity-item {
  display: flex;
  align-items: center;
  gap: var(--docku-space-3);
  padding: var(--docku-space-2) var(--docku-space-3);
  background: var(--docku-surface);
  border: 1px solid var(--docku-border);
  border-radius: 6px;
  font-size: .9rem;
}
/* When the whole row is a link, lay it out like the .activity-item
   but with hover affordances. */
.activity-item-link {
  display: flex;
  align-items: center;
  gap: var(--docku-space-3);
  width: 100%;
  padding: var(--docku-space-2) var(--docku-space-3);
  background: var(--docku-surface);
  border: 1px solid var(--docku-border);
  border-radius: 6px;
  font-size: .9rem;
  color: inherit;
  text-decoration: none;
  transition: background var(--docku-dur) var(--docku-ease),
              border-color var(--docku-dur) var(--docku-ease),
              transform var(--docku-dur) var(--docku-ease);
}
.activity-item-link:hover,
.activity-item-link:focus-visible {
  background: var(--docku-surface-sunken);
  border-color: var(--docku-primary);
  transform: translateX(2px);
  outline: none;
}
.activity-item-link:focus-visible {
  box-shadow: 0 0 0 3px var(--docku-primary-soft);
}
.activity-arrow {
  margin-left: 0.5rem;
  color: var(--docku-primary);
  opacity: 0;
  transition: opacity var(--docku-dur) var(--docku-ease);
  font-size: 0.75rem;
}
.activity-item-link:hover .activity-arrow,
.activity-item-link:focus-visible .activity-arrow { opacity: 1; }
.activity-icon {
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background: var(--docku-primary-50);
  color: var(--docku-primary);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: .8rem;
  flex-shrink: 0;
}
.activity-title { flex: 1; min-width: 0; }
.activity-title .ttl {
  display: block;
  color: var(--docku-text);
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.activity-title .sub {
  display: block;
  font-size: .78rem;
  color: var(--docku-text-muted);
}
.activity-meta {
  display: flex;
  align-items: center;
  gap: var(--docku-space-2);
  flex-shrink: 0;
}

/* ── Status chip ─────────────────────────────────────────── */
.status-chip {
  display: inline-block;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: .72rem;
  font-weight: 600;
  text-transform: none;
  letter-spacing: .03em;
  background: var(--docku-surface-sunken);
  color: var(--docku-text-2);
}
.status-chip.draft    { background: var(--docku-surface-sunken); color: var(--docku-text-2); }
.status-chip.editing  { background: var(--docku-info-soft);    color: var(--docku-info-text); }
.status-chip.review   { background: var(--docku-warning-soft); color: var(--docku-warning-text); }
.status-chip.active   { background: var(--docku-success-soft); color: var(--docku-success-text); }
.status-chip.archived { background: var(--docku-surface-sunken); color: var(--docku-text-muted); }

/* ── Days-until-review cell ──────────────────────────────── */
.days-cell {
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}
.days-cell.overdue { color: var(--docku-danger); }
.days-cell.soon    { color: var(--docku-warning); }
.days-cell.ok      { color: var(--docku-text-2); }

/* ============================================================
   Dashboard analytics panels + Reports page header (v0.2.0)
   ============================================================ */

/* ── Page header (Reports page) ──────────────────────────── */
.page-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--docku-space-4);
  padding: var(--docku-space-5);
  margin-bottom: var(--docku-space-4);
}
.page-header-left { min-width: 0; flex: 1; }
.page-header-actions { display: flex; align-items: center; gap: var(--docku-space-2); flex-shrink: 0; }
.page-title {
  display: flex;
  align-items: center;
  gap: var(--docku-space-2);
  font-size: 1.4rem;
  margin: 0 0 var(--docku-space-1) 0;
  color: var(--docku-text);
}
.page-title i { color: var(--docku-primary); }
.page-sub {
  color: var(--docku-text-muted);
  font-size: .9rem;
  margin: 0;
}

/* ── Dashboard analytics layout ─────────────────────────── */
.dashboard-analytics-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--docku-space-4);
  margin-bottom: var(--docku-space-4);
}
.dashboard-analytics-row.first {
  margin-top: var(--docku-space-3);
}
@media (max-width: 1024px) {
  .dashboard-analytics-row { grid-template-columns: 1fr; }
  .dashboard-analytics-row .dashboard-panel + .dashboard-panel { margin-top: var(--docku-space-4); }
  /* .reports-summary is already content-driven (`auto-fit`); the old
     fixed 2-up override (CSS-007) left an orphan column under the
     single-card “My documents” summary. Rely on the base rule. */
}

.dashboard-panel {
  padding: 0;
}
.dashboard-panel .card-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--docku-space-3) var(--docku-space-4);
  border-bottom: 1px solid var(--docku-border);
  gap: var(--docku-space-2);
  min-height: 44px;
}
.dashboard-panel .card-header h3 {
  margin: 0;
  font-size: 1rem;
  display: flex;
  align-items: center;
}
.dashboard-panel .card-header h3 i { color: var(--docku-primary); }
.dashboard-panel .card-header h3 span { margin-left: var(--docku-space-2); }
.card-header-link {
  font-size: .82rem;
  color: var(--docku-primary);
  text-decoration: none;
  font-weight: 500;
}
.card-header-link:hover { text-decoration: underline; }

.dashboard-panel-body {
  padding: var(--docku-space-4) var(--docku-space-4) var(--docku-space-5);
}
.dashboard-panel .reports-summary {
  margin-bottom: var(--docku-space-3);
  gap: var(--docku-space-3);
}
.dashboard-panel .reports-summary-card {
  min-height: 78px;
}
.dashboard-panel-warn {
  display: flex;
  align-items: center;
  gap: var(--docku-space-2);
  margin: var(--docku-space-3) 0 0 0;
  padding: var(--docku-space-2) var(--docku-space-3);
  background: var(--docku-danger-soft);
  color: var(--docku-danger-text);
  border-radius: 6px;
  font-size: .85rem;
}
.dashboard-panel-ok {
  display: flex;
  align-items: center;
  gap: var(--docku-space-2);
  margin: var(--docku-space-3) 0 0 0;
  padding: var(--docku-space-2) var(--docku-space-3);
  background: var(--docku-success-soft);
  color: var(--docku-success-text);
  border-radius: 6px;
  font-size: .85rem;
}

/* ── Empty state (small variant) ─────────────────────────── */
.empty-state-sm {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: var(--docku-space-5) var(--docku-space-4);
  color: var(--docku-text-muted);
  gap: 6px;
}
.empty-state-sm i {
  font-size: 1.8rem;
  color: var(--docku-text-faint);
}
.empty-state-sm p {
  margin: 0;
  font-size: .9rem;
}

/* ── Stat card color variants (overdue / reviews) ────────── */
.stat-card.danger {
  border-left: 3px solid var(--docku-danger);
}
.stat-card.danger .stat-card-icon { background: var(--docku-danger-soft); color: var(--docku-danger); }
.stat-card.success {
  border-left: 3px solid var(--docku-success);
}
.stat-card.success .stat-card-icon { background: var(--docku-success-soft); color: var(--docku-success); }

/* ── Alert (Reports page errors) ────────────────────────── */
.alert {
  display: flex;
  align-items: center;
  gap: var(--docku-space-2);
  padding: var(--docku-space-3) var(--docku-space-4);
  border-radius: 6px;
  margin-bottom: var(--docku-space-3);
  font-size: .9rem;
}
.alert-danger {
  background: var(--docku-danger-soft);
  color: var(--docku-danger-text);
  border: 1px solid var(--docku-danger);
}

/* ── Reports loading placeholder ────────────────────────── */
.reports-loading { padding: var(--docku-space-4); }

/* ── Empty state (general) ──────────────────────────────── */
.empty-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: var(--docku-space-6) var(--docku-space-4);
  color: var(--docku-text-muted);
  gap: var(--docku-space-2);
}
.empty-state i {
  font-size: 2.2rem;
  color: var(--docku-text-faint);
}
.empty-state p {
  margin: 0;
  font-size: .95rem;
}

/* ── Collaborators & approval panel (DocumentView) ────────── */
.collab-panel {
  display: flex;
  flex-direction: column;
  gap: var(--docku-space-3);
}
.collab-summary {
  display: flex;
  flex-wrap: wrap;
  gap: var(--docku-space-2);
  align-items: center;
}
.collab-summary-stat {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.25rem 0.65rem;
  border-radius: var(--docku-radius-full);
  font-size: 0.75rem;
  font-weight: 600;
  background: var(--docku-surface-raised);
  color: var(--docku-text-2);
  border: 1px solid var(--docku-border);
}
.collab-summary-stat .collab-summary-icon {
  font-size: 0.7rem;
  opacity: 0.85;
}
.collab-summary-stat.yes { background: #ecfdf5; color: #047857; border-color: #a7f3d0; }
.collab-summary-stat.no  { background: var(--docku-danger-soft); color: var(--docku-danger-text); border-color: var(--docku-danger); }
.collab-summary-stat.pending { background: var(--docku-warning-soft); color: var(--docku-warning-text); border-color: var(--docku-warning); }
.collab-summary-stat.approved { background: #ecfdf5; color: #047857; border-color: #a7f3d0; }
.collab-summary-stat.rejected { background: var(--docku-danger-soft); color: var(--docku-danger-text); border-color: var(--docku-danger); }
.collab-summary-stat.review   { background: var(--docku-info-soft); color: var(--docku-info-text); border-color: var(--docku-info); }

.collab-list {
  display: flex;
  flex-direction: column;
  gap: var(--docku-space-2);
}
.collab-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--docku-space-2);
  padding: 0.55rem 0.75rem;
  border: 1px solid var(--docku-border);
  border-radius: 8px;
  background: var(--docku-surface);
}
.collab-row .collab-user {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  font-weight: 600;
  color: var(--docku-text);
  flex: 1 1 160px;
  min-width: 0;
}
.collab-row .collab-username {
  display: block;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.collab-row .collab-inviter {
  display: block;
  color: var(--docku-text-muted);
  font-size: 0.8rem;
  font-weight: 400;
}
.role-pill {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  padding: 0.15rem 0.55rem;
  border-radius: var(--docku-radius-full);
  font-size: 0.7rem;
  font-weight: 700;
  text-transform: none;
  letter-spacing: 0.04em;
  background: var(--docku-surface-raised);
  color: var(--docku-text-2);
}
.role-pill::before {
  content: "";
  width: 6px; height: 6px; border-radius: 50%;
  background: currentColor;
  opacity: 0.7;
}
.role-pill.viewer   { background: #e0e7ff; color: #3730a3; }
.role-pill.editor   { background: var(--docku-info-soft); color: var(--docku-info-text); }
.role-pill.approver { background: #fef3c7; color: #92400e; }
.vote-pill {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  padding: 0.15rem 0.55rem;
  border-radius: var(--docku-radius-full);
  font-size: 0.7rem;
  font-weight: 700;
  text-transform: none;
  letter-spacing: 0.04em;
}
.vote-pill.yes    { background: #ecfdf5; color: #047857; }
.vote-pill.no     { background: var(--docku-danger-soft); color: var(--docku-danger-text); }
.vote-pill.pending { background: var(--docku-warning-soft); color: var(--docku-warning-text); }

.collab-actions {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  flex-wrap: wrap;
}
.collab-actions select {
  font-size: 0.78rem;
  padding: 0.2rem 0.4rem;
  border-radius: 6px;
  border: 1px solid var(--docku-border);
  background: var(--docku-surface);
  color: var(--docku-text);
}

/* ── Pending collaborator badges (edit mode) ──────────────── */
.pending-badge {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  padding: 0.15rem 0.55rem;
  border-radius: var(--docku-radius-full);
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  border: 1px solid transparent;
  white-space: nowrap;
}
.pending-badge .fa { font-size: 0.7rem; }
.pending-badge.pending-add    { background: var(--docku-warning-soft); color: var(--docku-warning-text); border-color: var(--docku-warning); }
.pending-badge.pending-role   { background: var(--docku-info-soft);    color: var(--docku-info-text);    border-color: var(--docku-info); }
.pending-badge.pending-remove { background: var(--docku-danger-soft);  color: var(--docku-danger-text);  border-color: var(--docku-danger); }

/* ── Dirty indicator on Save buttons ───────────────────────── */
.btn-dirty-dot {
  display: inline-block;
  width: 0.55em;
  height: 0.55em;
  margin-left: 0.45em;
  border-radius: 50%;
  background: #fde68a;
  box-shadow: 0 0 0 2px rgba(253, 230, 138, 0.35);
  animation: btn-dirty-pulse 1.6s ease-in-out infinite;
  vertical-align: middle;
}
@keyframes btn-dirty-pulse {
  0%, 100% { box-shadow: 0 0 0 2px rgba(253, 230, 138, 0.35); }
  50%      { box-shadow: 0 0 0 5px rgba(253, 230, 138, 0.10); }
}

.collab-add-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--docku-space-2);
  align-items: center;
  padding: 0.55rem 0.75rem;
  border: 1px dashed var(--docku-border);
  border-radius: 8px;
  background: var(--docku-surface);
}
.collab-add-row select,
.collab-add-row input {
  font-size: 0.85rem;
}
.collab-add-row .collab-add-select {
  flex: 1 1 200px;
  min-width: 160px;
}
.collab-add-row .collab-add-picker {
  flex: 1 1 200px;
  min-width: 160px;
  min-width: 0;
}
.collab-add-row .collab-add-role {
  flex: 0 0 auto;
}

.collab-vote-area {
  display: flex;
  flex-direction: column;
  gap: var(--docku-space-2);
  padding: 0.75rem;
  border-radius: 8px;
  background: var(--docku-surface-raised);
  border: 1px solid var(--docku-border);
}
.collab-vote-area-title {
  font-weight: 600;
  color: var(--docku-text);
  display: flex;
  align-items: center;
  gap: 0.4rem;
}
.collab-vote-area-textarea {
  width: 100%;
  min-height: 60px;
  padding: 0.45rem 0.6rem;
  border-radius: 6px;
  border: 1px solid var(--docku-border);
  background: var(--docku-surface);
  color: var(--docku-text);
  font-family: inherit;
  font-size: 0.9rem;
  resize: vertical;
}
.collab-vote-buttons {
  display: flex;
  gap: 0.5rem;
  flex-wrap: wrap;
}

.collab-help {
  color: var(--docku-text-muted);
  font-size: 0.85rem;
  display: flex;
  align-items: center;
  gap: 0.4rem;
}

/* ── Approval badge (DocumentList) ───────────────────────── */
.approval-pill {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  padding: 0.15rem 0.55rem;
  border-radius: var(--docku-radius-full);
  font-size: 0.7rem;
  font-weight: 700;
  text-transform: none;
  letter-spacing: 0.04em;
  margin-left: 0.35rem;
  background: var(--docku-surface-raised);
  color: var(--docku-text-2);
  border: 1px solid var(--docku-border);
}
.approval-pill.approved { background: #ecfdf5; color: #047857; border-color: #a7f3d0; }
.approval-pill.rejected { background: var(--docku-danger-soft); color: var(--docku-danger-text); border-color: var(--docku-danger); }
.approval-pill.pending  { background: var(--docku-warning-soft); color: var(--docku-warning-text); border-color: var(--docku-warning); }

/* "Review requested" pill — shown on document rows where the current
   user has an outstanding acknowledgment invite. Amber/orange to stand
   apart from the document-status and approval pills. */
.ack-pill {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  padding: 0.15rem 0.55rem;
  border-radius: var(--docku-radius-full);
  font-size: 0.7rem;
  font-weight: 700;
  text-transform: none;
  letter-spacing: 0.04em;
  margin-left: 0.35rem;
  background: #fff7ed;
  color: #b45309;
  border: 1px solid #fcd34d;
}
.ack-pill .fa { font-size: 0.65rem; }

/* ── Quick actions grid (Dashboard) ───────────────────────── */
.dashboard > .quick-actions {
  margin-top: var(--docku-space-6);
}
.quick-actions .card-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--docku-space-3) var(--docku-space-5);
  border-bottom: 1px solid var(--docku-border);
}
.quick-actions .card-header h3 {
  margin: 0;
  font-size: 1.05rem;
  font-weight: 600;
  color: var(--docku-text);
}
.quick-actions-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: var(--docku-space-4);
  padding: var(--docku-space-5);
  justify-items: stretch;
  align-items: stretch;
}
.quick-action {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: var(--docku-space-2);
  padding: var(--docku-space-5);
  background: var(--docku-surface);
  border: 1px solid var(--docku-border);
  border-radius: var(--docku-radius-lg);
  box-shadow: var(--docku-shadow-xs);
  font-family: inherit;
  color: var(--docku-text);
  cursor: pointer;
  position: relative;
  transition: box-shadow var(--docku-dur) var(--docku-ease),
              transform var(--docku-dur) var(--docku-ease),
              border-color var(--docku-dur) var(--docku-ease);
  min-height: 120px;
  height: 100%;
}
.quick-action > .fa,
.quick-action > [class^="fa-"],
.quick-action > [class*=" fa-"] {
  font-size: 1.4rem;
  color: var(--docku-primary);
  background: var(--docku-primary-50);
  width: 40px;
  height: 40px;
  border-radius: var(--docku-radius);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  margin-bottom: var(--docku-space-1);
  transition: background var(--docku-dur) var(--docku-ease),
              color var(--docku-dur) var(--docku-ease);
}
.quick-action-label {
  font-size: 0.95rem;
  font-weight: 600;
  color: var(--docku-text);
  line-height: 1.2;
}
.quick-action-desc {
  font-size: 0.82rem;
  color: var(--docku-text-muted);
  line-height: 1.4;
}
.quick-action:hover {
  box-shadow: var(--docku-shadow);
  transform: translateY(-2px);
  border-color: var(--docku-primary-soft);
}
.quick-action:hover > .fa,
.quick-action:hover > [class^="fa-"],
.quick-action:hover > [class*=" fa-"] {
  background: var(--docku-primary);
  color: #fff;
}
.quick-action:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px var(--docku-primary-soft);
  border-color: var(--docku-primary);
}
.quick-action:active {
  transform: translateY(0);
}
@media (max-width: 640px) {
  .quick-actions-grid {
    grid-template-columns: 1fr;
    padding: var(--docku-space-4);
    gap: var(--docku-space-3);
  }
  .quick-action { min-height: 0; padding: var(--docku-space-4); }
}

/* ── Dashboard layout & vertical rhythm ───────────────────── */
.dashboard {
  display: flex;
  flex-direction: column;
  gap: var(--docku-space-5);
}
.dashboard > * { margin-bottom: 0; }

/* Greeting hero */
.dashboard-greeting {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--docku-space-5);
  padding: var(--docku-space-6);
  background:
    radial-gradient(circle at top right, var(--docku-primary-50) 0%, transparent 60%),
    var(--docku-surface);
}
.dashboard-greeting-left { min-width: 0; flex: 1; }
.dashboard-greeting-eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  margin: 0 0 var(--docku-space-2);
  font-size: 0.8rem;
  font-weight: 600;
  text-transform: none;
  letter-spacing: 0.05em;
  color: var(--docku-text-muted);
}
.dashboard-greeting-eyebrow .fa { color: var(--docku-primary); }
.dashboard-greeting-title {
  margin: 0 0 var(--docku-space-2);
  font-size: 1.55rem;
  font-weight: 700;
  letter-spacing: -0.015em;
  color: var(--docku-text);
}
.dashboard-greeting-name { color: var(--docku-primary); }
.dashboard-greeting-sub {
  margin: 0;
  color: var(--docku-text-muted);
  font-size: 0.95rem;
}
.dashboard-greeting-actions {
  display: flex;
  align-items: center;
  gap: var(--docku-space-3);
  flex-shrink: 0;
  flex-wrap: wrap;
  justify-content: flex-end;
}
@media (max-width: 768px) {
  .dashboard-greeting {
    flex-direction: column;
    align-items: flex-start;
    padding: var(--docku-space-5);
  }
  .dashboard-greeting-actions { width: 100%; }
  .dashboard-greeting-actions .btn { flex: 1; }
}

/* ── Content type tabs (DocumentCreate) ────────────────── */
.content-type-tabs {
  display: flex;
  gap: 2px;
  padding: 4px;
  margin: 0 var(--docku-space-5);
  margin-top: var(--docku-space-4);
  background: var(--docku-surface-sunken);
  border: 1px solid var(--docku-border);
  border-radius: var(--docku-radius);
  width: fit-content;
  max-width: calc(100% - var(--docku-space-10));
  overflow-x: auto;
}
.content-type-tab {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.5rem 0.95rem;
  background: transparent;
  border: 0;
  border-radius: calc(var(--docku-radius) - 4px);
  color: var(--docku-text-muted);
  font-family: inherit;
  font-size: 0.88rem;
  font-weight: 600;
  cursor: pointer;
  white-space: nowrap;
  transition: background var(--docku-dur-fast) var(--docku-ease),
              color var(--docku-dur-fast) var(--docku-ease);
}
.content-type-tab:hover:not(.is-active) {
  color: var(--docku-text);
  background: var(--docku-surface);
}
.content-type-tab.is-active {
  background: var(--docku-surface);
  color: var(--docku-primary);
  box-shadow: var(--docku-shadow-xs);
}
.content-type-tab .fa {
  font-size: 0.95rem;
  color: inherit;
  opacity: 0.85;
}
.content-type-tab-label { line-height: 1; }

.content-type-panel {
  padding: var(--docku-space-5);
}
.content-type-panel .field-hint {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  margin: var(--docku-space-3) 0 0;
  color: var(--docku-text-muted);
  font-size: 0.82rem;
}

/* Three independently-toggleable content sections (DocumentCreate) */
.content-active-summary {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--docku-space-2);
  padding: var(--docku-space-3) var(--docku-space-5);
  border-bottom: 1px dashed var(--docku-border);
  background: var(--docku-surface-raised);
}
.content-active-summary-label {
  font-size: 0.78rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--docku-text-muted);
}
.content-toggle-section {
  border-top: 1px solid var(--docku-border);
}
.content-toggle-section:first-of-type {
  border-top: none;
}
.content-toggle-header {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: var(--docku-space-3);
  padding: var(--docku-space-4) var(--docku-space-5);
  cursor: pointer;
  user-select: none;
  margin: 0;
  font-weight: 400;
}
.content-toggle-header:hover {
  background: var(--docku-surface-raised);
}
.content-toggle-header input[type="checkbox"] {
  width: 18px;
  height: 18px;
  margin: 0;
  cursor: pointer;
}
.content-toggle-header > .fa {
  color: var(--docku-primary);
  font-size: 1rem;
}
.content-toggle-title {
  font-weight: 600;
  color: var(--docku-text);
}
.content-toggle-hint {
  font-size: 0.82rem;
  color: var(--docku-text-muted);
  grid-column: 3;
  text-align: right;
}
.content-toggle-panel {
  padding: 0 var(--docku-space-5) var(--docku-space-5);
  border-top: 1px dashed var(--docku-border);
  padding-top: var(--docku-space-4);
  margin-top: 0;
}
@media (max-width: 640px) {
  .content-toggle-header {
    grid-template-columns: auto 1fr;
    grid-template-rows: auto auto;
  }
  .content-toggle-hint {
    grid-column: 1 / -1;
    text-align: left;
  }
}

/* File upload dropzone */
.content-file-input {
  position: absolute;
  width: 1px; height: 1px;
  opacity: 0;
  pointer-events: none;
}
.content-upload-empty,
.content-upload-success {
  display: flex;
  align-items: center;
  gap: var(--docku-space-4);
  padding: var(--docku-space-5);
  border: 1.5px dashed var(--docku-border-strong);
  border-radius: var(--docku-radius-lg);
  background: var(--docku-surface-raised);
  transition: border-color var(--docku-dur-fast) var(--docku-ease),
              background var(--docku-dur-fast) var(--docku-ease);
}
.content-upload-empty.is-loading { opacity: 0.75; }
.content-upload-empty:hover { border-color: var(--docku-primary); background: var(--docku-surface); }
.content-upload-success {
  border-style: solid;
  border-color: var(--docku-success);
  background: var(--docku-success-soft);
}
.content-upload-icon {
  width: 52px; height: 52px;
  border-radius: var(--docku-radius);
  background: var(--docku-surface);
  color: var(--docku-primary);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 1.3rem;
  flex-shrink: 0;
  border: 1px solid var(--docku-border);
}
.content-upload-icon.is-success {
  background: var(--docku-success);
  color: #fff;
  border-color: var(--docku-success);
}
.content-upload-text { min-width: 0; flex: 1; }
.content-upload-text strong {
  display: block;
  color: var(--docku-text);
  font-size: 0.95rem;
  font-weight: 600;
  margin-bottom: 0.2rem;
  word-break: break-word;
}
.content-upload-text span {
  display: block;
  color: var(--docku-text-muted);
  font-size: 0.85rem;
  line-height: 1.4;
}

/* External link field */
.content-link-field { display: flex; flex-direction: column; gap: 0.35rem; margin: 0; }
.content-link-input-wrap {
  position: relative;
  display: flex;
  align-items: center;
}
.content-link-icon {
  position: absolute;
  left: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 100%;
  color: var(--docku-text-muted);
  font-size: 0.95rem;
  pointer-events: none;
}
.content-link-input {
  width: 100%;
  min-height: 44px;
  padding: 0.55rem 0.85rem 0.55rem 2.5rem;
  font-size: 0.95rem;
  font-family: inherit;
  color: var(--docku-text);
  background: var(--docku-surface);
  border: 1px solid var(--docku-border);
  border-radius: var(--docku-radius);
  transition: border-color var(--docku-dur-fast) var(--docku-ease),
              box-shadow var(--docku-dur-fast) var(--docku-ease);
  margin: 0;
}
.content-link-input:focus {
  outline: none;
  border-color: var(--docku-primary);
  box-shadow: 0 0 0 3px var(--docku-primary-soft);
}
.content-link-input.is-invalid {
  border-color: var(--docku-danger);
  box-shadow: 0 0 0 3px var(--docku-danger-soft);
}
.content-link-warn {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  margin-top: 0.35rem;
  color: var(--docku-danger);
  font-weight: 600;
}
.content-link-warn code {
  background: var(--docku-surface-raised);
  padding: 1px 5px;
  border-radius: 4px;
  font-size: 0.78rem;
  color: var(--docku-danger-text);
}

/* ── Multi-tab content editor (DocumentCreate + DocumentView edit) ──
 * Each payload kind (markdown / file / URL) renders as a labelled
 * "tab header" with an inline tickbox, plus a collapsible panel below.
 * All three panels are visible simultaneously when their tickboxes are
 * on; the user never loses context to single-body tab switching.
 * The pill nav at the top of the section is sticky so it stays
 * reachable while scrolling through long markdown bodies.
 */
.content-section {
  overflow: visible;
}

/* ── Sticky pill nav ─────────────────────────────────── */
.content-tab-nav {
  position: sticky;
  top: 0;
  z-index: 5;
  display: flex;
  align-items: center;
  gap: var(--docku-space-3);
  padding: var(--docku-space-3) var(--docku-space-5);
  background: var(--docku-surface, #fff);
  border-bottom: 1px solid var(--docku-border);
  flex-wrap: wrap;
}
.content-tab-nav-label {
  font-size: 0.75rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--docku-text-muted);
  flex-shrink: 0;
}
.content-tab-nav-pills {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  flex: 1 1 auto;
  min-width: 0;
}
.content-tab-pill {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.35rem 0.85rem;
  border: 1px solid var(--docku-border, #e2e8f0);
  background: var(--docku-surface-raised, #f8fafc);
  color: var(--docku-text-muted, #475569);
  border-radius: 999px;
  cursor: pointer;
  font: inherit;
  font-size: 0.85rem;
  font-weight: 500;
  white-space: nowrap;
  transition:
    background var(--docku-dur-fast, 0.15s) var(--docku-ease, ease),
    border-color var(--docku-dur-fast, 0.15s) var(--docku-ease, ease),
    color var(--docku-dur-fast, 0.15s) var(--docku-ease, ease);
}
.content-tab-pill:hover {
  border-color: var(--docku-primary, #2563eb);
  color: var(--docku-text, #0f172a);
  background: var(--docku-surface, #fff);
}
.content-tab-pill.is-active {
  background: var(--docku-primary-soft, rgba(37, 99, 235, 0.12));
  border-color: var(--docku-primary, #2563eb);
  color: var(--docku-primary, #2563eb);
  font-weight: 600;
}
.content-tab-pill .fa {
  font-size: 0.85rem;
  opacity: 0.85;
}
.content-tab-pill-dot {
  display: inline-block;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: currentColor;
  margin-left: 0.1rem;
}

/* ── Tab stack ───────────────────────────────────────── */
.content-tabs {
  display: flex;
  flex-direction: column;
}
.content-tab {
  border-top: 1px solid var(--docku-border);
  scroll-margin-top: 70px; /* keep destination below the sticky pill nav */
}
.content-tab:first-of-type {
  border-top: none;
}

/* ── Tab header (looks like a tab; contains its own tickbox) ── */
.content-tab-header {
  position: relative;
  background: var(--docku-surface, #fff);
  transition:
    background var(--docku-dur-fast, 0.15s) var(--docku-ease, ease),
    box-shadow var(--docku-dur-fast, 0.15s) var(--docku-ease, ease);
}
.content-tab-header::before {
  /* The "tab top" — accent bar shown when active. Mimics a real tab's
   * top border; visually communicates which tab is currently open. */
  content: '';
  position: absolute;
  inset: 0 0 auto 0;
  height: 3px;
  background: transparent;
  border-top-left-radius: var(--docku-radius, 6px);
  border-top-right-radius: var(--docku-radius, 6px);
  transition: background var(--docku-dur-fast, 0.15s) var(--docku-ease, ease);
}
.content-tab-header.is-active {
  background: var(--docku-surface-raised, #f8fafc);
  box-shadow: inset 0 0 0 1px var(--docku-border);
}
.content-tab-header.is-active::before {
  background: var(--docku-primary, #2563eb);
}
.content-tab-header-label {
  display: grid;
  grid-template-columns: auto auto 1fr auto;
  align-items: center;
  gap: var(--docku-space-3);
  padding: var(--docku-space-4) var(--docku-space-5);
  margin: 0;
  cursor: pointer;
  user-select: none;
  font-weight: 400;
}
.content-tab-header-label:hover {
  background: rgba(37, 99, 235, 0.04);
}
.content-tab-header-label input[type="checkbox"] {
  width: 18px;
  height: 18px;
  margin: 0;
  cursor: pointer;
  accent-color: var(--docku-primary, #2563eb);
}
.content-tab-header-label > .fa {
  color: var(--docku-primary, #2563eb);
  font-size: 1rem;
}
.content-tab-header:not(.is-active) .content-tab-header-label > .fa {
  color: var(--docku-text-muted, #94a3b8);
}
.content-tab-header-title {
  font-weight: 600;
  color: var(--docku-text, #0f172a);
}
.content-tab-header:not(.is-active) .content-tab-header-title {
  color: var(--docku-text-muted, #475569);
  font-weight: 500;
}
.content-tab-header-hint {
  font-size: 0.82rem;
  color: var(--docku-text-muted, #475569);
  grid-column: 4;
  text-align: right;
}

/* ── Tab panel (collapsible body under each tab header) ── */
.content-tab-panel {
  padding: 0 var(--docku-space-5) var(--docku-space-5);
  border-top: 1px dashed var(--docku-border);
  padding-top: var(--docku-space-4);
  margin-top: 0;
  background: var(--docku-surface, #fff);
}

/* Mobile: stack label & hint; pill nav scrolls horizontally */
@media (max-width: 768px) {
  .content-tab-nav {
    flex-wrap: wrap;
  }
  .content-tab-nav-pills {
    flex-wrap: nowrap;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: thin;
    padding-bottom: 2px;
  }
  .content-tab-nav-pills::-webkit-scrollbar {
    height: 4px;
  }
  .content-tab-pill {
    flex-shrink: 0;
  }
  .content-tab-header-label {
    grid-template-columns: auto 1fr;
    grid-template-rows: auto auto;
    gap: var(--docku-space-2) var(--docku-space-3);
  }
  .content-tab-header-label input[type="checkbox"] {
    grid-row: 1 / span 2;
  }
  .content-tab-header-label > .fa {
    grid-row: 1;
    grid-column: 2;
  }
  .content-tab-header-title {
    grid-row: 1;
    grid-column: 2;
  }
  .content-tab-header-hint {
    grid-column: 2;
    grid-row: 2;
    text-align: left;
  }
}

@media (max-width: 640px) {
  .content-type-tabs {
    width: calc(100% - var(--docku-space-10));
    margin: var(--docku-space-4) var(--docku-space-4) 0;
  }
  .content-type-panel { padding: var(--docku-space-4); }
  .content-upload-empty,
  .content-upload-success {
    flex-direction: column;
    align-items: flex-start;
    text-align: left;
  }
  .content-upload-empty .btn,
  .content-upload-success .btn { align-self: stretch; }
  .content-tab-header-label {
    padding: var(--docku-space-3) var(--docku-space-4);
  }
  .content-tab-panel {
    padding-left: var(--docku-space-4);
    padding-right: var(--docku-space-4);
  }
  .content-tab-nav {
    padding: var(--docku-space-3) var(--docku-space-4);
  }
}
@media (max-width: 640px) {
  .content-type-tabs {
    width: calc(100% - var(--docku-space-10));
    margin: var(--docku-space-4) var(--docku-space-4) 0;
  }
  .content-type-panel { padding: var(--docku-space-4); }
  .content-upload-empty,
  .content-upload-success {
    flex-direction: column;
    align-items: flex-start;
    text-align: left;
  }
  .content-upload-empty .btn,
  .content-upload-success .btn { align-self: stretch; }
}

/* ── 21. Token picker (UserPicker) ────────────────────────── */
/* Search-and-pick chip field used to replace native <select multiple>
   for user-list pickers. The control looks like an input; the dropdown
   floats on desktop and goes full-screen bottom-sheet on mobile. */

.token-picker {
  display: block;
  width: 100%;
  position: relative;
}

.token-picker-control {
  display: flex;
  align-items: flex-start;
  gap: 0.35rem;
  min-height: 40px;
  padding: 0.3rem 0.5rem 0.3rem 0.4rem;
  background: var(--docku-surface);
  border: 1px solid var(--docku-border);
  border-radius: var(--docku-radius);
  cursor: text;
  transition: border-color var(--docku-dur-fast) var(--docku-ease),
              box-shadow var(--docku-dur-fast) var(--docku-ease);
}
.token-picker.is-open .token-picker-control,
.token-picker-control:focus-within {
  border-color: var(--docku-primary);
  box-shadow: 0 0 0 3px var(--docku-primary-soft);
}
.token-picker.is-disabled .token-picker-control {
  background: var(--docku-surface-raised);
  cursor: not-allowed;
  opacity: 0.7;
}
.token-picker.is-sm .token-picker-control { min-height: 32px; padding: 0.2rem 0.4rem; }
.token-picker.is-sm .token-chip { font-size: 0.78rem; padding: 0.05rem 0.35rem 0.05rem 0.05rem; }

.token-picker-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 0.3rem;
  align-items: center;
  flex: 1;
  min-width: 0;
}

.token-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.1rem 0.4rem 0.1rem 0.1rem;
  background: var(--docku-surface-raised);
  border: 1px solid var(--docku-border);
  border-radius: var(--docku-radius-full);
  font-size: 0.82rem;
  font-weight: 500;
  color: var(--docku-text);
  max-width: 100%;
  min-height: 24px;
  line-height: 1.2;
}
.token-chip .avatar { width: 22px; height: 22px; font-size: 0.65rem; }
.token-chip-label {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 180px;
}
.token-chip-remove {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 20px;
  padding: 0;
  margin-left: 0.1rem;
  background: transparent;
  border: none;
  border-radius: 50%;
  color: var(--docku-text-muted);
  cursor: pointer;
  font: inherit;
  transition: background var(--docku-dur-fast) var(--docku-ease),
              color var(--docku-dur-fast) var(--docku-ease);
}
.token-chip-remove:hover {
  background: var(--docku-danger-soft);
  color: var(--docku-danger);
}
.token-chip-remove:focus-visible {
  outline: none;
  background: var(--docku-primary-soft);
  color: var(--docku-primary-dark);
  box-shadow: 0 0 0 3px var(--docku-primary-soft);
}
.token-chip-remove .fa { font-size: 0.7rem; }

.token-picker-input {
  flex: 1;
  min-width: 80px;
  border: none;
  background: transparent;
  outline: none;
  padding: 0.2rem 0.25rem;
  font-size: 0.92rem;
  font-family: inherit;
  color: var(--docku-text);
  min-height: 28px;
}
.token-picker-input::placeholder { color: var(--docku-text-faint); }
.token-picker-input:disabled { cursor: not-allowed; }

.token-picker-trailing {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0 0.25rem;
  color: var(--docku-text-faint);
  font-size: 0.78rem;
  align-self: center;
}
.token-picker.is-open .token-picker-trailing .fa { transform: rotate(180deg); }
.token-picker-trailing .fa { transition: transform var(--docku-dur-fast) var(--docku-ease); }

.token-picker-helper {
  margin: 0.3rem 0 0;
  font-size: 0.78rem;
  color: var(--docku-text-muted);
}

/* ── Multi-term search field (SearchTerms, PUB-016) ──────────────
   The control is the collaborator-picker chrome without its dropdown:
   `.token-picker*` already supplies the box, the chips and the focus ring.
   The label and the syntax hint sit *above* the control because both call
   sites bottom-align the neighbouring inputs/buttons with this field — a
   trailing hint line would drop them out of line with the search box. */
.search-terms {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  min-width: 0;
}
.search-terms-label {
  font-size: 0.7rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--docku-text-muted);
}
.search-terms-hint {
  margin: 0;
  font-size: 0.72rem;
  color: var(--docku-text-muted);
}
/* Pico's `input:not([type=checkbox],…)` rule is (0,1,1) and therefore
   outranks `.token-picker-input`'s own compact padding/height (0,1,0): the
   input would otherwise inherit Pico's full form-control box and blow the
   chip control out to ~100px, twice the `.input` box it sits beside.
   Re-declared at (0,2,0) so the control renders at `.input`'s height
   (measured: 50px each at the 1280px root size, bottom-aligned with the
   buttons beside them). */
.search-terms .token-picker-input {
  height: auto;
  min-height: 1.4rem;
  padding: 0.2rem 0.25rem;
  margin-bottom: 0;
}

/* Dropdown — desktop (anchored) */
.token-picker-dropdown.is-desktop {
  position: fixed;
  z-index: 1200;
  max-height: 280px;
  overflow-y: auto;
  background: var(--docku-surface);
  border: 1px solid var(--docku-border);
  border-radius: var(--docku-radius);
  box-shadow: var(--docku-shadow-lg);
}
.token-picker-dropdown.is-mobile {
  position: fixed;
  inset: auto 0 0 0;
  z-index: 1200;
  max-height: 70vh;
  display: flex;
  flex-direction: column;
  background: var(--docku-surface);
  border-top-left-radius: var(--docku-radius-lg);
  border-top-right-radius: var(--docku-radius-lg);
  box-shadow: var(--docku-shadow-lg);
  padding: var(--docku-space-2) 0 var(--docku-space-4);
  animation: token-picker-sheet-in 0.18s var(--docku-ease-out);
}
@keyframes token-picker-sheet-in {
  from { transform: translateY(20px); opacity: 0; }
  to   { transform: translateY(0); opacity: 1; }
}
/* Drag-handle hint for mobile sheet */
.token-picker-dropdown.is-mobile::before {
  content: "";
  display: block;
  width: 36px;
  height: 4px;
  border-radius: 4px;
  background: var(--docku-border-strong);
  margin: 0 auto var(--docku-space-2);
}
.token-picker-dropdown.is-mobile .token-picker-list { padding-bottom: env(safe-area-inset-bottom, 0); }

.token-picker-list {
  list-style: none;
  margin: 0;
  padding: 0.25rem;
}

.token-picker-option {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.5rem 0.6rem;
  border-radius: var(--docku-radius);
  cursor: pointer;
  font-size: 0.9rem;
  color: var(--docku-text);
  user-select: none;
  transition: background var(--docku-dur-fast) var(--docku-ease);
}
.token-picker-option:hover { background: var(--docku-surface-raised); }
.token-picker-option.is-highlighted {
  background: var(--docku-primary-50);
  color: var(--docku-primary-dark);
}
.token-picker-option-label {
  flex: 1;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.token-picker-option-mark {
  color: var(--docku-primary);
  font-size: 0.78rem;
}

.token-picker-empty {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.7rem 0.6rem;
  font-size: 0.85rem;
  color: var(--docku-text-muted);
  font-style: italic;
}
.token-picker-empty .fa { color: var(--docku-text-faint); }

@media (max-width: 640px) {
  .token-picker-input { font-size: 16px; /* iOS zoom guard */ }
  .token-picker-option { padding: 0.7rem 0.6rem; font-size: 0.95rem; }
}

/* ── Document Create — optional section badge ───── */
.form-section-header h3 .form-section-optional {
  display: inline-block;
  margin-left: 0.4rem;
  padding: 0.05rem 0.45rem;
  border-radius: var(--docku-radius-full, 999px);
  background: var(--docku-surface-raised, #f3f4f6);
  color: var(--docku-text-muted, #6b7280);
  font-size: 0.65rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: none;
  vertical-align: middle;
}

/* ── Document Create — staged collaborator list ───── */
.collab-list-staged {
  margin-top: var(--docku-space-2, 0.5rem);
}

/* ── Document View — read-only mode styles ─────────────────── */
.docs-view-article {
  display: flex;
  flex-direction: column;
  gap: var(--docku-space-6);
  background: transparent;
  box-shadow: none;
  padding: 0;
}

.docs-view-article .form-section {
  margin-bottom: 0;
}


.docs-view-readonly-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--docku-space-3) var(--docku-space-5);
}
.docs-view-readonly-grid > .span-2 { grid-column: span 2; }
@media (max-width: 768px) {
  .docs-view-readonly-grid { grid-template-columns: 1fr; }
  .docs-view-readonly-grid > .span-2 { grid-column: span 1; }
}

.docs-view-field-label {
  display: block;
  font-size: 0.72rem;
  text-transform: none;
  letter-spacing: 0.06em;
  font-weight: 600;
  color: var(--docku-text-muted);
  margin-bottom: 0.25rem;
}

.docs-view-field-value {
  display: block;
  color: var(--docku-text);
  font-size: 0.95rem;
  word-break: break-word;
}

.tag-pill {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  padding: 0.2rem 0.55rem;
  border-radius: var(--docku-radius-full);
  background: var(--docku-primary-50);
  color: var(--docku-primary-dark);
  font-size: 0.78rem;
  font-weight: 500;
  margin: 0 0.25rem 0.25rem 0;
}
/* "+N" overflow chip for the publications Tags column: non-interactive —
   the full list is in the expanded row and in the chip's tooltip. */
.tag-pill-more {
  background: var(--docku-surface-sunken);
  color: var(--docku-text-muted);
  cursor: default;
}

/* Cluster of tag pills used in the Documents list "Tags" column.
   Keep them tightly packed with a consistent small gap. */
.tag-pill-list {
  display: inline-flex;
  flex-wrap: wrap;
  gap: 0.2rem;
  align-items: center;
}
.tag-pill-list .tag-pill { margin: 0; }

.type-badge {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.2rem 0.6rem;
  border-radius: var(--docku-radius);
  background: var(--docku-surface-raised);
  border: 1px solid var(--docku-border);
  color: var(--docku-text-2);
  font-size: 0.82rem;
  font-weight: 500;
  text-transform: capitalize;
}

/* Markdown body rendering (sanitized HTML) */
.markdown-body {
  font-size: 0.95rem;
  line-height: 1.65;
  /* Reading measure: the app shell is full-bleed (CSS-014), so cap
     long-form prose at ~78 characters and centre the column inside its
     card.  Tables / filters / grids keep the full viewport width. */
  max-width: 78ch;
  margin-inline: auto;
  /* Defensive: ensure HTML flow is honoured even if a parent or utility
     class sets `white-space: nowrap` / `pre`. Combined with marked's
     `breaks: true` (set in app.js), single newlines render as soft breaks
     and paragraphs keep their normal flow. */
  white-space: normal;
  color: var(--docku-text);
}

/* ── Document watermark overlay ───────────────────────────────────
   When a document has ``watermark_enabled`` set, the SPA renders
   a faint diagonal text overlay on top of the markdown preview and
   (mirror) on the public publication viewer.  The wrapper is
   position: relative so the absolutely-positioned overlay sits
   inside its bounds; ``pointer-events: none`` keeps the overlay
   invisible to mouse interaction so users can still copy text,
   select links, and scroll without obstruction.  The text is
   centred on the wrapper with a 30° rotation matching the PDF
   stamp so the browser and downloaded PDF read consistently. */
.markdown-body-wrap {
  position: relative;
  overflow: hidden;
}
.watermark-overlay {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
  user-select: none;
  z-index: 5;
  overflow: hidden;
}
.watermark-overlay .watermark-text {
  transform: rotate(-30deg);
  font-size: 3.5rem;
  font-weight: 700;
  letter-spacing: 0.25rem;
  color: rgba(15, 23, 42, 0.07);
  white-space: nowrap;
  text-transform: uppercase;
  /* Render the same text on the wrap horizontally but slightly
     offset so a long string spans the visible width. */
  padding: 1rem 2rem;
  border: 0.25rem solid rgba(15, 23, 42, 0.05);
  border-radius: 0.5rem;
}
/* Edit-mode watermark controls — keep them visually grouped
   below the free-form fields.  We only need a thin top divider
   and a small visual cue on the toggle row. */
.watermark-editor {
  margin-top: 0.75rem;
  padding-top: 0.75rem;
  border-top: 1px solid var(--docku-border, #e2e8f0);
}
.watermark-toggle {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}
.watermark-toggle .field-label {
  font-weight: 500;
}
.form-section-help {
  color: var(--docku-text-muted, #64748b);
  font-size: 0.85rem;
  margin: 0;
}
.markdown-body h1,
.markdown-body h2,
.markdown-body h3,
.markdown-body h4 {
  margin: 1.25rem 0 0.5rem;
  color: var(--docku-text);
  font-weight: 600;
}
.markdown-body h1 { font-size: 1.35rem; }
.markdown-body h2 { font-size: 1.15rem; }
.markdown-body h3 { font-size: 1.05rem; }
.markdown-body p { margin: 0 0 0.75rem; }
.markdown-body ul,
.markdown-body ol {
  margin: 0 0 0.75rem;
  padding-left: 1.5rem;
}
.markdown-body li { margin-bottom: 0.25rem; }
.markdown-body pre {
  background: var(--docku-surface-raised);
  border: 1px solid var(--docku-border);
  border-radius: var(--docku-radius);
  padding: 0.75rem 1rem;
  overflow-x: auto;
  font-size: 0.85rem;
}
.markdown-body code {
  background: var(--docku-surface-raised);
  padding: 0.15rem 0.35rem;
  border-radius: 4px;
  font-size: 0.85rem;
}
.markdown-body blockquote {
  margin: 0 0 0.75rem;
  padding-left: 0.75rem;
  border-left: 3px solid var(--docku-primary-soft);
  color: var(--docku-text-2);
}
.markdown-body table {
  width: 100%;
  border-collapse: collapse;
  margin-bottom: 0.75rem;
}
.markdown-body th,
.markdown-body td {
  border: 1px solid var(--docku-border);
  padding: 0.4rem 0.6rem;
  text-align: left;
  font-size: 0.88rem;
}
.markdown-body th {
  background: var(--docku-surface-raised);
  font-weight: 600;
}
.markdown-body a {
  color: var(--docku-primary);
  text-decoration: underline;
}
.markdown-body img {
  max-width: 100%;
  height: auto;
  border-radius: var(--docku-radius-sm);
}

/* ── Publications header + search ────────────────────────────────
   The title band and the search control are *stacked* inside one
   `.page-header`, not squeezed onto a single row: the guest subtitle
   is long enough that a one-row layout wrapped unpredictably and left
   the controls on a ragged baseline.  Scoped to `.publications-page`
   so no other page's `.page-header` changes. */
.publications-header {
  flex-direction: column;
  align-items: stretch;
  gap: var(--docku-space-4);
  /* Drop the shared `.page-header` padding so the title and the search
     row line up with the table card's left/right edges. */
  padding: 0;
}
.publications-search {
  display: flex;
  align-items: flex-end;
  flex-wrap: wrap;
  gap: var(--docku-space-2);
}
.pub-search-field {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  flex: 1 1 18rem;
  max-width: 30rem;
  min-width: 0;
}
.pub-search-field label {
  font-size: 0.7rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--docku-text-muted);
}
.pub-search-actions {
  display: flex;
  align-items: center;
  gap: var(--docku-space-2);
  margin-left: auto;
}
/* `.input` (40px) and `.btn` (~40px) now bottom-align because both carry
   `margin: 0`; the 1–2px height difference is below the eye. */
@media (max-width: 640px) {
  .pub-search-field { flex: 1 1 100%; max-width: none; }
  .pub-search-actions { margin-left: 0; width: 100%; }
  .pub-search-actions .btn { flex: 1 1 auto; justify-content: center; }
}

/* Sticky table header + bounded vertical scroll, mirroring the documents
   list (`.docs-list-page .table-scroll`).  Applied at every width like the
   documents list: below 769px the table is a card stack and the thead is
   off-screen, so the sticky rule is inert there. */
.publications-page .table-scroll {
  /* PUB-015: a row-driven window — the sticky header (2.2rem) plus five
     catalogue rows (5.3rem each, 1280x900, two-line description) — clamped to
     the window minus the topbar and 12rem of breathing room, so a short
     window shows fewer rows instead of hiding the column header.  The old
     `100dvh - 16rem` formula showed ~3 rows at 1024x768 and ~4 at 1280x900:
     the visible row count moved with the window rather than being a
     decision.  Row height is content-driven, so a wrapping description can
     move the count by one — that is accepted over truncating any text.
     Card mode releases this window and the table's 1400px floor; see the
     card-stack block in §9 Tables. */
  max-height: min(
    calc(2.2rem + 5 * 5.3rem),
    calc(100dvh - var(--docku-topbar-h) - 12rem)
  );
  overflow: auto;
}
.publications-page .data-table thead th {
  position: sticky;
  top: 0;
  z-index: 3;
}
.publications-page .data-table thead th.col-actions {
  z-index: 4;
}

/* ── Expanded row — release the bounded inner scroll (PUB-014) ────
   While a row is expanded the catalogue drops its inner scroll box: the
   detail is several screens tall, so a bounded box meant reading it through
   a nested scrollbar (and on a phone it left barely one card visible).

   `overflow` has to be released on the `.table-wrap` card too, not just on
   the scroll box.  That card's `overflow: hidden` (which clips the table to
   the card's rounded corners) is itself a scrollport, so leaving it in place
   would trap the sticky header: with the box grown past the viewport, the
   header would pin to the card's top edge and scroll away with it rather
   than pinning below the topbar.  The two horizontal-scroll affordances —
   the mirrored top track and the "Scroll for more" hint — are hidden while
   expanded because there is no horizontal scroll left to drive them, and the
   header's rounded corners are re-declared (the card no longer clips them). */
.publications-page .table-wrap.has-expanded { overflow: visible; }
.publications-page .table-wrap.has-expanded .table-scroll {
  max-height: none;
  overflow: visible;
}
.publications-page .table-wrap.has-expanded .table-scroll-top,
.publications-page .table-wrap.has-expanded .scroll-hint { display: none; }
.publications-page .table-wrap.has-expanded .data-table thead th {
  /* Pinned under the sticky topbar rather than at the card's top edge. */
  top: var(--docku-topbar-h);
}
.publications-page .table-wrap.has-expanded .data-table thead th:first-child {
  border-top-left-radius: var(--docku-radius-lg);
}
.publications-page .table-wrap.has-expanded .data-table thead th:last-child {
  border-top-right-radius: var(--docku-radius-lg);
}

/* Guest footer on the catalogue pages.  `.app-main` is full-bleed
   (CSS-014), so the footer would otherwise inherit `.home-band-inner`'s
   1280px content cap and centre inside it — on a wide screen its left
   edge sat ~160px to the right of the table's and read as "centred".
   Let the footer span the band, and drop the band's own side padding so
   its content lines up with the table card's edges (the surrounding
   `.app-main` padding already provides the gutter). */
.publications-page > .home-foot,
.publication-view-page > .home-foot {
  margin-top: var(--docku-space-6);
  padding-inline: 0;
}
.publications-page > .home-foot .home-foot-inner,
.publication-view-page > .home-foot .home-foot-inner {
  max-width: none;
}

/* ── Publications catalogue — moderate density ────────────────────
   The catalogue deliberately keeps all twelve columns, so shave the
   vertical padding and the body size a step: more rows fit on screen and
   more columns come into view, without hiding any data. */
.publications-page .data-table { font-size: 0.85rem; }
.publications-page .data-table thead th { padding: 0.55rem var(--docku-space-3); }
.publications-page .data-table tbody td { padding: 0.6rem var(--docku-space-3); }

/* ── Publications list — inline row expansion ──────────────────── */
/* The whole data row is clickable, mirroring the affordance used
 * elsewhere in the app (e.g. notifications).  Keyboard and screen-reader
 * users get a real disclosure control instead: the Title cell holds a
 * `<button class="pub-row-toggle">` carrying `aria-expanded` /
 * `aria-controls`.  `aria-expanded` is NOT valid on a plain table row
 * (role=row inside table) — it is only allowed on treegrid rows — so
 * putting it on the <tr> tripped axe's aria-conditional-attr rule.
 *
 * Note: we deliberately do NOT use `role="button"` on the <tr>;
 * Pico CSS paints anything matching [role=button] with
 * `background-color: var(--pico-primary-background)` which would
 * otherwise bleed the brand primary (#2563eb) onto the row.  An
 * explicit background-color below defends against any other
 * selector that might match. */
.publications-page .data-table tbody tr.pub-row {
  cursor: pointer;
  /* Belt-and-braces: declare an explicit background-color on the
     base row so it stays inside our colour system regardless of
     Pico's classless defaults. */
  background-color: var(--docku-surface, #fff);
  /* PUB-014: expanding scrolls this row to the top of the viewport, so it
     needs to clear the sticky topbar plus the column header that pins
     beneath it while a row is open (2.25rem ≈ the header's cell padding and
     line box). */
  scroll-margin-top: calc(var(--docku-topbar-h) + 2.25rem);
}
@media (max-width: 768px) {
  /* Card mode hides the column header, so only the topbar is in the way. */
  .publications-page .data-table tbody tr.pub-row {
    scroll-margin-top: var(--docku-topbar-h);
  }
}
/* Row-level disclosure button.  Resets the Pico button chrome so it
   reads as the title text, and provides the focus ring the old
   focusable <tr> used to own. */
.pub-row-toggle {
  display: inline-flex;
  align-items: center;
  gap: var(--docku-space-1);
  margin: 0;
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.pub-row-toggle:hover strong { text-decoration: underline; }
.pub-row-toggle:focus-visible {
  outline: 2px solid var(--docku-text-muted, #64748b);
  outline-offset: 2px;
}
/* Disclosure chevron in the Title cell: a visible cue that the row opens
   (the whole row is clickable, but nothing said so before). */
.pub-row-chevron {
  flex: none;
  font-size: 0.65rem;
  color: var(--docku-text-faint);
  transition: transform var(--docku-dur-fast) var(--docku-ease);
}
.pub-row-chevron.is-open { transform: rotate(90deg); }
/* Hover: the soft brand tint (--docku-row-hover-bg resolves to
   --docku-primary-50), legible on the base surface in either theme.
   Pointer-only, so a tap on a touch screen cannot leave a row stuck in
   its hover state. */
@media (hover: hover) {
  .publications-page .data-table tbody tr.pub-row:hover {
    background: var(--docku-row-hover-bg);
  }
}
.publications-page .data-table tbody tr.pub-row.is-expanded {
  background: var(--docku-row-expanded-bg);
}

/* Spanning detail row beneath the clicked row.  Single TD that
 * spans every column; padding hosts the same .docs-view-article card
 * stack used by PublicationView. */
.publications-page .data-table tbody tr.pub-detail-row > .pub-detail-cell {
  padding: 0;
  background: var(--docku-row-expanded-bg);
  border-top: 1px solid var(--docku-row-expanded-border);
  border-bottom: 1px solid var(--docku-row-expanded-border);
}
.publications-page .pub-detail-row .docs-view-article {
  padding: var(--docku-space-5, 1.25rem) var(--docku-space-5, 1.25rem) var(--docku-space-4, 1rem);
}

/* Footer of the expanded card — secondary action row that mirrors
 * PublicationView's "Open in workspace" / "Back to list" pattern. */
.pub-detail-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--docku-space-2, 0.5rem);
  justify-content: flex-end;
  padding-top: var(--docku-space-3, 0.75rem);
  border-top: 1px dashed var(--docku-border, #e5e7eb);
}
@media (max-width: 640px) {
  .pub-detail-actions { justify-content: stretch; }
  .pub-detail-actions .btn { flex: 1 1 auto; }
}

/* ── Confirm modal (Promise-based, replaces native confirm()) ──── */
body.confirm-open { overflow: hidden; }
.confirm-overlay {
  /* Sits above other modals (e.g. silent-edit at 1100) so a confirm
   * triggered from inside a form modal still wins. */
  z-index: 1200;
  animation: action-sheet-fade 0.18s ease-out;
}
.confirm-modal {
  /* Override the action-sheet's centred-card width so the confirm
   * dialog reads more like a focused alert than a long list. */
  width: min(440px, 100%);
  max-width: 100%;
  text-align: left;
  padding: var(--docku-space-4) var(--docku-space-4) var(--docku-space-3);
  border-radius: 1.25rem;
  max-height: 80vh;
  overflow: hidden;
  animation: action-sheet-pop-in 0.22s var(--docku-ease-out);
}
.confirm-header {
  padding: 0 0 var(--docku-space-2);
  border-bottom: 1px solid var(--docku-border);
  margin-bottom: var(--docku-space-3);
}
.confirm-title {
  margin: 0;
  display: flex; align-items: center; gap: 0.6rem;
  font-size: 1.05rem;
  font-weight: 700;
  color: var(--docku-text);
}
.confirm-title .fa {
  font-size: 1.1rem;
  color: var(--docku-primary);
  flex-shrink: 0;
}
.confirm-title .fa-exclamation-triangle { color: var(--docku-danger); }

.confirm-body { padding: 0 0 var(--docku-space-3); }
.confirm-message {
  margin: 0;
  font-size: 0.95rem;
  line-height: 1.45;
  color: var(--docku-text);
  white-space: pre-wrap;
  word-break: break-word;
}
.confirm-actions {
  display: flex;
  justify-content: flex-end;
  gap: var(--docku-space-2);
  flex-wrap: wrap;
}
.confirm-actions button {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  min-height: 38px;
  padding: 0.45rem 0.9rem;
  font-size: 0.95rem;
}
.confirm-spinner {
  width: 14px; height: 14px;
  border-radius: 50%;
  border: 2px solid currentColor;
  border-top-color: transparent;
  animation: confirm-spin 0.7s linear infinite;
  display: inline-block;
}
@keyframes confirm-spin { to { transform: rotate(360deg); } }
@media (max-width: 640px) {
  .confirm-modal {
    border-radius: 1.25rem 1.25rem 0 0;
    max-height: 90vh;
  }
  .confirm-overlay { align-items: flex-end !important; padding: 0 !important; }
}

/* ── ErrorBoundary fallback panel ─────────────────────────────── */
.error-boundary {
  /* Fall back to a simple centred card so a crashed page is still
   * navigable, even when the app shell itself is functional. */
  min-height: 60vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--docku-space-5) var(--docku-space-3);
}
.error-boundary-card {
  width: min(520px, 100%);
  background: var(--docku-surface);
  border: 1px solid var(--docku-border);
  border-radius: var(--docku-radius);
  padding: var(--docku-space-5) var(--docku-space-4);
  text-align: center;
  box-shadow: 0 4px 12px rgba(15, 23, 42, 0.06);
}
.error-boundary-icon {
  width: 56px; height: 56px;
  margin: 0 auto var(--docku-space-3);
  background: var(--docku-danger-soft);
  color: var(--docku-danger);
  border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  font-size: 1.5rem;
}
.error-boundary-title {
  margin: 0 0 var(--docku-space-2);
  font-size: 1.25rem;
  font-weight: 700;
  color: var(--docku-text);
}
.error-boundary-message {
  margin: 0 0 var(--docku-space-2);
  font-size: 0.95rem;
  color: var(--docku-text-2);
  word-break: break-word;
}
.error-boundary-detail {
  margin: 0 0 var(--docku-space-3);
  font-family: monospace;
  font-size: 0.8rem;
  color: var(--docku-text-muted);
  background: var(--docku-surface-raised);
  padding: var(--docku-space-2);
  border-radius: var(--docku-radius-sm);
  text-align: left;
  word-break: break-word;
}
.error-boundary-actions {
  display: flex;
  justify-content: center;
  gap: var(--docku-space-2);
  flex-wrap: wrap;
  margin-top: var(--docku-space-3);
}
.error-boundary-actions button {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  min-height: 38px;
  padding: 0.45rem 0.9rem;
}

/* ── Mobile tap-target adjustments (WCAG 2.5.5, min 44×44) ── */
@media (max-width: 768px) {
  .btn {
    min-height: 44px;
    padding: 0.6rem 1.1rem;
    font-size: 0.95rem;
    /* Prevent the 300 ms double-tap delay on mobile browsers. */
    touch-action: manipulation;
  }
  .btn-sm {
    min-height: 40px;
    padding: 0.45rem 0.85rem;
  }
  .action-menu-trigger {
    width: 44px;
    height: 44px;
    font-size: 1.05rem;
  }
  .action-sheet-item {
    min-height: 56px;
    padding: 1.05rem 1.25rem;
  }
  /* Larger hit area for table rows on mobile. */
  .data-table tbody td {
    padding: var(--docku-space-4) var(--docku-space-3);
  }
  .data-table tbody tr.is-clickable td:first-child {
    padding-left: var(--docku-space-4);
  }
  /* iOS won't auto-zoom into inputs if font-size ≥ 16 px. */
  input, select, textarea, .input {
    font-size: 16px;
  }
}

/* ── Component state contract (FD-005) ──────────────────────
   .btn already owns the full default / hover / :focus-visible /
   :active / [disabled] / aria-busy matrix.  The rules below extend the
   same contract to the other interactive or status-bearing families so
   no family is stateless:
     * [aria-busy="true"] -> progress cursor.  Templates already set
       aria-busy on submitting buttons and ConfirmModal shells, but no
       stylesheet rule honoured it.
     * :focus-visible -> the shared 3px ring for controls that are not
       .btn (plain links / icon buttons inside a shell).
     * .is-disabled / [aria-disabled="true"] -> dimmed, non-interactive.
   `.skeleton` is deliberately absent: it *is* a loading state (its
   shimmer animation is the affordance) and has no interactive variant. */
.btn[aria-busy="true"],
.modal[aria-busy="true"],
.action-sheet-overlay[aria-busy="true"],
.toast[aria-busy="true"],
.badge[aria-busy="true"],
.empty-state[aria-busy="true"] {
  cursor: progress;
}

/* Pico injects its own ::before loading glyph on any [aria-busy=true];
   where a template already renders its own spinner that doubles the
   indicator (e.g. the Sign-in button showed Pico's ring + .spinner).
   Suppress the pseudo-element only where we supply our own glyph. */
.btn[aria-busy="true"]:has(.spinner)::before,
.modal[aria-busy="true"]:has(.confirm-spinner)::before { content: none; }

.modal a:focus-visible,
.modal button:not(.btn):focus-visible,
.toast a:focus-visible,
.toast button:focus-visible,
.empty-state a:focus-visible,
.empty-state button:not(.btn):focus-visible,
.badge:focus-visible {
  outline: none;
  box-shadow: var(--docku-focus-ring);
}

.badge.is-disabled,
.badge[aria-disabled="true"],
.empty-state.is-disabled,
.empty-state[aria-disabled="true"] {
  opacity: 0.55;
  pointer-events: none;
}

/* ── Reduced-motion support (WCAG 2.3.3) ──────────────────── */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* ── Safe-area insets for notched / Dynamic-Island devices ── */
@supports (padding: max(0px)) {
  .app-topbar,
  .app-sidebar,
  .bottom-action-bar,
  .error-boundary {
    padding-left: max(var(--docku-space-3, 0.75rem), env(safe-area-inset-left));
    padding-right: max(var(--docku-space-3, 0.75rem), env(safe-area-inset-right));
  }
  .app-topbar {
    padding-top: max(0px, env(safe-area-inset-top));
  }
  .bottom-action-bar {
    padding-bottom: max(var(--docku-space-3, 0.75rem), env(safe-area-inset-bottom));
  }
  /* The drawer hugs the left edge and spans the full viewport height,
     so it needs the notch (landscape) and home-indicator insets. */
  .mobile-nav-drawer {
    padding-left: env(safe-area-inset-left);
    padding-top: env(safe-area-inset-top);
  }
  .mobile-nav-foot {
    padding-bottom: max(var(--docku-space-3, 0.75rem), env(safe-area-inset-bottom));
  }
}

/* ── Landing page (HomeView at "/") ────────────────────────── */
/* Guest-only: authed visitors are bounced to /dashboard by the
   router guard.  Reuses .card / .quick-actions-grid / .btn-* tokens
   so the landing feels native to the rest of the app.

   The landing is a stack of edge-to-edge bands whose content is
   re-centred by `.home-band-inner`; it drops `.app-main`'s padding so the
   bands reach the viewport edge.  (`.app-main` is full-bleed for every
   route since CSS-014; the landing no longer needs a special cap lift.) */
body:has(.home-page) .app-main {
  padding: 0;
  /* The bands are surface-coloured; matching .app-main stops a grey
     `--docku-bg` strip showing under the footer on tall viewports. */
  background: var(--docku-surface);
}
.home-page {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0;
  max-width: none;
  margin: 0;
  padding: 0;
}
.home-band-inner {
  width: 100%;
  max-width: var(--docku-content-max);
  margin-inline: auto;
}
.home-hero {
  width: 100%;
  /* Top gap halved (SURF-005): the band sits closer to the nav. The bottom
     keeps the full rhythm so the hero->features seam is unchanged. */
  padding: var(--docku-space-6) 0 var(--docku-space-12);
  background:
    radial-gradient(circle at top right, var(--docku-primary-50) 0%, transparent 60%),
    var(--docku-surface);
  border-radius: 0;
  /* .card's border/shadow would draw a 1px grey rail along the viewport
     edge on a full-bleed band — drop both (CSS-009). */
  border: 0;
  box-shadow: none;
}
.home-hero-inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  /* Roomy gap between the hero copy (Sign in CTA) and the framed catalogue
     screenshot. */
  gap: var(--docku-space-10);
  /* Match the feature grid / footer inset (--docku-space-5) so the bands
     line up on the same vertical edge (CSS-010). */
  padding-inline: var(--docku-space-5);
}
.home-hero-copy {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--docku-space-3);
  max-width: 44rem;
  text-align: center;
}
.home-hero-eyebrow {
  margin: 0;
  font-size: 0.78rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--docku-primary);
}
.home-hero-title {
  margin: 0;
  font-size: clamp(1.7rem, 3.2vw, 2.5rem);
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.15;
  color: var(--docku-text);
  text-wrap: balance;
}
.home-hero-tagline {
  margin: 0;
  font-size: 1.05rem;
  color: var(--docku-text-muted);
  line-height: 1.5;
  max-width: 56ch;
}
.home-hero-cta {
  display: flex;
  justify-content: center;
  gap: var(--docku-space-3);
  flex-wrap: wrap;
  margin-top: var(--docku-space-2);
}
/* The primary guest CTA: a touch larger than the default .btn-lg. */
.home-hero-cta .btn {
  font-size: 1.05rem;
  padding: var(--docku-space-3) var(--docku-space-5);
}
.home-hero-media {
  width: 100%;
}
/* Browser-window frame so the capture reads as a screenshot, not the live
   app.  Reuses .card card-flush for the border/radius/padding so no new raw
   literals are introduced. */
.home-hero-frame {
  margin: 0;
  overflow: hidden;
  box-shadow: var(--docku-shadow-lg);
}
.home-hero-frame-bar {
  display: flex;
  align-items: center;
  gap: var(--docku-space-2);
  /* Window-chrome strip: roomy enough to read as a title bar rather than a
     thin rule.  It carries only the decorative traffic-light dots now that
     the Browse control lives in the hero CTA. */
  padding: var(--docku-space-2) var(--docku-space-3);
  background: var(--docku-surface-raised);
}
.home-hero-frame-dots {
  display: inline-flex;
  align-items: center;
  gap: var(--docku-space-2);
}
.home-hero-frame-dot {
  flex: none;
  width: 0.6rem;
  height: 0.6rem;
  border-radius: var(--docku-radius-full);
  background: var(--docku-border-strong);
}
/* Traffic-light window controls (red / yellow / green, left to right).
   Reuse the semantic tokens so no raw colour literal enters the ratchet;
   the solid accents are theme-stable while -soft/-text swap in dark. */
.home-hero-frame-dot--red { background: var(--docku-danger); }
.home-hero-frame-dot--yellow { background: var(--docku-warning); }
.home-hero-frame-dot--green { background: var(--docku-success); }
.home-hero-shot {
  display: block;
  width: 100%;
  height: auto;
  background: var(--docku-surface);
  user-select: none;
}
.home-features {
  width: 100%;
  border-radius: 0;
  border: 0;
  box-shadow: none;
}
.home-features .card-header h2 { margin: 0; }
.home-features .card-header h2 i { color: var(--docku-primary); margin-right: var(--docku-space-2); }

/* Content-driven feature grid (CSS-007). Stays auto-fit — never a fixed
   track count — so a removed card cannot leave an orphan empty column; a
   `repeat(3, 1fr)` previously did exactly that once the third card was
   removed. Full-width now, so it inherits the global `.quick-actions-grid`
   auto-fit tracks (4-up on a desktop-width page). The 769–1024 band gets a
   wider floor so the fourth card cannot wrap alone into a 3+1 row
   (CSS-008); the phone band collapses to one column. */
@media (max-width: 768px) {
  .home-features .quick-actions-grid { grid-template-columns: 1fr; }
}
@media (min-width: 769px) and (max-width: 1024px) {
  .home-features .quick-actions-grid {
    grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
  }
}
.home-foot {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: var(--docku-space-6) var(--docku-space-5);
  /* Soft brand tint so the footer reads as its own band (it previously used
     --docku-surface, identical to the page, so the band was invisible).
     --docku-primary-50 is a pale blue in light and a deep navy in dark; the
     link colours stay AA on it (enforced by the dark-scheme axe pass). */
  background: var(--docku-primary-50);
  width: 100%;
  border-radius: 0;
  border: 0;
  border-top: thin solid var(--docku-primary-100);
  box-shadow: none;
  text-align: left;
}
.home-foot-inner {
  display: flex;
  flex-direction: column;
  gap: var(--docku-space-5);
}
/* Tier 1 — brand left, nav/utility right (stacks centred on phones). */
.home-foot-main {
  display: flex;
  flex-direction: row;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--docku-space-6);
}
.home-foot-brand {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--docku-space-1);
  max-width: 34rem;
}
.home-foot-wordmark {
  font-size: 1.05rem;
  font-weight: 700;
  letter-spacing: 0.02em;
  color: var(--docku-text);
}
.home-foot-tagline {
  margin: 0;
  font-size: 0.9rem;
  color: var(--docku-text-muted);
}
.home-foot-aside {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: var(--docku-space-2);
  flex-shrink: 0;
}
.home-foot-links {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  align-items: center;
  gap: var(--docku-space-2) var(--docku-space-5);
  margin: 0;
  padding: 0;
  list-style: none;
}
.home-foot-links a {
  color: var(--docku-primary);
  text-decoration: none;
  font-size: 0.9rem;
}
.home-foot-links a:hover { text-decoration: underline; }
.home-foot-top {
  display: inline-flex;
  align-items: center;
  gap: var(--docku-space-2);
  margin: 0;
  padding: 0;
  border: 0;
  background: none;
  color: var(--docku-primary);
  font: inherit;
  font-size: 0.9rem;
  cursor: pointer;
}
.home-foot-top:hover { text-decoration: underline; }
/* Tier 2 — copyright left, version pill right, split by a hairline. */
.home-foot-meta {
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: space-between;
  gap: var(--docku-space-2);
  width: 100%;
  padding-top: var(--docku-space-4);
  border-top: thin solid var(--docku-primary-100);
  font-size: 0.82rem;
  color: var(--docku-text-muted);
}
.home-foot-version {
  padding: 0.1rem 0.55rem;
  border: thin solid var(--docku-border);
  border-radius: var(--docku-radius-full);
  background: var(--docku-surface-raised);
  color: var(--docku-text-muted);
  font-variant-numeric: tabular-nums;
}

/* Dark theme needs a lighter blue for text on the dark surface: the shared
   brand `--docku-primary` (#2563eb) only reaches ~3.4:1, below WCAG AA,
   while `--docku-primary-light` (#3b82f6) reaches ~4.7:1 on the plain
   surface.  Scoped to the landing so the global brand hue is untouched
   (frontend-design owns a themeable link token if this generalises). */
[data-theme="dark"] .home-hero-eyebrow {
  color: var(--docku-primary-light);
}
/* On the footer's navy tint (--docku-primary-50 = #0f1f3d) the dark-theme
   link token (#3b82f6) reaches only 4.44:1 — a hair under AA — so footer
   link text uses the lighter --docku-primary-soft (#bfdbfe, ~11.5:1).
   The dark-scheme axe pass (A11Y-001) enforces this. */
[data-theme="dark"] .home-foot-top,
[data-theme="dark"] .home-foot-links a {
  color: var(--docku-primary-soft);
}
@media (max-width: 640px) {
  .home-hero { padding-block: var(--docku-space-4) var(--docku-space-8); }
  .home-hero-inner { padding-inline: var(--docku-space-4); }
  .home-hero-title { font-size: 1.6rem; }
  .home-hero-tagline { font-size: 0.98rem; }
  .home-hero-cta .btn { width: 100%; justify-content: center; }
  /* Footer collapses to a centred single column in reading order. */
  .home-foot { text-align: center; }
  .home-foot-main {
    flex-direction: column;
    align-items: center;
    gap: var(--docku-space-4);
  }
  .home-foot-brand { align-items: center; }
  .home-foot-aside { align-items: center; }
  .home-foot-links { justify-content: center; }
  .home-foot-meta { justify-content: center; gap: var(--docku-space-3); }
}

/* ── Document autofill (POST /api/documents/extract) ──────────── */
/* Flash a soft amber background on inputs the extractor just filled
   so the user can tell at a glance what changed.  Keyframe duration is
   ~3s to match AutofillHighlights.js (FLASH_MS = 3000). */
.autofill-flash,
.autofill-flash input,
.autofill-flash textarea,
.autofill-flash select {
  animation: autofill-pulse 3s var(--docku-ease) 1;
  background-color: #fef3c7 !important;
  border-color: var(--docku-warning) !important;
  box-shadow: 0 0 0 2px rgba(245, 158, 11, 0.18);
}
@keyframes autofill-pulse {
  0%   { background-color: #fde68a; box-shadow: 0 0 0 4px rgba(245, 158, 11, 0.30); }
  60%  { background-color: #fef3c7; box-shadow: 0 0 0 2px rgba(245, 158, 11, 0.18); }
  100% { background-color: transparent; box-shadow: none; }
}
/* CodeMirror's editor surface lives inside the .CodeMirror element;
   flash the parent so the whole editable area lights up. */
.autofill-flash .CodeMirror,
.autofill-flash.CodeMirror {
  background-color: #fef3c7 !important;
  animation: autofill-pulse 3s var(--docku-ease) 1;
}
/* Hidden autofill <input type=file> mirrors the file input pattern used
   in the Content / File tab — same class so the visually-hidden behaviour
   is consistent. */
.autofill-file-input {
  display: none;
}
/* Warnings card.  Inherits .app-banner.warn amber styling and adds a
   short list of extractor warnings + a dismiss action. */
.autofill-warnings {
  display: flex;
  align-items: flex-start;
  gap: var(--docku-space-3);
}
.autofill-warnings-text {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  gap: var(--docku-space-2);
}
.autofill-warning-list {
  margin: 0;
  padding-left: var(--docku-space-4);
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.autofill-warning-list code {
  background: rgba(146, 64, 14, 0.08);
  padding: 1px 4px;
  border-radius: 4px;
  font-size: 0.85em;
  margin-right: 4px;
}
.autofill-tag {
  display: inline-block;
  margin-left: var(--docku-space-2);
  padding: 1px 6px;
  border-radius: 999px;
  background: rgba(146, 64, 14, 0.12);
  color: var(--docku-warning-text);
  font-size: 0.78em;
  font-weight: 600;
  letter-spacing: 0.04em;
}

/* ── Import-from-file section (DocumentCreate, first section) ──
   Reuses the .form-section / .card card-flush shell.  The header
   becomes a clickable checkbox gate (label wraps the whole row).
   Body slides in/out via v-show; we don't animate height to keep
   simple markup and predictable focus behaviour. */
.import-section .form-section-header {
  padding: 0;
}
.import-gate {
  display: grid;
  grid-template-columns: auto 2.25rem 1fr auto;
  align-items: center;
  gap: var(--docku-space-3);
  padding: var(--docku-space-4) var(--docku-space-5);
  cursor: pointer;
  user-select: none;
  border-radius: var(--docku-radius-lg, 12px);
  transition: background-color 0.15s ease;
}
.import-gate:hover {
  background: rgba(15, 23, 42, 0.04);
}
.import-gate input[type="checkbox"] {
  width: 1.05rem;
  height: 1.05rem;
  margin: 0;
  cursor: pointer;
  accent-color: var(--docku-primary, #4f46e5);
}
.import-gate-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.25rem;
  height: 2.25rem;
  border-radius: var(--docku-radius-md, 10px);
  background: linear-gradient(135deg, rgba(79, 70, 229, 0.16), rgba(124, 58, 237, 0.16));
  color: var(--docku-primary, #4f46e5);
  font-size: 1.05rem;
}
.import-gate-text h3 {
  margin: 0;
  font-size: 1.05rem;
  display: flex;
  align-items: center;
  gap: var(--docku-space-2);
}
.import-gate-text p {
  margin: 2px 0 0 0;
  color: var(--docku-text-muted, #64748b);
  font-size: 0.88rem;
}
.import-gate-text code {
  background: rgba(15, 23, 42, 0.06);
  padding: 1px 5px;
  border-radius: 4px;
  font-size: 0.85em;
}
.import-gate-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2rem;
  height: 2rem;
  color: var(--docku-text-muted, #64748b);
  font-size: 1rem;
}
.import-section-body {
  display: flex;
  flex-direction: column;
  gap: var(--docku-space-4);
  padding: 0 var(--docku-space-5) var(--docku-space-5);
}

/* Drop / pick zone.  Inherits .content-upload-empty styling and adds
   the drag-active highlight.  Uses a thick dashed border that flips
   solid on .is-dragging. */
.autofill-dropzone {
  position: relative;
  border: 2px dashed rgba(79, 70, 229, 0.32);
  border-radius: var(--docku-radius-md, 10px);
  transition: background-color 0.15s ease, border-color 0.15s ease, transform 0.15s ease;
}
.autofill-dropzone.is-dragging {
  border-color: var(--docku-primary, #4f46e5);
  border-style: solid;
  background: rgba(79, 70, 229, 0.06);
  transform: scale(1.005);
}
.autofill-dropzone.is-loading {
  border-color: rgba(79, 70, 229, 0.32);
  background: rgba(79, 70, 229, 0.03);
}
.autofill-dropzone.is-staged {
  border-color: rgba(79, 70, 229, 0.32);
  background: rgba(79, 70, 229, 0.03);
}
.autofill-stage-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  justify-content: center;
  margin-top: 0.75rem;
}

/* Minimal status card shown after a successful auto-fill. */
.autofill-summary {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.75rem 1rem;
  border: 1px solid rgba(15, 23, 42, 0.10);
  border-radius: var(--docku-radius-md, 10px);
  background: var(--docku-surface-soft, #f8fafc);
  color: var(--docku-text, #0f172a);
}
.autofill-summary > i {
  color: var(--docku-success, #16a34a);
  font-size: 1.1rem;
}
.autofill-summary-text {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  align-items: baseline;
}
.autofill-summary-text strong {
  font-weight: 600;
}
.autofill-summary__ai-btn {
  margin-left: auto;
}
.autofill-summary__ai-note {
  font-size: 0.85rem;
  color: var(--docku-success, #16a34a);
}
.autofill-summary__ai-error {
  font-size: 0.85rem;
  color: var(--docku-danger, #dc2626);
}

/* (Legacy preview-card rules below are kept in case any other
   surface still references them; the autofill import flow no
   longer renders the preview card.) */
.autofill-preview {
  border: 1px solid rgba(15, 23, 42, 0.10);
  border-radius: var(--docku-radius-md, 10px);
  background: var(--docku-surface-soft, #f8fafc);
  padding: var(--docku-space-4);
  display: flex;
  flex-direction: column;
  gap: var(--docku-space-3);
}
.autofill-preview-header {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--docku-space-3);
}
.autofill-preview-summary {
  display: flex;
  align-items: flex-start;
  gap: var(--docku-space-3);
  flex: 1 1 240px;
  min-width: 0;
}
.autofill-preview-summary > i {
  color: var(--docku-primary, #4f46e5);
  font-size: 1.2rem;
  margin-top: 2px;
}
.autofill-preview-summary strong {
  display: block;
  font-size: 0.95rem;
  word-break: break-all;
}
.autofill-preview-summary span {
  color: var(--docku-text-muted, #64748b);
  font-size: 0.85rem;
}
.autofill-preview-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--docku-space-2);
}
.autofill-preview-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--docku-space-2);
}
.preview-row {
  display: grid;
  grid-template-columns: 200px 1fr;
  gap: var(--docku-space-3);
  padding: var(--docku-space-2) var(--docku-space-3);
  background: var(--docku-surface, #ffffff);
  border: 1px solid rgba(15, 23, 42, 0.06);
  border-radius: var(--docku-radius-sm, 6px);
  font-size: 0.9rem;
}
.preview-row-label {
  font-weight: 600;
  color: var(--docku-text-muted, #475569);
}
.preview-row-value {
  word-break: break-word;
  white-space: pre-wrap;
  max-height: 7.5rem;
  overflow: auto;
}
.autofill-preview-toggle {
  align-self: flex-start;
}
.autofill-preview-note {
  margin: 0;
  font-size: 0.85rem;
  color: var(--docku-text-muted, #64748b);
  display: flex;
  align-items: center;
  gap: var(--docku-space-2);
}

/* Post-apply status row. */
.autofill-applied {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--docku-space-3);
  padding: var(--docku-space-3) var(--docku-space-4);
  background: rgba(34, 197, 94, 0.08);
  border: 1px solid rgba(34, 197, 94, 0.24);
  border-radius: var(--docku-radius-md, 10px);
  color: #166534;
  font-size: 0.9rem;
}
.autofill-applied > i {
  font-size: 1.1rem;
}

/* Typed error card.  Inherits .app-banner.error.  Lays out icon /
   text / actions on one row, collapsing on small screens. */
.autofill-error {
  display: flex;
  align-items: flex-start;
  gap: var(--docku-space-3);
}
.autofill-error > i {
  font-size: 1.2rem;
  margin-top: 2px;
}
.autofill-error-text {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  gap: var(--docku-space-1);
}
.autofill-error-text p {
  margin: 0;
  font-size: 0.9rem;
}
.autofill-error-raw {
  margin-top: var(--docku-space-2);
  font-size: 0.8rem;
}
.autofill-error-raw summary {
  cursor: pointer;
  color: var(--docku-text-muted, #64748b);
}
.autofill-error-raw pre {
  margin: var(--docku-space-2) 0 0 0;
  padding: var(--docku-space-2);
  background: rgba(15, 23, 42, 0.05);
  border-radius: 6px;
  overflow: auto;
  max-height: 12rem;
}
.autofill-error-actions {
  display: flex;
  flex-direction: column;
  gap: var(--docku-space-2);
}

/* Mobile: stack the preview row + hide side-by-side.  Hit-target
   padding matches the rest of the page's 640px breakpoint. */
@media (max-width: 768px) {
  .preview-row {
    grid-template-columns: 1fr;
    gap: var(--docku-space-1);
  }
  .preview-row-label {
    font-size: 0.8rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
  }
}
@media (max-width: 640px) {
  .import-gate {
    padding: var(--docku-space-3) var(--docku-space-4);
    grid-template-columns: auto 2rem 1fr auto;
  }
  .autofill-preview-header {
    flex-direction: column;
    align-items: stretch;
  }
  .autofill-preview-actions {
    width: 100%;
  }
  .autofill-preview-actions .btn {
    flex: 1 1 auto;
    min-height: 44px;
  }
  .autofill-error {
    flex-direction: column;
  }
  .autofill-error-actions {
    width: 100%;
    flex-direction: row;
  }
  .autofill-error-actions .btn {
    flex: 1 1 auto;
    min-height: 44px;
  }
}

