@charset "UTF-8";
/* ===========================================
   TEISUTIS - Bulma-based Theme (SCSS build)
   ===========================================
   Source: scss/theme.scss → compiled to css/theme.css
   =========================================== */
/* Critical: hide Alpine-cloaked content until JS runs (functional precedence) */
[x-cloak] {
  display: none !important;
}

/* Bulma is loaded via a separate <link> in base.html / base_minimal.html
   (alongside fontawesome.min.css), BEFORE this theme.css so theme can
   override Bulma defaults. Vendor stylesheets do NOT belong in compiled
   SCSS via the runtime-relative-URL form — Sass copies the directive
   verbatim into the compiled CSS, the browser then resolves the URL
   against the compiled CSS file's path, and any STATIC_URL change or
   per-app static-folder relocation breaks the import (with no Sass-time
   error). The vendor <link> tag in the base templates is the
   authoritative path; nothing in this file imports vendor CSS. */
/* ===========================================
   SCSS Variables → CSS custom properties
   Phase 2: Single source for colors, spacing, typography
   =========================================== */
/* ---- UI constants ---- */
/* ---- Typography (font stacks and size scale) ---- */
/* ---- Spacing scale ---- */
/* ---- Line height ---- */
/* ---- Widget / control dimensions ---- */
/* ---- Palette: 8 named base colors ---- */
/* Functional role aliases */
/* Hover shades (auto-computed: darken for light, lighten for dark) */
/* Dark theme palette (mirrors light: light-text↔dark-bg, dark-text↔light-bg) */
/* ---- :root (light theme) ---- */
:root {
  /* Bulma scheme overrides: neutralize blue hue (221°→0°) to prevent tints */
  --bulma-scheme-h: 0;
  --bulma-scheme-s: 0%;
  --bulma-card-shadow: none;
  --bulma-card-header-shadow: none;
  --bulma-card-header-background-color: transparent;
  --bulma-card-content-background-color: transparent;
  --bulma-card-background-color: transparent;
  --bulma-dropdown-content-background-color: var(--bg-secondary);
  --bulma-box-shadow: none;
  --bulma-box-background-color: var(--bg-secondary);
  --bulma-table-background-color: transparent;
  --bulma-table-head-background-color: transparent;
  --bulma-table-body-background-color: transparent;
  --bulma-table-cell-heading-color: var(--text-primary);
  --bulma-table-color: var(--text-primary);
  --bulma-table-striped-row-even-background-color: var(--bg-table-stripe);
  --bulma-table-striped-row-even-hover-background-color: var(--bg-table-stripe);
  --bulma-table-row-hover-background-color: var(--bg-tertiary);
  /* Named palette (8 base colors) */
  --color-red: #dc2626;
  --color-orange: #e5730a;
  --color-brass: #a08914;
  --color-green: #16a34a;
  --color-teal: #0d9488;
  --color-blue: #2563eb;
  --color-purple: #7c3aed;
  --color-pink: #db2777;
  /* Functional colors */
  --color-primary: #a08914;
  --color-primary-hover: #5c4f0c;
  --color-secondary: #7c3aed;
  --color-secondary-hover: #5512c8;
  --color-success: #16a34a;
  --color-success-hover: #0d602b;
  --color-danger: #dc2626;
  --color-danger-hover: #9c1919;
  --color-warning: #e5730a;
  --color-warning-hover: #9c4e07;
  --color-info: #2563eb;
  --color-info-hover: #1043b3;
  /* Background Colors */
  --bg-primary: #fafafa;
  --bg-secondary: #ffffff;
  --bg-tertiary: #ededed;
  --bg-accent: #282828;
  /* Text Colors */
  --text-primary: #181818;
  --text-secondary: #727272;
  --text-muted: #a2a2a2;
  --text-accent: #fafafa;
  /* Border Colors */
  --border-light: #dedede;
  --border-primary: #cccccc;
  --border-secondary: #a2a2a2;
  /* Spacing */
  --space-sm: 0.5rem;
  --space-sm-md: 0.75rem;
  --space-md: 1rem;
  --space-lg: 1.5rem;
  /* Font sizes (from typography scale) */
  --font-size-2xs: 0.625rem;
  --font-size-xs: 0.75rem;
  --font-size-sm: 0.875rem;
  --font-size-base: 1rem;
  --font-size-md: 1.125rem;
  --font-size-lg: 1.25rem;
  --font-size-xl: 1.5rem;
  --font-size-2xl: 2rem;
  --font-size-3xl: 2.5rem;
  --font-size-4xl: 3rem;
  /* Neutrals (shadows, overlays) */
  --color-white: #ffffff;
  --color-black: #000000;
  --shadow-color: rgba(0, 0, 0, 0.1);
  --shadow-color-medium: rgba(0, 0, 0, 0.15);
  --shadow-color-strong: rgba(0, 0, 0, 0.3);
  --code-bg: rgba(0, 0, 0, 0.05);
  /* Picker/tag selection ring (primary tint) */
  --picker-selected-ring: rgba(160, 137, 20, 0.3);
  /* Brand / link (reference other vars) */
  --color-brand: var(--color-secondary);
  --link-color: var(--color-secondary);
  --link-hover-color: var(--color-secondary-hover);
  /* Opacity variants (from SCSS palette) - badge/notification backgrounds */
  --color-success-bg: rgba(22, 163, 74, 0.1);
  --color-success-border: rgba(22, 163, 74, 0.2);
  --color-warning-bg: rgba(229, 115, 10, 0.1);
  --color-warning-border: rgba(229, 115, 10, 0.2);
  --color-danger-bg: rgba(220, 38, 38, 0.1);
  --color-danger-border: rgba(220, 38, 38, 0.2);
  --color-info-bg: rgba(37, 99, 235, 0.1);
  --color-secondary-bg: rgba(124, 58, 237, 0.1);
  /* Opaque light-tint backgrounds (buttons, notifications layered above fixed UI) */
  --color-success-bg-solid: #e3f4e9;
  --color-warning-bg-solid: #fceee2;
  --color-danger-bg-solid: #fbe5e5;
  --color-info-bg-solid: #e5ecfd;
  --color-primary-bg-solid: #f4f1e3;
  /* Pill text/border in light theme – darker shade for contrast on tint bg (GH #170) */
  --color-success-pill-fg: #0d602b;
  --color-warning-pill-fg: #9c4e07;
  --color-danger-pill-fg: #9c1919;
  --color-info-pill-fg: #1043b3;
  /* Table stripe (between --bg-secondary and --bg-tertiary) */
  --bg-table-stripe: #f5f5f5;
  /* Scrollbars */
  --scrollbar-track: transparent;
  --scrollbar-thumb: rgba(0, 0, 0, 0.2);
  --scrollbar-thumb-hover: rgba(0, 0, 0, 0.38);
  /* Chat - user (grey) */
  --chat-user-bg: #dedede;
  --chat-user-text: #181818;
  --chat-user-border: #cccccc;
  /* Chat - assistant (neutral) */
  --chat-assistant-bg: #ededed;
  --chat-assistant-text: var(--text-primary);
  --chat-assistant-border: #dedede;
  /* IDEA-124 — audio bubble + chip wrapper colours. The native <audio
   * controls> chrome inherits the UA theme; we recolour only the wrapper
   * and the fallback "Download to play" link so dark-mode pages don't show
   * a white-bordered island around the dark-themed controls. */
  --audio-wrapper-bg: transparent;
  --audio-wrapper-border: transparent;
  --audio-fallback-link-color: var(--link-color);
  /* IDEA-129 — live recording waveform bar colour. The canvas reads this
   * via getComputedStyle on construction; light default is brand primary. */
  --voice-waveform-bar-color: #a08914;
  /* IDEA-197 — semantic CSS-variable aliases for tag/badge restyle.
   * --color-text-{semantic} → darkened pill-fg (NOT base) for WCAG AA on
   * the 12%-mix bg in light theme (architect F1). --color-background-{semantic}
   * aliases the existing -bg-solid (opaque 12% mix) for badge readability.
   * Naming caveat: the new --color-background-* names live alongside
   * pre-existing --color-*-bg-solid; future sweeps should consolidate. */
  --color-text-success: var(--color-success-pill-fg);
  --color-text-warning: var(--color-warning-pill-fg);
  --color-text-danger: var(--color-danger-pill-fg);
  --color-text-info: var(--color-info-pill-fg);
  --color-background-success: var(--color-success-bg-solid);
  --color-background-warning: var(--color-warning-bg-solid);
  --color-background-danger: var(--color-danger-bg-solid);
  --color-background-info: var(--color-info-bg-solid);
  /* IDEA-197 — explicit border-radius vocabulary (md for tags/badges,
   * lg reserved for cards/drawers). Only md + lg added; broader scale
   * codification deferred to a separate IDEA. */
  --border-radius-md: 6px;
  --border-radius-lg: 12px;
}

/* ---- Dark theme overrides ---- */
.dark {
  --bg-primary: #181818;
  --bg-secondary: #282828;
  --bg-tertiary: #404040;
  --bg-accent: #fafafa;
  --text-primary: #fafafa;
  --text-secondary: #a2a2a2;
  --text-muted: #727272;
  --border-light: #404040;
  --border-primary: #545454;
  --border-secondary: #404040;
  --color-brand: var(--color-primary);
  --link-color: var(--color-primary);
  --link-hover-color: var(--color-primary-hover);
  --bulma-link: var(--color-primary);
  --bulma-link-hover: var(--color-primary-hover);
  /* Lighter hover shades for dark theme */
  --color-primary-hover: #e3c21e;
  --color-secondary-hover: #ab80f3;
  --color-success-hover: #24e16a;
  --color-danger-hover: #e76868;
  --color-warning-hover: #f79a45;
  --color-info-hover: #6b95f1;
  --chat-user-bg: #404040;
  --chat-user-text: #fafafa;
  --chat-user-border: #545454;
  --chat-assistant-bg: var(--bg-primary);
  --chat-assistant-text: var(--text-primary);
  --chat-assistant-border: #404040;
  --code-bg: rgba(255, 255, 255, 0.1);
  --picker-selected-ring: rgba(160, 137, 20, 0.4);
  /* Opaque notification backgrounds (dark theme) */
  --color-success-bg-solid: rgba(22, 163, 74, 0.25);
  --color-warning-bg-solid: rgba(229, 115, 10, 0.25);
  --color-danger-bg-solid: rgba(220, 38, 38, 0.25);
  --color-info-bg-solid: rgba(37, 99, 235, 0.25);
  --color-primary-bg-solid: rgba(160, 137, 20, 0.25);
  /* Table stripe */
  --bg-table-stripe: #323232;
  /* Scrollbars */
  --scrollbar-track: transparent;
  --scrollbar-thumb: rgba(255, 255, 255, 0.25);
  --scrollbar-thumb-hover: rgba(255, 255, 255, 0.45);
  /* Pill text: keep semantic color (readable on dark tinted bg) */
  --color-success-pill-fg: var(--color-success);
  --color-warning-pill-fg: var(--color-warning);
  --color-danger-pill-fg: var(--color-danger);
  --color-info-pill-fg: var(--color-info);
  /* IDEA-197 user steer 2026-05-28: filled-bg tag text needs much higher
   * lightness in dark theme to match the perceptual contrast light theme
   * achieves (dark text on light tint). Override the --color-text-*
   * aliases (used by .tag.is-*) with a 35%-lightened semantic so the
   * pill text reads bright against the 25%-rgba dark tint bg. Leaves the
   * underlying --color-*-pill-fg variable as-is (preserves the prior
   * semantic-color-on-dark-tint contract for any non-tag callers). */
  --color-text-success: #7eeea7;
  --color-text-warning: #fbcfa6;
  --color-text-danger: #f5c0c0;
  --color-text-info: #c9d8fa;
  /* IDEA-124 — dark-mode audio wrapper + fallback link. Wrapper uses a
   * subtle dark tint so the native controls' shadow-DOM chrome (whose UA
   * theme follows the OS preference, not our class) doesn't sit on a hard
   * white background. Fallback link uses the brand link colour, which the
   * top of this block already remaps to ``--color-primary`` lighter shade
   * for dark mode — WCAG AA contrast against ``$dark-bg-tertiary`` (the
   * chat user bubble) is ≥ 4.5:1 by inheritance. */
  --audio-wrapper-bg: rgba(255, 255, 255, 0.04);
  --audio-wrapper-border: #404040;
  --audio-fallback-link-color: var(--color-primary-hover);
  /* IDEA-129 — dark-mode bar colour. Lighter shade of brand primary so
   * bars stay visible against the dark recording-status background. */
  --voice-waveform-bar-color: var(--color-primary-hover);
}

/* ---- Bulma mapping ( :root ) ---- */
:root {
  --bulma-primary: var(--color-primary);
  --bulma-primary-hover: var(--color-primary-hover);
  --bulma-link: var(--link-color);
  --bulma-link-hover: var(--link-hover-color);
  --bulma-success: var(--color-success);
  --bulma-danger: var(--color-danger);
  --bulma-warning: var(--color-warning);
  --bulma-info: var(--color-info);
  --bulma-light: var(--bg-tertiary);
}

/* ===========================================
   Reusable mixins (Phase 4)
   Breakpoints, sticky backgrounds, button variants
   =========================================== */
/* Breakpoints: mobile ≤768px, tablet 769–1024px, desktop ≥1025px */
/** Wrap content in mobile-only media query (max-width: 768px) */
/** Wrap content in tablet-and-up media query (min-width: 769px) */
/** Wrap content in desktop-only media query (min-width: 1025px) */
/** Wrap content in tablet-only media query (769px–1024px) */
/** Solid background for sticky table cells (avoids duplicate background + background-color) */
/**
 * Thin, neutral scrollbar using CSS custom properties.
 * Colors are defined in _variables.scss (--scrollbar-track/thumb/thumb-hover)
 * and automatically switch with the .dark theme class — no per-component
 * dark-mode nesting required.
 *
 * $width  — scrollbar width/height (defaults to $scrollbar-width)
 */
/**
 * Elevated surface for card-like containers (.card, .box, .stat-card, .panel).
 * Single source of truth for container appearance — change once, applies everywhere.
 */
/** Section divider (card-header bottom, section separators) */
/* Neutralise the ``_cards.scss`` mobile table-bleed (IDEA-150/203/201/145).
   ``_cards.scss``'s ``@include mobile { .card-content > .table-scroll-container
   { margin-left: -0.5rem; margin-right: -0.5rem; width: calc(100% + 1rem); } }``
   negative-margin bleed is calibrated for content that should run edge-to-edge
   of a full-width card. Inside a SHELL surface (org-management centre, billing
   centre, preview/workspace drawer, dashboard admin widgets) the card sits in a
   narrower column/pane, so the uncompensated negative margins push the table
   PAST the card edge — the "table explodes out of the card" mobile defect.

   This mixin resets the bleed so the table fits exactly inside the card. It is
   the single source of truth for the four surfaces that re-house
   ``.card-content > .table-scroll-container`` inside a shell pane. Also resets
   the legacy ``div[style*="overflow-x"]`` siblings the bleed selector targets.

   MUST be ``@include``d from inside an ``@include mobile { … }`` block (it emits
   no media query of its own — Sass forbids ``@extend``-ing a placeholder across
   a media boundary, so a mixin is the cross-context-shareable form). */
/** Solid button variant: fill + border with same color, white text; hover uses hover var */
/* IDEA-201: shared edge-lip visual. The single source of truth for the
   edge affordance look so the desktop drawer ``__edge-control`` and the
   mobile pane edge-lip rails stay consistent — a thin transparent strip
   with a centred 2px spine + a circular chevron badge, on the same colour
   tokens. Consumers ``@include`` these and add their own positioning /
   interaction bits (cursor, gutter, gesture).

   NB: these are MIXINS, not %placeholders, because the mobile pane-lip
   consumer lives inside a ``@media`` block and Sass forbids ``@extend``-ing
   a top-level placeholder across a media-query boundary. A mixin inlines the
   declarations, which is exactly what's needed for a cross-context shared
   look. */
/* The circular chevron badge that rides the spine. */
/* ===========================================
   Utility classes: accessibility, loading, generic
   =========================================== */
/* ---- Screen reader only (visually hidden, accessible to AT) ---- */
.is-sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border-width: 0;
}

/* ---- Disabled / muted row (e.g. scope with is_enabled=False) ---- */
.is-disabled {
  opacity: 0.6;
}

/* ---- Flex gap utility (0.5rem) ---- */
.gap-2 {
  gap: 0.5rem;
}

/* ---- HR divider (full width, no margin) ---- */
.hr-full {
  width: 100%;
  margin: 0;
}

/* ---- Flex shrink (allow flex child to shrink below content) ---- */
.min-width-0 {
  min-width: 0;
}

/* ---- Cursor pointer (clickable elements) ---- */
.cursor-pointer {
  cursor: pointer;
}

/* ---- Loading indicators ---- */
.htmx-indicator {
  display: none;
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  z-index: 9999;
}

.spinner {
  width: 16px;
  height: 16px;
  border: 2px solid var(--border-light);
  border-top: 2px solid var(--color-primary);
  border-radius: 50%;
  animation: spin 1s linear infinite;
}

@keyframes spin {
  0% {
    transform: rotate(0deg);
  }
  100% {
    transform: rotate(360deg);
  }
}

/* ---- Global thin scrollbar for all scrollable elements ---- */
* {
  scrollbar-width: thin;
  scrollbar-color: var(--scrollbar-thumb) var(--scrollbar-track);
}

*::-webkit-scrollbar {
  width: 6px;
  height: 6px;
}

*::-webkit-scrollbar-track {
  background: var(--scrollbar-track);
  border-radius: calc(6px / 2);
}

*::-webkit-scrollbar-thumb {
  background: var(--scrollbar-thumb);
  border-radius: calc(6px / 2);
}

*::-webkit-scrollbar-thumb:hover {
  background: var(--scrollbar-thumb-hover);
}

/* Mermaid error fallback: show raw source instead of broken SVG */
.mermaid-error-fallback {
  background-color: var(--code-bg);
  color: var(--text-secondary);
  padding: 1em;
  border-radius: 4px;
  overflow-x: auto;
  font-size: 0.85em;
  margin-top: 0.25em;
}

.mermaid-error-fallback code {
  background-color: transparent;
  padding: 0;
}

/* ===========================================
   Typography: text utilities, headings, links
   Font stacks in _variables.scss; use $font-mono etc. here.
   =========================================== */
/* ---- Link colors (prevent Bulma violet) ---- */
a,
.has-text-link {
  color: var(--link-color) !important;
}

a:hover,
.has-text-link:hover {
  color: var(--link-hover-color) !important;
}

/* ---- Heading sizes (h1–h6 and Bulma .title) ---- */
/* One step down so event-with-date (h1) fits on one line in all views. */
h1, .title.is-1 {
  font-size: 2.5rem !important;
}

h2, .title.is-2 {
  font-size: 2rem !important;
}

h3, .title.is-3 {
  font-size: 1.5rem !important;
}

h4, .title.is-4 {
  font-size: 1.25rem !important;
}

h5, .title.is-5 {
  font-size: 1.125rem !important;
}

h6, .title.is-6 {
  font-size: 1rem !important;
}

/* ---- Heading line-height and spacing (global) ---- */
/* Tight line-height so space between heading lines is never bigger than space
   between heading and content below; margin-bottom >= effective line gap. */
h1, h2, h3, h4, h5, h6,
.title.is-1, .title.is-2, .title.is-3, .title.is-4, .title.is-5, .title.is-6 {
  line-height: 1.25 !important;
  margin-bottom: 0.5em !important;
}

h1, .title.is-1 {
  margin-top: 0 !important;
}

h2, h3, h4, h5, h6,
.title.is-2, .title.is-3, .title.is-4, .title.is-5, .title.is-6 {
  margin-top: 1em !important;
}

h2:first-child, h3:first-child, h4:first-child, h5:first-child, h6:first-child,
.title.is-2:first-child, .title.is-3:first-child, .title.is-4:first-child,
.title.is-5:first-child, .title.is-6:first-child {
  margin-top: 0 !important;
}

/* ---- Subtitle (single definition: size, color, no extra margin) ---- */
.subtitle {
  font-size: 1.25rem !important;
  color: var(--text-secondary) !important;
  margin-bottom: 0;
}

/* ---- Utility headings ---- */
.heading-2xl {
  font-size: 1.5rem;
  font-weight: 700;
  color: var(--text-primary);
  margin-bottom: 0.5rem;
}

/* ---- Text utilities (use in templates) ---- */
.text-decoration-none {
  text-decoration: none;
}

.font-mono {
  font-family: "SF Mono", "Monaco", "Inconsolata", "Roboto Mono", monospace;
  font-size: 0.875rem;
}

.text-secondary {
  color: var(--text-secondary);
}

/* Grey text: use theme muted color instead of Bulma has-text-grey default */
.has-text-grey {
  color: var(--text-muted) !important;
}

/* Icon/text on colored background (buttons, stat-card icons) */
.icon-white {
  color: var(--color-white);
}

/* ---- Mobile: heading sizes (2xl–sm), no margin overrides ---- */
/* Single place for mobile typography; global line-height/margin apply. */
@media screen and (max-width: 768px) {
  h1, .title.is-1 {
    font-size: 2rem !important;
  }
  h2, .title.is-2 {
    font-size: 1.5rem !important;
  }
  h3, .title.is-3 {
    font-size: 1.25rem !important;
  }
  h4, .title.is-4 {
    font-size: 1.125rem !important;
  }
  h5, .title.is-5 {
    font-size: 1rem !important;
  }
  h6, .title.is-6 {
    font-size: 0.875rem !important;
  }
}

/* ===========================================
   Buttons (primary, secondary, light, icon alignment, groups)
   =========================================== */
/* Primary colors */
.has-background-primary {
  background-color: var(--color-primary) !important;
}

.has-background-primary-dark {
  background-color: var(--color-primary-hover) !important;
}

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

.has-text-primary-dark {
  color: var(--color-primary-hover) !important;
}

.button {
  /* Outlined secondary: .button and a.button (links styled as buttons) */
  /* Semantic solid buttons (guarded: not .is-light, not .is-outlined) */
  /* Icon spacing: use gap on the flex container instead of fragile child margins */
  gap: 0.375em;
}

.button.is-primary:not(.is-light):not(.is-outlined) {
  background-color: var(--color-primary) !important;
  border-color: var(--color-primary) !important;
  color: white !important;
}

.button.is-primary:not(.is-light):not(.is-outlined):hover {
  background-color: var(--color-primary-hover) !important;
  border-color: var(--color-primary-hover) !important;
  color: white !important;
}

.button.is-secondary:not(.is-light):not(.is-outlined) {
  background-color: var(--color-secondary) !important;
  border-color: var(--color-secondary) !important;
  color: white !important;
}

.button.is-secondary:not(.is-light):not(.is-outlined):hover {
  background-color: var(--color-secondary-hover) !important;
  border-color: var(--color-secondary-hover) !important;
  color: white !important;
}

.button.is-link:not(.is-light):not(.is-outlined) {
  background-color: var(--link-color) !important;
  border-color: var(--link-color) !important;
  color: white !important;
}

.button.is-link:not(.is-light):not(.is-outlined):hover {
  background-color: var(--link-hover-color) !important;
  border-color: var(--link-hover-color) !important;
  color: white !important;
}

.button.is-secondary.is-outlined,
.button a.button.is-secondary.is-outlined {
  background-color: transparent !important;
  background: transparent !important;
  border-color: var(--color-secondary) !important;
  color: var(--color-secondary) !important;
}

.button.is-secondary.is-outlined:hover,
.button a.button.is-secondary.is-outlined:hover {
  background-color: var(--color-secondary) !important;
  background: var(--color-secondary) !important;
  border-color: var(--color-secondary) !important;
  color: var(--color-white) !important;
}

.button.is-light {
  background-color: var(--bg-tertiary) !important;
  border-color: var(--text-muted) !important;
  color: var(--text-primary) !important;
  /* Override Bulma variables */
  --bulma-button-background-l: 95 !important;
  --bulma-button-border-l: 90 !important;
  --bulma-button-color-l: 20 !important;
  /* Dark theme: lighten on hover (consistent with colored button convention) */
}

.button.is-light:hover {
  background-color: var(--bg-secondary) !important;
  border-color: var(--text-secondary) !important;
  color: var(--text-primary) !important;
  /* Override Bulma hover variables for light theme */
  --bulma-button-background-l: 98 !important;
  --bulma-button-border-l: 85 !important;
  --bulma-button-color-l: 15 !important;
}

.dark .button.is-light:hover {
  background-color: var(--border-primary) !important;
  border-color: var(--text-muted) !important;
  color: var(--text-accent) !important;
  --bulma-button-background-l: 35 !important;
  --bulma-button-border-l: 50 !important;
  --bulma-button-color-l: 95 !important;
}

.button.is-success:not(.is-light):not(.is-outlined) {
  background-color: var(--color-success) !important;
  border-color: var(--color-success) !important;
  color: white !important;
}

.button.is-success:not(.is-light):not(.is-outlined):hover {
  background-color: var(--color-success-hover) !important;
  border-color: var(--color-success-hover) !important;
  color: white !important;
}

.button.is-danger:not(.is-light):not(.is-outlined) {
  background-color: var(--color-danger) !important;
  border-color: var(--color-danger) !important;
  color: white !important;
}

.button.is-danger:not(.is-light):not(.is-outlined):hover {
  background-color: var(--color-danger-hover) !important;
  border-color: var(--color-danger-hover) !important;
  color: white !important;
}

.button.is-warning:not(.is-light):not(.is-outlined) {
  background-color: var(--color-warning) !important;
  border-color: var(--color-warning) !important;
  color: white !important;
}

.button.is-warning:not(.is-light):not(.is-outlined):hover {
  background-color: var(--color-warning-hover) !important;
  border-color: var(--color-warning-hover) !important;
  color: white !important;
}

.button.is-info:not(.is-light):not(.is-outlined) {
  background-color: var(--color-info) !important;
  border-color: var(--color-info) !important;
  color: white !important;
}

.button.is-info:not(.is-light):not(.is-outlined):hover {
  background-color: var(--color-info-hover) !important;
  border-color: var(--color-info-hover) !important;
  color: white !important;
}

.button .icon,
.button svg.icon {
  width: 1em;
  height: 1em;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  margin: 0 !important;
}

/* Button groups: .buttons (default) and .buttons.is-compact (tight, e.g. table row actions) */
.buttons {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  /* Tight group for icon-only or table actions (View/Edit/Delete) */
}

.buttons .button {
  margin: 0;
}

.buttons.is-compact {
  display: inline-flex;
  gap: 0.25rem;
  align-items: center;
}

.buttons.is-compact .button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

@media screen and (max-width: 768px) {
  .box .level-right .buttons .button,
.card-content .level-right .buttons .button,
.level .level-right .buttons .button {
    padding: 0.375rem 0.5rem 0.375rem 0.75rem;
    /* left padding so icon not flush */
    font-size: 0.75rem;
    min-width: auto;
  }
  .box .level-right .buttons .button .is-hidden-mobile,
.card-content .level-right .buttons .button .is-hidden-mobile,
.level .level-right .buttons .button .is-hidden-mobile {
    display: inline !important;
  }
  .box .level-right .buttons .button .icon,
.card-content .level-right .buttons .button .icon,
.level .level-right .buttons .button .icon {
    font-size: 0.75rem;
    width: 0.875rem;
    height: 0.875rem;
  }
  .buttons.is-compact .button {
    padding: 0.375rem;
    min-width: auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
  }
  .buttons.is-compact .button .icon + span, .buttons.is-compact .button span:not(.icon) {
    display: none;
  }
  .buttons.is-compact .button .icon, .buttons.is-compact .button svg.icon {
    margin-inline-start: 0;
    margin-inline-end: 0;
    width: 1rem;
    height: 1rem;
  }
}

/* ===========================================
   Cards, panel, stats grid, info grid
   =========================================== */
/* Organization detail page - stats grid */
.stats-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 1.5rem;
  margin-bottom: 2rem;
}

.stat-card {
  background: var(--bg-secondary) !important;
  background-color: var(--bg-secondary) !important;
  color: var(--text-primary);
  border: none;
  border-radius: 0.5rem;
  box-shadow: 0 2px 8px -2px var(--shadow-color), 0 0 0 1px var(--border-light) !important;
  padding: 1.5rem;
  text-align: center;
  transition: all 0.2s ease;
}

.stat-card:hover {
  box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
}

.stat-card .stat-icon {
  width: 3rem;
  height: 3rem;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  margin: 0 auto 1rem;
  font-size: 1.5rem;
}

.stat-card .stat-icon-blue {
  background-color: rgba(37, 99, 235, 0.1);
  color: var(--color-info);
}

.stat-card .stat-icon-green {
  background-color: rgba(22, 163, 74, 0.1);
  color: var(--color-success);
}

.stat-card .stat-icon-orange {
  background-color: var(--color-warning-bg);
  color: var(--color-warning);
}

.stat-card .stat-icon-purple {
  background-color: rgba(124, 58, 237, 0.1);
  color: var(--color-purple);
}

.stat-card .stat-value {
  font-size: 2rem;
  font-weight: 700;
  color: var(--text-primary);
  margin-bottom: 0.25rem;
}

.stat-card .stat-label {
  color: var(--text-secondary);
  font-size: 0.875rem;
  font-weight: 500;
}

/* Primary feature cards (3 cards): equal height, icon + title + text centered in remaining space */
.feature-cards-row {
  display: flex;
  align-items: stretch;
  /* Mobile: tighter font sizes */
  /* Mobile: stack cards vertically (icons + padding exceed 1/3 viewport), tighter gap */
}

.feature-cards-row .column {
  display: flex;
}

.feature-cards-row .card {
  flex: 1;
  display: flex;
  flex-direction: column;
  width: 100%;
}

.feature-cards-row .card-content {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-height: 0;
}

.feature-cards-row .card-content .feature-icon-wrapper {
  flex-shrink: 0;
  min-height: 8rem;
  /* ~128px for icon */
}

.feature-cards-row .card-content h3 {
  flex-shrink: 0;
  line-height: 1.25;
  margin-bottom: 0.75rem;
}

.feature-cards-row .card-content .subtitle {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  margin: 0;
  text-align: center;
}

@media (max-width: 768px) {
  .feature-cards-row .card h3 {
    font-size: 1.25rem;
  }
}

@media screen and (max-width: 768px) {
  .feature-cards-row .column {
    flex: 0 0 100%;
    max-width: 100%;
    margin-bottom: 0.75rem;
  }
  .feature-cards-row .column:last-child {
    margin-bottom: 0;
  }
  .feature-cards-row .card {
    margin-bottom: 0;
  }
}

/* Built for Hotels: card-style feature list (h4 + p per item) */
.feature-list .feature-list-item {
  padding: 1rem 1.25rem;
  margin-bottom: 0.75rem;
  background-color: var(--bg-tertiary);
  border-radius: 0.5rem;
  border: 1px solid var(--border-light);
}

.dark .feature-list .feature-list-item {
  border-color: var(--border-primary);
}

.feature-list .feature-list-item:last-child {
  margin-bottom: 0;
}

@media (max-width: 768px) {
  .feature-list .feature-list-item h4 {
    font-size: 1.25rem;
  }
}

.feature-list .feature-list-item h4 {
  font-size: 1.125rem;
  font-weight: 600;
  color: var(--text-primary);
  margin: 0 0 0.375rem;
  line-height: 1.25;
}

.feature-list .feature-list-item p {
  font-size: 0.875rem;
  color: var(--text-secondary);
  margin: 0;
  line-height: 1.4;
}

.feature-icon-wrapper {
  position: relative;
  display: flex;
  justify-content: center;
  align-items: center;
  margin: 0 auto;
}

.feature-icon-wrapper .feature-icon {
  border-radius: 1rem;
  display: block;
  border: none;
  box-shadow: none;
}

.feature-icon-wrapper .feature-icon-light {
  display: block;
}

.feature-icon-wrapper .feature-icon-dark {
  display: none;
}

.dark .feature-icon-wrapper .feature-icon-light {
  display: none;
}

.dark .feature-icon-wrapper .feature-icon-dark {
  display: block;
}

.card {
  background: var(--bg-secondary) !important;
  background-color: var(--bg-secondary) !important;
  color: var(--text-primary);
  border: none;
  border-radius: 0.5rem;
  box-shadow: 0 2px 8px -2px var(--shadow-color), 0 0 0 1px var(--border-light) !important;
  margin-bottom: 2rem;
  /* Event card: header wraps; badges drop below; row header uses same icon+text pattern as article */
  /* Reminder block: sibling of event-row-header-wrap, full-width row below date; icon left */
  /* Reminder alarm: icon left, text wraps next to it (same pattern as icon-text-row) */
  /* FAQ card: collapsible header trigger – text darkens on hover (trigger only, not context menu) */
  /* IDEA-148 R24 — featured FAQ subtle, theme-aware background shift.
   * Supersedes the legacy org-color right-border cue on the old
   * ``_faq_card.html`` (which IDEA-158 retires). The card base surface
   * is ``var(--bg-secondary)`` (see ``surface-elevated``); the featured
   * tint nudges it toward the neutral text colour in LIGHT (slightly
   * darker) and toward white in DARK (slightly brighter) — a low-
   * contrast distinction, NOT a callout. Driven by the existing
   * neutral surface custom properties (NOT ``--org-color``, which can
   * clash and isn't lightness-controlled). ``!important`` matches the
   * base mixin's specificity so the tint actually applies. Background
   * tint only — deliberately no accent border, to keep the cue subtle. */
  /* Article/event cards: dropdown icon top-right bound, no flex space reserved */
  /* Dropdown inside card - clipping and z-index (base in _dropdowns.scss) */
}

.card .card-header {
  background-color: var(--bg-tertiary);
  border-bottom: 1px solid var(--border-light);
  padding: 0.5rem;
}

.card .card-header-title {
  min-width: 0;
  overflow: hidden;
  padding: 0;
  font-size: 1.25rem;
  font-weight: 600;
  color: var(--text-primary);
  margin: 0;
  display: flex;
  align-items: center;
  gap: 0.5rem;
  /* Title/date span takes remaining space so text wraps next to icon; icon stays vertically centered (exclude .tag so pills keep size; exclude .card-header-title-count so the IDEA-197 " · N" separator stays inline at natural width) */
  /* IDEA-197 — " · N" inline count separator. Subtle, secondary-weight,
     * sits next to the title at natural width (NOT stretched by the flex
     * rule above). */
}

.card .card-header-title > span:not(.icon):not(.tag):not(.card-header-title-count) {
  flex: 1 1 0%;
  min-width: 0;
}

.card .card-header-title .card-header-title-count {
  flex: 0 0 auto;
  font-size: 0.75rem;
  font-weight: 400;
  color: var(--text-secondary);
}

.card .card-header-title .icon {
  flex-shrink: 0;
  width: 1.25rem;
  height: 1.25rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.card.event-card .card-header-title {
  flex-wrap: wrap;
}

.card .event-row-header-wrap {
  display: flex;
  flex-wrap: nowrap;
  align-items: baseline;
  gap: 0.25rem 0.5rem;
  min-width: 0;
}

.card .event-row-header-wrap .icon {
  flex-shrink: 0;
}

.card .event-row-header-wrap > span {
  flex: 1 1 auto;
  min-width: 0;
  overflow-wrap: break-word;
  word-break: break-word;
}

.card .event-reminder-block {
  flex-basis: 100%;
  width: 100%;
}

.card .event-reminder-alarm-wrap {
  display: inline-flex !important;
  flex-direction: row !important;
  flex-wrap: wrap;
  justify-content: flex-start !important;
  align-items: flex-start !important;
  text-align: left !important;
}

.card .event-reminder-alarm-wrap .event-reminder-icon {
  flex: 1 1 auto;
  min-width: 0;
  align-items: center;
  /* same as icon-text-row: center icon with text baseline */
  display: inline-flex;
  gap: 0.25rem;
}

.card .event-reminder-alarm-wrap .event-reminder-icon .icon {
  flex-shrink: 0;
}

.card .event-reminder-alarm-wrap .event-reminder-duration-text {
  overflow-wrap: break-word;
  word-break: break-word;
  min-width: 0;
}

.card.faq-card .card-header-title {
  transition: color 0.2s ease;
}

.card.faq-card .card-header-title:hover {
  color: var(--text-secondary) !important;
}

.card.faq-card.is-featured {
  background: color-mix(in srgb, var(--bg-secondary) 94%, var(--text-primary)) !important;
  background-color: color-mix(in srgb, var(--bg-secondary) 94%, var(--text-primary)) !important;
}

.dark .card.faq-card.is-featured, [data-theme='dark'] .card.faq-card.is-featured {
  background: color-mix(in srgb, var(--bg-secondary) 92%, #ffffff) !important;
  background-color: color-mix(in srgb, var(--bg-secondary) 92%, #ffffff) !important;
}

.card.article-card .card-header, .card.event-card .card-header {
  position: relative;
}

.card.article-card .card-header .card-header-icon, .card.event-card .card-header .card-header-icon {
  position: absolute;
  right: 0;
  top: 0;
  display: flex;
  align-items: flex-start;
}

.card.article-card .card-header .card-header-title, .card.event-card .card-header .card-header-title {
  padding: 0;
  margin-right: 2rem;
  /* clearance for absolute dropdown icon */
}

.card .event-card-badges {
  flex-basis: 100%;
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem;
}

.card .event-card-badges:empty {
  display: none;
}

.card .card-header-icon {
  flex-shrink: 0;
  padding: 0;
}

.card .card-content {
  padding: 1.5rem;
}

.card .card-content[style*="overflow-x"] {
  padding-left: 0;
  padding-right: 0;
}

.card .card-content > div[style*="overflow-x"],
.card .card-content > .table-scroll-container {
  margin-left: -1.5rem;
  margin-right: -1.5rem;
  width: calc(100% + 3rem);
}

.card .card-content[style*="overflow-x"] > .table th:first-child, .card .card-content[style*="overflow-x"] > .table td:first-child,
.card .card-content > div[style*="overflow-x"] > .table th:first-child,
.card .card-content > div[style*="overflow-x"] > .table td:first-child,
.card .card-content > .table-scroll-container .table th:first-child,
.card .card-content > .table-scroll-container .table td:first-child {
  padding-left: 0.5rem;
}

.card .card-content[style*="overflow-x"] > .table th:last-child, .card .card-content[style*="overflow-x"] > .table td:last-child,
.card .card-content > div[style*="overflow-x"] > .table th:last-child,
.card .card-content > div[style*="overflow-x"] > .table td:last-child,
.card .card-content > .table-scroll-container .table th:last-child,
.card .card-content > .table-scroll-container .table td:last-child {
  padding-right: 0.5rem;
}

.card .dropdown {
  overflow: visible;
}

.card .dropdown .dropdown-menu {
  z-index: 100;
}

/* ---- Attachment card: base layout (all breakpoints, all contexts) ---- */
.attachment-card {
  max-width: 100%;
  text-align: left;
}

.attachment-card .card-content {
  overflow: visible;
}

.attachment-card .media-left {
  margin-right: 0.5rem !important;
}

.attachment-card .level {
  min-width: 0;
}

.attachment-card .level-left {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  align-items: flex-start !important;
}

.attachment-card .level-left .level-item {
  justify-content: flex-start;
}

.attachment-card .level-right {
  flex-shrink: 0;
  flex-grow: 0;
  min-width: auto;
}

.attachment-card .level-right .buttons {
  flex-wrap: nowrap;
  gap: 0.25rem;
}

.attachment-card .media-content {
  overflow-x: visible !important;
  min-width: 0;
}

.attachment-card .media-content p.has-text-weight-medium a {
  text-decoration: none;
  cursor: pointer;
}

.attachment-card .media-content p.has-text-weight-medium {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
}

.attachment-card .content {
  overflow-x: visible;
}

/* ---- Article/event cards: overflow guards + level layout ---- */
.article-card,
.event-card {
  max-width: 100%;
}

.article-card .card-content,
.article-card .content,
.event-card .card-content,
.event-card .content {
  max-width: 100%;
  overflow-wrap: break-word;
  word-break: break-word;
}

.article-card .content p,
.article-card .content a,
.event-card .content p,
.event-card .content a {
  overflow-wrap: break-word;
  word-break: break-word;
}

.article-card .level,
.event-card .level {
  align-items: flex-start;
  flex-wrap: wrap;
  gap: 0.25rem;
}

.article-card .level-left,
.event-card .level-left {
  flex-basis: 100%;
  justify-content: flex-start;
  min-width: 0;
}

.article-card .level-right,
.event-card .level-right {
  flex-basis: 100%;
  margin-top: 0;
}

.article-card .level-right {
  justify-content: flex-end;
}

.event-card .level-right {
  justify-content: flex-start;
}

/* Icon + text rows: icon stays left, text wraps in remaining space (fixes address/location regression) */
.content .icon-text-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.25rem;
  min-width: 0;
}

.content .icon-text-row .icon {
  flex-shrink: 0;
}

.content .icon-text-row > a,
.content .icon-text-row > span {
  flex: 0 1 auto;
  min-width: 0;
  overflow-wrap: break-word;
  word-break: break-word;
}

/* Card/modal title visibility - shared for card header, card title, modal title */
.card-header-title,
.card-title,
.modal-card-title {
  color: var(--text-primary) !important;
  font-weight: 600;
}

.card-header-title a,
.card-title a,
.modal-card-title a {
  color: inherit !important;
  text-decoration: none;
  /* IDEA-147 manual eval (2026-05-09): no underline-on-hover here.
       When the title contains multiple text spans (date + time +
       duration on event row headers, status pills on article rows),
       the underline stretched across every span and read as visual
       noise. Hover affordance moved to a card-level background shift
       below — one subtle brightness change instead of multi-span
       text decoration. */
}

.dark .card-header-title, .dark .card-title, .dark .modal-card-title {
  color: var(--text-accent) !important;
  font-weight: 700;
}

.dark .card-header-title a, .dark .card-title a, .dark .modal-card-title a {
  color: inherit !important;
}

/* IDEA-147 manual eval (2026-05-09): card-level hover brightness shift
   replaces the per-anchor text underline. Triggers when ANY data-
   preview-link anchor inside a card header is hovered, so hovering
   the date / title / time-duration spans all light up the same row.
   Cursor stays a pointer (the anchor's own cursor) so the click
   affordance is preserved without text decoration.

   Browser support: ``:has()`` is supported across Chrome/Edge ≥105
   (Aug 2022), Safari ≥15.4 (Mar 2022), Firefox ≥121 (Dec 2023). On
   the rare unsupported browser the rule is silently inert — the
   underline stays gone, no hover affordance lights up — acceptable
   degradation. */
.card:has(.card-header a[data-preview-link]:hover) {
  background-color: var(--bulma-scheme-main-bis);
  transition: background-color 0.12s ease;
}

.info-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1rem;
}

@media (min-width: 769px) {
  .info-grid {
    grid-template-columns: 1fr 1fr;
  }
}

.info-grid .info-item {
  display: flex;
  flex-direction: column;
}

.info-grid .info-label {
  font-weight: 600;
  color: var(--text-secondary);
  font-size: 0.875rem;
  margin-bottom: 0.25rem;
}

.info-grid .info-value {
  color: var(--text-primary);
  font-weight: 500;
}

.panel {
  background: var(--bg-secondary) !important;
  background-color: var(--bg-secondary) !important;
  color: var(--text-primary);
  border: none;
  border-radius: 0.5rem;
  box-shadow: 0 2px 8px -2px var(--shadow-color), 0 0 0 1px var(--border-light) !important;
  width: 100%;
  max-width: 28rem;
  overflow: hidden;
}

.modal-card-foot {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: 0.75rem;
}

.modal-card-foot .button {
  margin: 0;
}

.section-header {
  padding: 2rem;
  text-align: center;
  border-bottom: 1px solid var(--border-light);
  background-color: var(--bg-tertiary);
}

@media screen and (max-width: 768px) {
  .card {
    margin-bottom: 1.5rem;
  }
  .card-content {
    padding: 0.75rem 0.5rem;
  }
  .attachment-card,
.attachment-card .card-content {
    padding-left: 0.5rem !important;
    padding-right: 0.5rem !important;
  }
  .article-card {
    width: 100%;
    max-width: 100%;
  }
  .article-card .card-content,
.article-card .content {
    width: 100%;
    max-width: 100%;
    overflow-x: visible;
  }
  .card .dropdown-menu {
    max-width: min(20rem, calc(100vw - 2rem));
    overflow-x: hidden;
    white-space: normal;
  }
  .card-header-icon .dropdown-menu {
    right: 0;
    left: auto;
  }
  .card-content.table-scroll-container {
    padding: 0 !important;
    max-height: 60vh;
    overflow-y: auto;
  }
  .card-content.table-scroll-container .table thead th {
    padding-top: 0.75rem;
  }
  .card-content.table-scroll-container .table th:first-child, .card-content.table-scroll-container .table td:first-child {
    padding-left: 0.5rem;
  }
  .card-content.table-scroll-container .table th:last-child, .card-content.table-scroll-container .table td:last-child {
    padding-right: 0.5rem;
  }
  .card-content.table-scroll-container .table tbody tr:last-child td {
    padding-bottom: 0.75rem;
  }
  .card-title {
    font-size: 1.125rem;
  }
  .card-content > div[style*="overflow-x"],
.card-content > .table-scroll-container {
    margin-left: -0.5rem;
    margin-right: -0.5rem;
    width: calc(100% + 1rem);
    padding-left: 0.5rem;
    padding-right: 0.5rem;
  }
  .card-content > div[style*="overflow-x"] .table,
.card-content > .table-scroll-container .table {
    min-width: 600px;
  }
  /* Compact formset tables: stay within card, no horizontal scroll (table-formset on container) */
  .card-content > .table-scroll-container.table-formset {
    margin-left: 0;
    margin-right: 0;
    width: 100%;
  }
  .stats-grid {
    grid-template-columns: repeat(2, 1fr);
    gap: 0.75rem;
    margin-bottom: 1.5rem;
  }
  .stat-card {
    padding: 1rem;
  }
  .stat-icon {
    width: 2.5rem;
    height: 2.5rem;
    margin-bottom: 0.75rem;
    font-size: 1.25rem;
  }
  .stat-value {
    font-size: 1.5rem;
  }
  .stat-label {
    font-size: 0.75rem;
  }
  .info-grid {
    grid-template-columns: 1fr;
    gap: 0.75rem;
  }
}

@media (min-width: 769px) {
  #attachments-section.box,
.box:has(.attachment-card),
.box:has(.file-upload) {
    overflow-x: visible !important;
    overflow-y: visible !important;
  }
}

/* Dashboard cards: colored top accent + compact padding */
.dashboard-card--events {
  border-top: 2px solid var(--color-primary);
}

.dashboard-card--articles {
  border-top: 2px solid var(--color-warning);
}

.dashboard-card--activity {
  border-top: 2px solid var(--color-info);
}

.dashboard-card--events, .dashboard-card--articles, .dashboard-card--activity {
  /* Compact padding on the outer dashboard card */
  /* Compact padding on nested event/article cards inside dashboard */
}

.dashboard-card--events > .card-header, .dashboard-card--articles > .card-header, .dashboard-card--activity > .card-header {
  padding: 0.375rem 0.5rem;
}

.dashboard-card--events > .card-content, .dashboard-card--articles > .card-content, .dashboard-card--activity > .card-content {
  padding: 0.75rem;
  min-height: 120px;
}

.dashboard-card--events .event-card .card-header,
.dashboard-card--events .article-card .card-header, .dashboard-card--articles .event-card .card-header,
.dashboard-card--articles .article-card .card-header, .dashboard-card--activity .event-card .card-header,
.dashboard-card--activity .article-card .card-header {
  padding: 0.375rem 0.5rem;
}

.dashboard-card--events .event-card .card-content,
.dashboard-card--events .article-card .card-content, .dashboard-card--articles .event-card .card-content,
.dashboard-card--articles .article-card .card-content, .dashboard-card--activity .event-card .card-content,
.dashboard-card--activity .article-card .card-content {
  padding: 0.5rem 0.75rem;
}

/* IDEA-158 (amends IDEA-145) — dashboard widget columns stack when the shell
   CENTRE pane is squeezed, not when the viewport is.

   The home-dashboard widgets (``_dashboard_center.html``) are Bulma
   ``.columns`` grids: the KB section is 2-up (``is-half-desktop``), the admin
   widgets row is 3-up (``is-one-third-desktop``). Bulma's column collapse is
   keyed off the VIEWPORT (``is-full-tablet`` → stacks below 1024px viewport).
   But with the workspace + preview drawers both open the centre pane can be
   <960px while the viewport is 1400px+, so the desktop N-up grid stays and the
   columns crush to ~1 char/line. A media query can't see the pane width.

   ``.shell-center`` declares ``container-type: inline-size`` +
   ``container-name: shell-center`` (``_shell.scss``); these ``@container``
   rules key off the pane's inline-size. Thresholds = (cols × ~320px readable
   min) + Bulma column gutters + the centre's 1.25rem padding:
     * admin widgets (3-up): 3×320 = 960px floor → stack below 960px.
     * KB section (2-up):    2×320 = 640px floor → stack below 640px.
   Below each floor the matching ``.column`` children go full-width — mirrors
   Bulma's ``is-full`` mobile behaviour (``flex: none; width: 100%``).

   Scoped to ``.dashboard-center`` + the specific column wrappers so no other
   ``.columns`` in the centre (article/event detail bodies, billing tables)
   is ever stacked by these queries. */
@container shell-center (max-width: 960px) {
  .dashboard-center .dashboard-admin-widgets > .column {
    flex: none;
    width: 100%;
  }
}

@container shell-center (max-width: 640px) {
  /* KB section is the first (non-admin) ``.columns`` block inside the centre. */
  .dashboard-center > .columns:not(.dashboard-admin-widgets) > .column {
    flex: none;
    width: 100%;
  }
}

/* Article card: event summary and markers row (overdue, timeline, critical, periodic) */
.article-card-markers {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.375rem;
}

.article-card-markers .tag,
.article-card-markers .event-timeline-pill {
  margin-bottom: 0;
}

/* Article card: attachment strip */
.article-card-attachments {
  border-top: 1px solid var(--border-light);
}

.dark .article-card-attachments {
  border-top-color: var(--border-primary);
}

.article-card-attachment-thumb {
  background: none;
  border: none;
  cursor: pointer;
  padding: 0;
  line-height: 0;
  border-radius: 3px;
  overflow: hidden;
}

.article-card-attachment-thumb:hover .article-card-attachment-img {
  opacity: 0.85;
  transform: scale(1.05);
}

.article-card-attachment-img {
  width: 28px;
  height: 28px;
  object-fit: cover;
  border-radius: 3px;
  border: 1px solid var(--border-light);
  display: block;
  transition: opacity 0.15s ease, transform 0.15s ease;
}

.dark .article-card-attachment-img {
  border-color: var(--border-primary);
}

.article-card-attachment-icon {
  height: 28px !important;
  min-width: 28px;
  padding: 0 0.25rem !important;
}

.attachment-featured-image {
  width: 100%;
  max-height: 260px;
  object-fit: cover;
  border-radius: 6px;
  border: 1px solid var(--border-light);
}

.attachment-featured-image--card {
  max-height: 140px;
}

.attachment-list--compact {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
}

.attachment-list-item--compact {
  display: inline-flex;
  align-items: center;
}

.attachment-preview-thumb-button {
  width: 32px;
  height: 32px;
  border: 1px solid var(--border-light);
  border-radius: 4px;
  background: none;
  padding: 0;
  overflow: hidden;
  cursor: pointer;
}

.attachment-preview-thumb-img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.attachment-preview-thumb-icon {
  width: 32px;
  height: 32px;
  border: 1px solid var(--border-light);
  border-radius: 4px;
  align-items: center;
  justify-content: center;
}

.attachment-meta-trigger {
  position: relative;
}

@media (hover: hover) and (pointer: fine) {
  .attachment-meta-trigger[data-meta]:hover::after,
.attachment-meta-trigger[data-meta]:focus-visible::after {
    content: attr(data-meta);
    position: absolute;
    left: 50%;
    transform: translateX(-50%);
    bottom: calc(100% + 8px);
    background: var(--bg-secondary);
    color: var(--text-primary);
    border: 1px solid var(--border-primary);
    border-radius: 4px;
    padding: 0.2rem 0.45rem;
    white-space: nowrap;
    font-size: 0.7rem;
    z-index: 20;
  }
}

.attachment-meta-trigger.is-meta-visible::after {
  content: attr(data-meta);
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  bottom: calc(100% + 8px);
  background: var(--bg-secondary);
  color: var(--text-primary);
  border: 1px solid var(--border-primary);
  border-radius: 4px;
  padding: 0.2rem 0.45rem;
  white-space: nowrap;
  font-size: 0.7rem;
  z-index: 20;
}

.attachment-content-previewable {
  cursor: zoom-in;
}

.featured-image-picker {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
}

.featured-image-choice {
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  width: 120px;
  border: 1px solid var(--border-light);
  border-radius: 8px;
  padding: 0.5rem;
  cursor: pointer;
  transition: border-color 0.2s ease, background-color 0.2s ease;
}

.featured-image-choice:hover {
  border-color: var(--primary);
}

.featured-image-choice.is-selected {
  border-color: var(--primary);
  background: var(--bg-secondary);
}

.featured-image-choice-thumb {
  width: 100%;
  height: 72px;
  border-radius: 6px;
  overflow: hidden;
  margin-bottom: 0.4rem;
  border: 1px solid var(--border-light);
  background: var(--bg-secondary);
}

.featured-image-choice-thumb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.featured-image-choice-name {
  width: 100%;
  text-align: center;
  font-size: 0.75rem;
  line-height: 1.2;
  color: var(--text-secondary);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.featured-image-choice--none {
  justify-content: center;
}

/* Event timeline pill on article cards (gh#153): past > today > future counters */
.event-timeline-pill {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  padding: 0.125rem 0.375rem;
  border-radius: 0.25rem;
  background: var(--bg-tertiary);
  border: 1px solid var(--border-primary);
  font-size: 0.75rem;
}

.event-timeline-pill .event-timeline-counters {
  display: inline-flex;
  align-items: center;
  gap: 0.125rem;
}

.event-timeline-pill .event-timeline-counter {
  min-width: 1ch;
}

.event-timeline-pill .event-timeline-counter.event-timeline-past {
  color: var(--text-muted);
}

.event-timeline-pill .event-timeline-counter.event-timeline-today {
  color: var(--color-primary);
  font-weight: 500;
}

.event-timeline-pill .event-timeline-counter.event-timeline-future {
  color: var(--color-info);
}

.event-timeline-pill .event-timeline-sep {
  color: var(--text-muted);
  font-size: 0.65rem;
}

/* Event-form date/time/duration row mobile overflow (IDEA-168 follow-on,
   2026-05-21). The crispy layout in EventForm.helper.layout uses
   ``.column.is-narrow`` (date), ``.column.is-narrow`` (time), and
   ``.column.is-2`` (duration_minutes) on the first row. Bulma's
   default mobile-stack behaviour is overridden by the ``.is-X`` width
   modifiers — they stay sized at content / 16.66% on mobile, so the
   duration input pushes past the viewport edge inside the narrow
   drawer pane. Scope the stack-on-mobile reset to ``.event-form-body``
   so we don't regress other surfaces that may want Bulma's
   width-modifier semantics preserved on mobile. */
@media screen and (max-width: 768px) {
  .event-form-body .columns > .column {
    flex: 1 1 100% !important;
    width: 100% !important;
    min-width: 0;
    max-width: 100%;
  }
}

/* Event-list active-filter chip (IDEA-168 mobile follow-on, 2026-05-21).
   The "Linked to: <article-title>" chip overflowed the mobile viewport
   when the article title was long. Reuse the M21 cycle-2 drawer-chrome-
   title trick: outer pill caps at parent width; the inner text span
   owns the horizontal scroll with a faint scrollbar on tablet+ and
   hidden scrollbar on mobile (touch drag is the intuitive affordance).
*/
.event-active-filter-chips {
  max-width: 100%;
}

.event-active-filter-chip {
  max-width: 100%;
}

.event-active-filter-chip__text {
  display: inline-block;
  max-width: 100%;
  min-width: 0;
  overflow-x: auto;
  overflow-y: hidden;
  white-space: nowrap;
  scrollbar-width: thin;
  scrollbar-color: var(--scrollbar-thumb) transparent;
}

.event-active-filter-chip__text::-webkit-scrollbar {
  height: 4px;
}

.event-active-filter-chip__text::-webkit-scrollbar-thumb {
  background-color: var(--scrollbar-thumb);
  border-radius: 2px;
}

.event-active-filter-chip__text::-webkit-scrollbar-track {
  background: transparent;
}

@media screen and (max-width: 768px) {
  .event-active-filter-chip__text {
    scrollbar-width: none;
  }
  .event-active-filter-chip__text::-webkit-scrollbar {
    display: none;
  }
}

/* ===========================================
   Layout: hero, section, footer, page containers
   =========================================== */
/* Page background and text so light/dark theme applies to full page (chat, lists, etc.) */
body {
  background-color: color-mix(in srgb, var(--org-color) 5%, var(--bg-primary));
  color: var(--text-primary);
}

/* Hero subtitle: wrap at word boundaries only (no mid-word break) */
.hero-subtitle {
  word-break: normal;
  overflow-wrap: normal;
  hyphens: none;
  line-height: 1.35;
  max-width: 780px;
  margin-left: auto;
  margin-right: auto;
}

@media (max-width: 768px) {
  .hero.hero-secondary h1 {
    font-size: clamp(1.75rem, 5.5vw, 2.4rem);
  }
}

.hero.hero-secondary {
  margin-top: 0 !important;
  padding-top: 0 !important;
  background-image: url("/static/teisutis_core/img/hero-bg-light.76ea93191a96.jpg") !important;
  background-size: cover !important;
  background-position: center !important;
  background-repeat: no-repeat !important;
  background-color: var(--color-primary) !important;
}

.hero.hero-secondary .hero-body {
  background-color: transparent !important;
  padding: 4rem 1.5rem !important;
}

.hero.hero-secondary h1 {
  color: var(--text-primary) !important;
  text-shadow: 0 1px 6px rgba(255, 255, 255, 0.6);
}

.hero.hero-secondary .subtitle {
  color: var(--text-primary) !important;
  text-shadow: 0 1px 4px rgba(255, 255, 255, 0.5);
}

.dark .hero.hero-secondary {
  background-image: url("/static/teisutis_core/img/hero-bg-dark.f800f10f5086.jpg") !important;
  background-size: cover !important;
  background-position: center !important;
  background-repeat: no-repeat !important;
  background-color: var(--color-secondary) !important;
}

.dark .hero.hero-secondary .hero-body {
  background-color: transparent !important;
}

.dark .hero.hero-secondary h1 {
  color: var(--color-white) !important;
  text-shadow: 0 2px 8px rgba(0, 0, 0, 0.5);
}

.dark .hero.hero-secondary .subtitle {
  color: var(--text-primary) !important;
  text-shadow: 0 1px 4px rgba(0, 0, 0, 0.4);
}

.hero.hero-secondary .buttons .button,
.hero.hero-secondary .buttons a.button {
  box-shadow: 0 4px 6px -1px var(--shadow-color), 0 2px 4px -1px var(--shadow-color) !important;
  transition: all 0.2s ease !important;
}

.hero.hero-secondary .buttons .button:hover, .hero.hero-secondary .buttons .button:focus,
.hero.hero-secondary .buttons a.button:hover,
.hero.hero-secondary .buttons a.button:focus {
  box-shadow: 0 10px 15px -3px var(--shadow-color), 0 4px 6px -2px var(--shadow-color-medium) !important;
  transform: translateY(-1px) !important;
}

/* Secondary CTA (See How It Works): identical shadow to primary – Bulma overrides require explicit rule */
.hero.hero-secondary .hero-cta-secondary {
  box-shadow: 0 4px 6px -1px var(--shadow-color), 0 2px 4px -1px var(--shadow-color) !important;
}

.hero.hero-secondary .hero-cta-secondary:hover, .hero.hero-secondary .hero-cta-secondary:focus {
  box-shadow: 0 10px 15px -3px var(--shadow-color), 0 4px 6px -2px var(--shadow-color-medium) !important;
}

.hero-cta-primary {
  background-color: var(--color-white) !important;
  border-color: var(--color-white) !important;
  color: var(--color-secondary) !important;
  font-weight: 600 !important;
}

.hero-cta-primary:hover {
  background-color: var(--bg-tertiary) !important;
  border-color: var(--bg-tertiary) !important;
  color: var(--color-secondary) !important;
}

.dark .hero-cta-primary {
  background-color: var(--bg-tertiary) !important;
  border-color: var(--bg-tertiary) !important;
  color: var(--text-primary) !important;
}

.dark .hero-cta-primary:hover {
  background-color: var(--bg-secondary) !important;
  border-color: var(--bg-secondary) !important;
}

.section.section-secondary {
  background-color: var(--color-primary) !important;
  /* Light: teal */
}

.dark .section.section-secondary {
  background-color: var(--color-secondary) !important;
  /* Dark: blue */
}

footer.footer {
  background-color: transparent !important;
  padding: 3rem 1.5rem !important;
  margin-top: 4rem !important;
  border-top: 1px solid var(--border-light) !important;
}

.dark footer.footer {
  border-top-color: var(--border-primary) !important;
}

footer.footer .has-text-grey {
  color: var(--text-secondary) !important;
}

footer.footer .has-text-grey-light {
  color: var(--text-muted) !important;
}

footer.footer .icon {
  opacity: 0.6;
  transition: opacity 0.2s ease, color 0.2s ease;
}

footer.footer .icon:hover {
  opacity: 1;
  color: var(--color-secondary) !important;
}

.dark footer.footer .icon:hover {
  color: var(--color-primary) !important;
}

footer.footer .footer-social-x {
  font-size: 1.25rem;
  font-weight: 600;
}

.page-centered {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1rem;
  background-color: var(--bg-primary);
}

.auth-page-container {
  min-height: 80vh;
}

.auth-page-container-small {
  min-height: 70vh;
}

/* ---- Bulma .box / .content (article/event detail, cards, prose code) ---- */
/* Used: article_detail (box > article > .content), event_detail (box > article.media > .media-content > .content),
   cards (card-content > .content), landing, auth. Mobile padding/headings → mobile/_responsive.scss.
   Tables in .content are wrapped by markdownify in .table-scroll-container (only the table scrolls, not the whole block). */
.box {
  background: var(--bg-secondary) !important;
  background-color: var(--bg-secondary) !important;
  color: var(--text-primary);
  border: none;
  border-radius: 0.5rem;
  box-shadow: 0 2px 8px -2px var(--shadow-color), 0 0 0 1px var(--border-light) !important;
}

.box .media-content,
.box .content {
  overflow-x: hidden;
}

.box article.media {
  width: 100%;
  max-width: 100%;
}

.box article.media .media-content {
  overflow-x: visible;
  width: 100%;
  max-width: 100%;
  flex: 1 1 auto;
  min-width: 0;
}

.box article.media .content {
  overflow-x: visible;
  width: 100%;
  max-width: 100%;
}

/* Prose code in Bulma .content (article/event body, cards) */
.content {
  /* Tables from markdown are wrapped in .table-scroll-container by markdownify; only the table scrolls */
}

.content pre,
.content pre.highlight {
  overflow-x: auto;
  max-width: 100%;
  white-space: pre;
}

.content pre code {
  width: max-content;
  min-width: 100%;
}

.content .table-scroll-container {
  overflow-x: auto;
  max-width: 100%;
  max-height: none;
  border: none;
  box-shadow: none;
  background-color: transparent;
}

/* ---- Mobile: hero, page-centered, panel, landing sections ---- */
@media screen and (max-width: 768px) {
  .hero.hero-secondary .hero-body {
    padding: 2rem 0.5rem !important;
  }
  .hero.hero-secondary .hero-body .container {
    padding-left: 0 !important;
    padding-right: 0 !important;
  }
  .hero.hero-secondary .hero-body .subtitle.is-4 {
    font-size: 1.25rem !important;
    margin-top: 1rem !important;
    margin-bottom: 1.5rem !important;
  }
  .hero.hero-secondary .hero-body .buttons {
    margin-top: 1rem !important;
  }
  .hero.hero-secondary .hero-body .button.is-large {
    font-size: 1rem !important;
    padding: 0.75rem 1.5rem !important;
  }
  /* Landing: minimal side padding to match dashboard (optimize mobile real estate) */
  #features.section,
#contact.section {
    padding-left: 0.5rem !important;
    padding-right: 0.5rem !important;
  }
  #features .container,
#contact .container {
    padding-left: 0 !important;
    padding-right: 0 !important;
  }
  .page-centered {
    padding: 1rem;
  }
  .panel {
    margin: 1rem;
  }
}

/* ---- Thin side padding for main content up to tablet (mobile + tablet; desktop ≥1025px) ---- */
@media screen and (max-width: 1024px) {
  .main .container {
    padding-left: 0.5rem !important;
    padding-right: 0.5rem !important;
  }
}

/* ---- Vertical spacing: page header and sections (gh#154, gh#155) ---- */
/* Article list: same pattern as chat header – level-left (title) + level-right (button) in one row. */
.main .container header.article-list-header .level {
  align-items: center;
  gap: 0.5rem;
}

.main .container header.article-list-header .level-left {
  flex: 1 1 auto;
  min-width: 0;
}

.main .container header.article-list-header .level-left h1 {
  margin-bottom: 0;
}

.main .container header.article-list-header .level-right {
  flex: 0 0 auto;
}

.main .container > .level,
.main .container > header.level {
  margin-bottom: 1rem;
}

.main .container > .box + .box,
.main .container > .card + .card,
.main .container > .box + .card,
.main .container > .card + .box {
  margin-top: 1rem;
}

.column.detail-sidebar > .box + .box,
.column.detail-sidebar > .box + .card,
.column.detail-sidebar > .card + .box,
.column.detail-sidebar > .card + .card,
.column.detail-sidebar > div + .box,
.column.detail-sidebar > div + .card {
  margin-top: 1rem;
}

/* ---- Mobile: Phase 1 base (container, columns, box, content, headings, dropdowns) ---- */
/* Padding convention: 0.5rem for elements with border/shadow (box, card-content, card-header).
   No cascading padding - .content, .columns rely on parent. Ref: gh#154, gh#155 */
@media screen and (max-width: 768px) {
  .container {
    padding: 0.5rem;
  }
  .columns {
    margin-left: 0;
    margin-right: 0;
  }
  .columns .column {
    padding-left: 0 !important;
    padding-right: 0 !important;
  }
  .content {
    padding-left: 0 !important;
    padding-right: 0 !important;
  }
  .box {
    padding-left: 0.5rem !important;
    padding-right: 0.5rem !important;
    padding-top: 0.75rem;
    padding-bottom: 0.75rem;
  }
  .card-content, .card-header {
    padding-left: 0.5rem !important;
    padding-right: 0.5rem !important;
  }
  .box .content, .box .columns, .box .columns .column,
.card-content .content, .card-content .columns, .card-content .columns .column {
    padding-left: 0 !important;
    padding-right: 0 !important;
  }
  /* Heading sizes on mobile → see components/_typography.scss */
  .dropdown-menu {
    max-width: min(20rem, calc(100vw - 1rem));
  }
  .dropdown-content.box {
    padding-left: 0.75rem !important;
    padding-right: 0.75rem !important;
    padding-top: 0.75rem;
    padding-bottom: 0.75rem;
  }
  .dropdown-item {
    white-space: normal;
    word-wrap: break-word;
  }
  .level-right .dropdown .dropdown-menu {
    right: 0;
    left: auto;
  }
}

/* ---- Breadcrumb: horizontal scroll instead of wrap/clip, active item clickable ---- */
.breadcrumb {
  overflow-x: auto;
}

.breadcrumb ul {
  flex-wrap: nowrap;
}

.breadcrumb li.is-active a {
  pointer-events: auto;
  cursor: pointer;
}

/* ---- Mobile: breadcrumb, Bulma titles, level, container ---- */
@media screen and (max-width: 768px) {
  .breadcrumb {
    padding: 0.5rem 0.75rem;
    margin-bottom: 0.5rem !important;
  }
  .breadcrumb ul {
    display: flex;
    flex-wrap: nowrap;
    overflow-x: auto;
  }
  .breadcrumb li {
    flex-shrink: 0;
  }
  .breadcrumb a {
    display: block;
    white-space: nowrap;
    max-width: none;
  }
  .breadcrumb li.is-active a {
    min-width: 0;
  }
  /* .title, .subtitle, .box .title on mobile → see components/_typography.scss */
  .breadcrumb + .level:not(.chat-header .level) {
    padding: 0.5rem 0.75rem;
    /* margin-bottom from .main .container > .level (1rem) provides section spacing */
  }
  /* Override Bulma 1.0 level centering on mobile.
     Bulma sets align-items:center on .level (centers children like .level-left)
     AND flex-direction:column + align-items:center on .level-left/.level-right
     (horizontally centers their content). Override both layers. */
  .main .level:not(.is-mobile) {
    align-items: flex-start !important;
  }
  .main .level:not(.is-mobile) .level-left,
.main .level:not(.is-mobile) .level-right {
    align-items: flex-start !important;
    text-align: left;
  }
  .container > .title:first-child, .container > .subtitle:first-child {
    padding-left: 0.75rem;
    padding-right: 0.75rem;
    padding-top: 0.5rem;
    padding-bottom: 0;
  }
}

/* ---- Mobile: table overflow, attachments, article list, article cards ---- */
@media screen and (max-width: 768px) {
  /* Article list header: keep title + button in one row (same as chat header). */
  .main .container header.article-list-header .level {
    flex-direction: row !important;
    flex-wrap: nowrap;
  }
  .main .container header.article-list-header .level-left {
    min-width: 0;
  }
  .box:has(> .table):not(#attachments-section):not(:has(.attachment-card)):not(:has(.file-upload)) {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
  }
  #attachments-section.box {
    overflow-x: visible;
    overflow-y: visible;
  }
  .box .table {
    width: 100%;
    min-width: 600px;
    margin-bottom: 0;
  }
  .box .table th, .box .table td {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  .box .table th:first-child, .box .table td:first-child {
    min-width: 150px;
  }
  .box .table th:nth-child(2), .box .table td:nth-child(2), .box .table th:nth-child(3), .box .table td:nth-child(3) {
    min-width: 100px;
  }
  .box .table th:nth-child(4), .box .table td:nth-child(4) {
    min-width: 120px;
  }
  .box .table th:last-child, .box .table td:last-child {
    min-width: 100px;
  }
  #article-list-container {
    width: 100%;
    max-width: 100%;
    overflow-x: visible;
  }
  #article-list-container .columns {
    flex-direction: column;
    margin-left: 0;
    margin-right: 0;
  }
  #article-list-container .columns .column.is-3 {
    width: 100%;
    margin-bottom: 0.5rem;
    padding-left: 0;
    padding-right: 0;
  }
  #article-list-container .columns .column.is-9 {
    width: 100%;
    max-width: 100%;
    padding-left: 0;
    padding-right: 0;
  }
  .columns .column:not(:last-child) {
    margin-bottom: 0.5rem;
  }
  .articles-grid {
    width: 100%;
    max-width: 100%;
    overflow-x: visible;
  }
  /* Spacing: level (category pills + Edit/Delete) and tags row not tight; buttons keep left padding for icon */
  .box .content .level {
    gap: 0.75rem;
  }
  .box .content .level + .tags {
    margin-top: 0.75rem;
  }
  .box .level .level-right .button {
    min-width: auto;
    padding: 0.375rem 0.5rem 0.375rem 0.75rem;
    /* extra left so icon not flush */
  }
  /* Orphan attachments: sort toolbar stacks, bulk bar tighter */
  .orphan-attachments-grid > .level.is-mobile {
    flex-wrap: wrap;
    gap: 0.5rem;
  }
  .orphan-attachments-grid > .level.is-mobile .level-left, .orphan-attachments-grid > .level.is-mobile .level-right {
    flex-basis: 100%;
    justify-content: flex-start;
  }
  .orphan-attachments-grid > .level.is-mobile .level-right .buttons.has-addons .button {
    font-size: 0.65rem;
    padding: 0.25rem 0.4rem;
  }
  .orphan-bulk-bar {
    padding: 0.5rem 0.75rem;
  }
  .orphan-bulk-bar .level {
    flex-wrap: wrap;
    gap: 0.5rem;
  }
  .orphan-bulk-bar .buttons .button {
    font-size: 0.75rem;
  }
}

/* Orphan bulk action bar: sticky bottom when items selected */
.orphan-bulk-bar {
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  background: var(--bg-dark, #404040);
  padding: 0.75rem 1.5rem;
  z-index: 30;
  box-shadow: 0 -2px 8px var(--shadow-color);
}

/* File drop area: theme-aware so not too dark in light theme, not too light in dark theme */
.attachment-upload-zone .attachment-drop-area.upload-zone-bg {
  background-color: var(--bg-tertiary) !important;
}

.attachment-upload-zone .attachment-drop-area .upload-zone-icon,
.attachment-upload-zone .attachment-drop-area .upload-zone-text {
  color: var(--text-secondary);
}

/* Attachments section + upload zone: wrap text on all viewports (desktop/tablet as well as mobile) */
#attachments-section.box,
.attachment-upload-zone {
  min-width: 0;
}

.attachment-upload-zone .attachment-drop-area {
  overflow-wrap: break-word;
  word-break: break-word;
}

.attachment-upload-zone .attachment-drop-area .upload-zone-text,
.attachment-upload-zone .attachment-drop-area p {
  overflow-wrap: break-word;
  word-break: break-word;
}

/* Compact attachments section (e.g. inside FAQ list card) – less vertical space */
.attachments-section--compact.box {
  padding: 0.5rem 0.75rem;
}

.attachments-section--compact.box .level {
  margin-bottom: 0.25rem;
}

.attachments-section--compact.box .level h3 {
  font-size: 1rem;
  margin: 0;
}

.attachments-section--compact .attachment-upload-zone {
  margin-bottom: 0.5rem;
}

.attachments-section--compact .attachment-drop-area {
  padding: 0.5rem 0.75rem !important;
}

.attachments-section--compact .attachment-drop-area .icon.is-large {
  margin-bottom: 0.25rem;
}

.attachments-section--compact .attachment-drop-area .icon.fa-3x {
  font-size: 1.5rem;
}

.attachments-section--compact .attachment-drop-area .upload-zone-text.mb-3 {
  margin-bottom: 0.25rem !important;
}

.attachments-section--compact .attachment-drop-area .buttons.is-centered {
  margin-top: 0.25rem;
}

.attachments-section--compact .attachment-drop-area .is-size-7.mt-3 {
  margin-top: 0.25rem !important;
}

.attachments-section--compact .has-text-centered.py-6 {
  padding-top: 1rem !important;
  padding-bottom: 1rem !important;
}

.attachments-section--compact .has-text-centered.py-6 .icon.is-large.has-text-grey-light {
  font-size: 1.5rem;
}

.attachments-section--compact .has-text-centered.py-6 .has-text-grey.is-size-7 {
  margin-top: 0.25rem;
}

/* Filter rows (conversation list, article list): wrap on mobile so controls don't overflow */
#conversation-filters .conversation-filters-group,
#article-filters .article-filters-group {
  flex-wrap: wrap;
  gap: 0.5rem;
}

/* Tag filter collapsible: pointer cursor when hovering over summary (closed or expanded) */
#article-filters .filter-tags-details summary {
  cursor: pointer;
}

/* Detail page metadata levels (author/date/approval, created/updated) wrap on all viewports */
.box .content .level:not(.is-mobile),
.box .media-content .level:not(.is-mobile) {
  flex-wrap: wrap;
  gap: 0.25rem;
}

/* Allow created/updated text to wrap (no nowrap) so long lines don’t overflow on desktop/tablet */
.box .content .level .level-item small.has-text-grey,
.box .media-content .level .level-item small.has-text-grey {
  white-space: normal;
  overflow-wrap: break-word;
  word-break: break-word;
}

.box .content .level {
  align-items: flex-start;
}

/* ---- Utility layout classes ---- */
.is-clickable-subtitle {
  margin-bottom: 0.5rem;
  cursor: pointer;
}

.list-no-style {
  list-style-type: none;
}

/* ===========================================
   Tables (base, table-scroll-container, sticky headers)
   =========================================== */
.table {
  width: 100%;
  border-collapse: collapse;
}

.table th,
.table td {
  padding: 0.75rem;
  text-align: left;
  border-bottom: 1px solid var(--border-light);
  min-width: 0;
  overflow-x: auto;
}

.table th {
  font-weight: 600;
  color: var(--text-primary);
  background-color: var(--bg-tertiary);
}

.table td {
  color: var(--text-primary);
}

@media screen and (max-width: 768px) {
  .table .select.is-small {
    width: 100%;
  }
  .table .select.is-small select {
    width: 100%;
    max-width: 100%;
    font-size: 0.875rem;
  }
}

/* IDEA-197 — section-card table density. Equal-column layout + tighter
 * mobile cell padding + lighter wrapped column headers. Scoped to
 * .card > .card-content tables that are NOT inside a .table-scroll-container
 * (that container at lines below has its own table-layout: fixed + sticky
 * column rules calibrated for horizontal scroll). Architect F2 lock. */
.card > .card-content:not(.table-scroll-container) .table:not(.table-scroll-container .table) {
  table-layout: fixed;
}

@media screen and (max-width: 768px) {
  .card > .card-content:not(.table-scroll-container) .table:not(.table-scroll-container .table) th,
.card > .card-content:not(.table-scroll-container) .table:not(.table-scroll-container .table) td {
    padding: 6px 8px;
  }
  .card > .card-content:not(.table-scroll-container) .table:not(.table-scroll-container .table) th {
    font-weight: 500;
    line-height: 1.2;
    font-size: 0.6875rem;
  }
}

.table-scroll-container {
  overflow-x: auto;
  overflow-y: auto;
  max-height: 70vh;
  -webkit-overflow-scrolling: touch;
  padding: 0 !important;
  background-color: var(--bg-secondary);
  border: 1px solid var(--border-light);
  box-shadow: inset 0 2px 12px rgba(0, 0, 0, 0.06);
  /* Compact formset tables: first column (Amount) needs space for number input,
     middle flexible, last column fixed. Min-width so on narrow viewports the table
     scrolls. 9rem for first column avoids horizontal scrollbar in reminder amount fields. */
}

.dark .table-scroll-container {
  box-shadow: inset 0 2px 12px rgba(0, 0, 0, 0.3);
}

.table-scroll-container .table {
  min-width: 600px;
  table-layout: fixed;
  width: 100%;
  background-color: var(--bg-secondary) !important;
  color: var(--text-primary) !important;
}

.table-scroll-container .table th,
.table-scroll-container .table td {
  min-width: 0;
  overflow-x: auto;
}

.table-scroll-container .table thead th {
  padding-top: 0.5rem;
  background-color: var(--bg-tertiary) !important;
  color: var(--text-primary) !important;
}

.table-scroll-container .table tbody td {
  background-color: var(--bg-secondary) !important;
  color: var(--text-primary) !important;
}

.table-scroll-container .table tbody tr:nth-child(even) td {
  background-color: var(--bg-table-stripe) !important;
}

.table-scroll-container .table tbody tr:last-child td {
  padding-bottom: 0.5rem;
}

.table-scroll-container .table th:first-child,
.table-scroll-container .table td:first-child {
  padding-left: 0.5rem;
}

.table-scroll-container .table th:last-child,
.table-scroll-container .table td:last-child {
  padding-right: 0.5rem;
}

.table-scroll-container.table-formset .table {
  min-width: 24rem;
}

.table-scroll-container.table-formset .table th:first-child,
.table-scroll-container.table-formset .table td:first-child {
  width: 9rem;
  max-width: 9rem;
}

.table-scroll-container.table-formset .table th:last-child,
.table-scroll-container.table-formset .table td:last-child {
  width: 7rem;
  max-width: 7rem;
}

.table-sticky-header {
  position: sticky;
  left: 0;
  background: var(--bg-secondary) !important;
  background-color: var(--bg-secondary) !important;
  z-index: 10;
  box-shadow: 2px 0 4px var(--shadow-color);
}

thead th.table-sticky-header {
  top: 0 !important;
  z-index: 20 !important;
}

.table-sticky-cell {
  position: sticky;
  left: 0;
  background: var(--bg-secondary) !important;
  background-color: var(--bg-secondary) !important;
  z-index: 5;
  box-shadow: 2px 0 4px var(--shadow-color);
}

.table.is-striped tbody tr:nth-child(even) .table-sticky-cell {
  background: var(--bg-table-stripe) !important;
  background-color: var(--bg-table-stripe) !important;
}

thead th.table-sticky-header-row {
  position: sticky;
  top: 0;
  background: var(--bg-tertiary) !important;
  background-color: var(--bg-tertiary) !important;
  z-index: 15;
  box-shadow: 0 2px 4px var(--shadow-color);
}

.table-col-min-width {
  min-width: 160px;
}

@media screen and (max-width: 768px) {
  .table-col-min-width {
    min-width: 120px;
  }
}

/* IDEA-203 (M3) — billing shell tables on mobile.
   The orders + billed-usage tables are `.card-content > .table-scroll-container`
   and pick up the general `_cards.scss` mobile `-0.5rem` bleed; without the
   `[data-org-section]` neutralisation (IDEA-150) they escape/misalign past the
   card edge. Neutralise the bleed for the billing `[data-billing-section]`
   surface so the table fits inside the card padding (NOT zeroing the card
   padding — keeps the subscription form layout intact). Hyphenate headers so
   multi-syllable lt/ru column labels wrap cleanly (lang-aware via `<html lang>`). */
@media screen and (max-width: 768px) {
  /* IDEA-203 (M3) billing centre + IDEA-201 (M-walk) drawer body + IDEA-145
     dashboard admin widgets all re-house ``.card-content >
     .table-scroll-container`` inside a narrow shell pane, where the
     ``_cards.scss`` mobile negative-margin bleed pushes the table past the card
     edge. One shared mixin (``neutralize-card-table-bleed``) resets the bleed
     for every such surface — see ``_mixins.scss``. */
  [data-billing-section] .card-content > .table-scroll-container,
[data-billing-section] .card-content > div[style*="overflow-x"] {
    margin-left: 0;
    margin-right: 0;
    width: 100%;
  }
  .shell-drawer__body .card-content > .table-scroll-container,
.shell-drawer__body .card-content > div[style*="overflow-x"] {
    margin-left: 0;
    margin-right: 0;
    width: 100%;
  }
  /* IDEA-145: the dashboard centre's admin widgets (invitations + usage tables)
     are ``.card-content > .table-scroll-container`` cards in a narrow
     ``.column`` — same bleed defect as the billing centre. The widget card's
     ``display: contents`` placeholder wrapper means the table-scroll-container
     is a child of the real widget card's ``.card-content``, so the generic
     ``.card-content >`` selector inside this scope reaches it. */
  .dashboard-center .card-content > .table-scroll-container,
.dashboard-center .card-content > div[style*="overflow-x"] {
    margin-left: 0;
    margin-right: 0;
    width: 100%;
  }
  /* Hyphenate multi-syllable lt/ru column headers so they wrap cleanly in the
     narrow mobile pane (lang-aware via ``<html lang>``) — billing centre +
     dashboard admin widgets share the convention. */
  [data-billing-section] .table th,
.dashboard-center .table th {
    hyphens: auto;
    -webkit-hyphens: auto;
    -moz-hyphens: auto;
  }
}

/* ===========================================
   Chat view (conversation list, AI chat UI)
   Application-specific styles for chat/STT views (teisutis_ai)
   =========================================== */
/* ---- Chat-specific variables (colors, font sizes) ---- */
/* Font sizes: use global scale from _variables.scss
   (h1=$font-size-xl, h2=$font-size-lg, h3=$font-size-md, code/status=$font-size-sm, toggle=$font-size-base) */
/* Chat subtitle separator: "|" prepended to scope/property labels, colored by entity */
.chat-subtitle-sep {
  font-weight: 800;
}

.conversation-list-table .conversation-list-title {
  max-width: 70vw;
}

.conversation-list-table td .tag + .button {
  margin-left: 0.5rem;
}

/* ---- AI chat: sticky layout (chat.html) ---- */
.chat-interface {
  display: flex;
  flex-direction: column;
  overflow: hidden;
  margin: 0;
  flex: 1 1 auto;
  min-height: 0;
  height: 100%;
}

.chat-interface .chat-notice {
  margin: 1rem;
  flex-shrink: 0;
}

/* Django messages in chat view: style #messages-container like chat notices so any message (e.g. profile-incomplete) is not broken visually */
.container:has(.chat-interface) #messages-container {
  margin: 1rem;
  padding: 0;
  flex-shrink: 0;
  background-color: var(--bg-secondary);
}

.container:has(.chat-interface) #messages-container .notification {
  margin-bottom: 0.75rem;
  /* Use opaque -bg-solid vars so fixed chat-interface doesn't show through (see _variables.scss) */
  /* High contrast: primary text on tinted bg (light theme = dark text, dark theme = light text) */
  color: var(--text-primary);
}

.container:has(.chat-interface) #messages-container .notification.is-danger {
  background-color: var(--color-danger-bg-solid);
}

.container:has(.chat-interface) #messages-container .notification.is-warning {
  background-color: var(--color-warning-bg-solid);
}

.container:has(.chat-interface) #messages-container .notification.is-success {
  background-color: var(--color-success-bg-solid);
}

.container:has(.chat-interface) #messages-container .notification.is-info {
  background-color: var(--color-info-bg-solid);
}

.container:has(.chat-interface) #messages-container .notification.is-primary {
  background-color: var(--color-primary-bg-solid);
}

.container:has(.chat-interface) #messages-container .notification .title {
  color: inherit;
}

.container:has(.chat-interface) #messages-container .notification:last-child {
  margin-bottom: 0;
}

/* Shared: strict 100vh layout for chat (tablet + mobile) */
body:has(.chat-interface) {
  height: 100vh;
  overflow: hidden;
}

body:has(.chat-interface) .min-h-screen {
  display: flex;
  flex-direction: column;
  height: 100vh;
  overflow: hidden;
}

body:has(.chat-interface) .navbar {
  flex-shrink: 0;
}

body:has(.chat-interface) .main {
  flex: 1 1 0;
  min-height: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

body:has(.chat-interface) .main .container {
  flex: 1 1 0;
  min-height: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

@media (min-width: 769px) {
  .container:has(.chat-interface) #messages-container {
    margin: 0.5rem 1rem;
  }
  .chat-interface {
    flex: 1 1 0;
    min-height: 0;
    height: 100%;
    max-height: none;
  }
}

@media screen and (max-width: 768px) {
  body {
    --chat-mobile-top: 0px;
  }
  body:has(.navbar):not(.navbar-is-hidden) {
    --chat-mobile-top: 3.25rem;
  }
  .chat-interface {
    position: fixed;
    top: var(--chat-mobile-top);
    left: 0;
    right: 0;
    bottom: 0;
    height: auto;
    max-height: calc(100vh - var(--chat-mobile-top));
    max-height: calc(100dvh - var(--chat-mobile-top));
    padding: 0;
    display: flex;
    flex-direction: column;
    overflow: hidden;
    z-index: 1;
  }
  .chat-interface .chat-messages {
    flex: 1 1 0;
    min-height: 0;
    max-height: none;
  }
  .chat-interface .chat-input-area {
    flex: 0 0 auto;
    flex-shrink: 0;
    margin: 0;
    padding: 0.5rem;
    z-index: 10;
  }
  .container:has(.chat-interface) #messages-container {
    position: relative;
    z-index: 2;
  }
  .shell-center .chat-interface--internal,
.shell-center .chat-interface--public {
    position: static;
    inset: auto;
    height: 100%;
    max-height: none;
    z-index: auto;
  }
  .chat-header {
    flex: 0 0 auto;
    padding: 0.5rem !important;
  }
  .chat-header h1 {
    font-size: 1.25rem !important;
    line-height: 1.2;
  }
  .chat-header .level {
    display: flex;
    flex-direction: row;
    align-items: center;
    gap: 0.5rem;
  }
  .chat-header .level-left {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    margin-right: 0.5rem;
    align-self: flex-start;
  }
  .chat-header .level-left > div {
    display: flex;
    flex-direction: column;
    gap: 0.125rem;
    align-items: flex-start;
    width: 100%;
  }
  .chat-header .chat-header-subtitles {
    margin-top: 0.125rem;
  }
  .chat-header .chat-header-subtitle-text .subtitle {
    font-size: 0.6875rem;
    line-height: 1.2;
  }
  .chat-header .chat-context-filters {
    margin-top: 0.125rem;
  }
  .chat-header .chat-context-filters .label {
    display: none;
  }
  .chat-header .chat-context-filters .chat-context-filters-group {
    gap: 0.25rem;
  }
  .chat-header .subtitle-label {
    display: none;
  }
  .chat-header .chat-header-actions .button {
    padding: 0.375rem 0.5rem;
    min-width: 2.5rem;
    height: 2.5rem;
  }
  .chat-header .chat-header-actions .button span:not(.icon) {
    display: none;
  }
  .chat-header .chat-header-actions .button .icon, .chat-header .chat-header-actions .button svg.icon {
    margin-inline-start: 0;
    margin-inline-end: 0;
  }
  .chat-interface--embed .chat-header .chat-header-row,
.chat-interface--public .chat-header .chat-header-row {
    margin-left: 0;
  }
  .connection-status-badge {
    padding: 0.25rem 0.5rem;
    font-size: 0.625rem;
  }
  .connection-status-badge .icon {
    font-size: 0.5rem;
  }
  .connection-status-badge span:not(.icon) {
    display: none;
  }
  .chat-messages {
    flex: 1 1 0;
    min-height: 0;
    max-height: 100%;
    padding: 0.5rem 0;
    overflow-y: auto;
  }
  .stt-icon-browser .stt-icon-browser-desktop {
    display: none;
  }
  .stt-icon-browser .stt-icon-browser-mobile {
    display: inline;
  }
  /* Internal/embed-auth mobile compaction: avoid header growth from token meter wrapping. */
  .chat-interface--internal .chat-header,
.chat-interface--embed-auth .chat-header {
    /* Prevent title from being squeezed by status/actions on the same row. */
  }
  .chat-interface--internal .chat-header .chat-header-right-inner,
.chat-interface--embed-auth .chat-header .chat-header-right-inner {
    flex-wrap: nowrap;
    gap: 0.25rem;
  }
  .chat-interface--internal .chat-header .level,
.chat-interface--embed-auth .chat-header .level {
    display: grid;
    grid-template-columns: 1fr auto;
    row-gap: 0.25rem;
    column-gap: 0.5rem;
    align-items: start;
  }
  .chat-interface--internal .chat-header .level-left,
.chat-interface--embed-auth .chat-header .level-left {
    grid-column: 1 / -1;
    margin-right: 0;
    width: 100%;
  }
  .chat-interface--internal .chat-header .level-right.chat-header-right,
.chat-interface--embed-auth .chat-header .level-right.chat-header-right {
    grid-column: 1 / -1;
    margin-left: 0;
    justify-self: end;
  }
}

.chat-header {
  position: sticky;
  top: 0;
  z-index: 10;
  background-color: transparent;
  padding: 1rem 0;
  margin: 0;
  flex-shrink: 0;
}

.chat-header h1 {
  margin-bottom: 0;
  overflow-wrap: break-word;
  word-break: break-word;
  hyphens: auto;
}

.chat-header .level-left {
  align-items: flex-start;
  justify-content: flex-start;
}

.chat-header .chat-header-subtitles {
  margin-top: 0.25rem;
}

.chat-header .chat-header-subtitle-text {
  overflow-x: auto;
  overflow-y: hidden;
  -webkit-overflow-scrolling: touch;
}

.chat-header .chat-header-subtitle-text .subtitle {
  white-space: nowrap;
  margin-bottom: 0.125rem;
}

.chat-header .chat-header-subtitle-text .subtitle:last-child {
  margin-bottom: 0;
}

.chat-header .chat-context-filters {
  margin-top: 0.25rem;
}

.chat-header .chat-context-filters .chat-context-filters-group {
  flex-wrap: nowrap;
  gap: 0.5rem;
}

.chat-header .chat-context-filters select:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

.chat-interface .chat-messages {
  flex: 1 1 auto;
  min-height: 0;
  overflow-x: hidden;
  overflow-y: auto;
  padding: 1rem 0;
  margin-bottom: 0;
  background: var(--bg-secondary);
  border-radius: 0.5rem;
  border: 1px solid var(--border-light);
  box-shadow: inset 0 2px 12px rgba(0, 0, 0, 0.06);
}

@media (min-width: 769px) {
  .chat-interface .chat-messages {
    min-height: 0;
    max-height: none;
  }
}

.chat-interface .chat-messages.scope-color-border {
  border-left: 3px solid var(--scope-color, transparent);
  border-right: 3px solid var(--property-color, transparent);
}

.dark .chat-interface .chat-messages {
  box-shadow: inset 0 2px 12px rgba(0, 0, 0, 0.3);
}

.chat-interface .chat-messages.is-dragging {
  position: relative;
}

.chat-interface .chat-messages.is-dragging::before {
  content: '';
  position: absolute;
  inset: 0;
  background-color: rgba(160, 137, 20, 0.1);
  border: 2px dashed var(--color-primary);
  border-radius: 0.5rem;
  pointer-events: none;
  z-index: 10;
}

.chat-interface .chat-input-area {
  position: sticky;
  bottom: 0;
  z-index: 10;
  flex-shrink: 0;
  display: flex;
  /* IDEA-149 step 11 (2a smoke): vertical stack — pills + voice-row +
       inline .chat-compose-row — instead of the old 3-column row that
       collapsed into a vertical mess on narrow viewports. */
  flex-direction: column;
  gap: 0.5rem;
  align-items: stretch;
  margin: 0;
  /* No horizontal padding — the composer spans the full centre width, same
       as .chat-messages (which has padding: …0). Vertical only. */
  padding: 0.5rem 0;
  background-color: transparent;
}

.chat-interface .chat-input-area.is-dragging {
  border: 2px dashed var(--color-primary);
  background-color: var(--bg-tertiary);
}

.chat-input-area {
  /* No negative side-margin — composer is full centre width (matches
     .chat-messages). IDEA-149 step 11 (2a smoke). */
  margin: 0;
}

/* Mobile: override general .chat-interface .chat-input-area (appears above) with solid bg and safe-area */
@media screen and (max-width: 768px) {
  .chat-interface .chat-input-area {
    background-color: var(--bg-primary);
    padding-bottom: calc(0.5rem + env(safe-area-inset-bottom, 0px));
    position: relative;
  }
}

/* ---- Messages (bubbles, header, retry) ---- */
.message {
  margin-bottom: 1rem;
  max-width: 80%;
  padding: 0.5rem 0.75rem;
  border-radius: 1rem;
  position: relative;
}

.message.user {
  margin-left: auto;
  margin-right: 0.5rem;
  background-color: var(--chat-user-bg);
  color: var(--chat-user-text);
  border: 1px solid var(--chat-user-border);
  text-align: right;
}

.message.assistant {
  margin-left: 0.5rem;
  margin-right: auto;
  background-color: var(--chat-assistant-bg);
  color: var(--chat-assistant-text);
  border: 1px solid var(--chat-assistant-border);
  text-align: left;
}

.message.assistant .message-content {
  white-space: normal;
}

.message.thinking-indicator {
  opacity: 0.8;
}

.message-header {
  position: relative;
  padding: 0.25rem 0.5rem !important;
  font-size: 0.75rem;
  margin-bottom: 0.25rem;
  font-weight: 600;
  display: flex;
  justify-content: space-between;
  align-items: center;
  opacity: 0.85;
  border: none;
  border-radius: 0.375rem;
}

.message.user .message-header {
  color: var(--text-secondary);
  background-color: var(--code-bg);
}

.dark .message.user .message-header {
  background-color: var(--code-bg);
  color: var(--text-secondary);
}

.message.assistant .message-header {
  color: var(--text-secondary);
  background-color: rgba(0, 0, 0, 0.05);
}

.dark .message.assistant .message-header {
  background-color: rgba(255, 255, 255, 0.08);
  color: var(--text-secondary);
}

.retry-button {
  margin-left: 0.5rem;
  padding: 0.25rem 0.5rem;
  vertical-align: middle;
}

.retry-button .icon {
  margin: 0;
}

.retry-button:hover {
  background-color: var(--code-bg);
}

.message.user .retry-button {
  color: var(--text-secondary, #6B7280);
}

.message.user .retry-button:hover {
  color: var(--text-primary, #111827);
  background-color: rgba(0, 0, 0, 0.1);
}

.dark .message.user .retry-button {
  color: var(--text-secondary);
}

.dark .message.user .retry-button:hover {
  color: var(--text-accent);
  background-color: rgba(255, 255, 255, 0.15);
}

/* ---- Message content (prose, markdown) ---- */
.message-content,
.response-content {
  min-width: 0;
  max-width: 100%;
  overflow-x: auto;
}

.message-content {
  padding: 0;
  word-wrap: break-word;
  line-height: 1.5;
}

.message-content .tags {
  margin-bottom: 0.5rem;
  margin-top: 0;
}

.message-content .tags:first-child {
  margin-top: 0;
}

.message-content .tags:last-child {
  margin-bottom: 0;
}

.message-content h1, .message-content h2, .message-content h3, .message-content h4, .message-content h5, .message-content h6 {
  margin-top: 1em;
  margin-bottom: 0.5em;
  font-weight: 600;
  line-height: 1.25;
}

.message-content h1 {
  font-size: 1.5rem;
}

.message-content h2 {
  font-size: 1.25rem;
}

.message-content h3 {
  font-size: 1.125rem;
}

.message-content p {
  margin-bottom: 0.75em;
}

.message-content ul, .message-content ol {
  margin: 0.75em 0;
  padding-left: 1.5em;
}

.message-content li {
  margin: 0.25em 0;
}

.message-content code {
  background-color: var(--code-bg);
  padding: 0.2em 0.4em;
  border-radius: 3px;
  font-family: "SF Mono", "Monaco", "Inconsolata", "Roboto Mono", monospace;
  font-size: 0.875rem;
}

.message-content pre {
  background-color: var(--code-bg);
  padding: 1em;
  border-radius: 4px;
  overflow-x: auto;
  margin: 0.75em 0;
}

.message-content pre code {
  background-color: transparent;
  padding: 0;
}

.message-content .code-block-wrapper {
  position: relative;
  margin: 0.75em 0;
}

.message-content .code-block-wrapper pre {
  margin: 0;
}

.message-content .code-block-wrapper .code-block-copy-btn {
  position: absolute;
  top: 0.5rem;
  right: 0.5rem;
  z-index: 1;
  min-height: 1.75rem;
  min-width: 1.75rem;
  padding: 0.25rem 0.5rem;
  font-size: 0.75rem;
}

.message-content blockquote {
  border-left: 3px solid var(--border-secondary);
  padding-left: 1em;
  margin: 0.75em 0;
  color: var(--text-secondary);
}

.message-content a {
  color: var(--link-color);
  text-decoration: underline;
}

.message-content a:hover {
  color: var(--link-hover-color);
}

.message-content strong {
  font-weight: 600;
}

.message-content em {
  font-style: italic;
}

.message-content .table-wrapper {
  overflow-x: auto;
  max-width: 100%;
  margin: 0.75em 0;
}

.message-content table {
  border-collapse: collapse;
  margin: 0;
  width: 100%;
  min-width: max-content;
}

.message-content table th, .message-content table td {
  border: 1px solid var(--border-secondary);
  padding: 0.5em;
  white-space: nowrap;
}

.message-content table th {
  background-color: var(--bg-tertiary);
  font-weight: 600;
}

.message-content hr {
  border: none;
  border-top: 1px solid var(--border-secondary);
  margin: 1em 0;
}

.thinking-indicator-content {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  color: var(--text-secondary);
  font-style: italic;
}

.thinking-indicator-content .icon {
  color: var(--color-primary);
}

.thinking-indicator-content .fa-spin {
  animation: spin 1s linear infinite;
}

/* ---- References (collapsible in assistant messages) ---- */
.references-collapsible {
  margin-top: 0.75em;
  margin-bottom: 0.75em;
}

.references-toggle {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.5rem 0;
  margin: 0;
  border: none;
  background: none;
  cursor: pointer;
  color: var(--text-primary);
  font-weight: 600;
  font-size: 1rem;
  text-align: left;
  width: 100%;
}

.references-toggle:hover {
  color: var(--link-color);
}

.references-toggle .icon {
  transition: transform 0.2s ease;
  margin: 0;
}

.references-toggle[aria-expanded="true"] .icon {
  transform: rotate(90deg);
}

.dark .references-toggle {
  color: var(--text-accent);
}

.dark .references-toggle:hover {
  color: var(--link-color);
}

.references-content {
  margin-top: 0.5rem;
  margin-left: 1.5rem;
  padding-left: 0.5rem;
  border-left: 2px solid var(--border-light);
}

.dark .references-content {
  border-left-color: rgba(255, 255, 255, 0.2);
}

.references-content.is-hidden {
  display: none;
}

.references-content ul, .references-content ol {
  margin: 0.5em 0;
  padding-left: 1.5em;
}

.references-content li {
  margin: 0.25em 0;
}

.references-content a {
  color: var(--link-color);
  text-decoration: underline;
}

.references-content a:hover {
  color: var(--link-hover-color);
}

/* ---- Thinking (collapsible interim thoughts) ---- */
.thinking-section {
  margin-top: 0.75rem;
  padding-top: 0.75rem;
  border-top: 1px solid var(--border-light);
}

.thinking-section.is-hidden {
  display: none;
}

.thinking-toggle {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.375rem 0.5rem;
  font-size: 0.75rem;
  color: var(--text-secondary);
  background-color: var(--bg-tertiary);
  border: 1px solid var(--border-light);
  border-radius: 0.375rem;
  cursor: pointer;
  transition: background-color 0.2s ease, border-color 0.2s ease;
  width: 100%;
  text-align: left;
}

.thinking-toggle:hover {
  background-color: var(--bg-primary);
  border-color: var(--border-primary);
}

.thinking-toggle .icon {
  color: var(--color-primary);
  transition: transform 0.2s ease;
}

.thinking-toggle[aria-expanded="true"] .icon {
  transform: rotate(90deg);
}

.thinking-content {
  margin-top: 0.5rem;
  padding: 0.75rem;
  background-color: var(--bg-tertiary);
  border: 1px solid var(--border-light);
  border-radius: 0.375rem;
  font-size: 0.875rem;
  line-height: 1.6;
  color: var(--text-secondary);
  white-space: pre-wrap;
  word-wrap: break-word;
  font-family: "SF Mono", "Monaco", "Inconsolata", "Roboto Mono", monospace;
  max-height: 400px;
  overflow-y: auto;
}

.thinking-content.is-hidden {
  display: none;
}

.thinking-status-section {
  padding: 0.5rem 0;
  margin-bottom: 0.75rem;
  border-bottom: 1px dashed var(--border-light);
  font-size: 0.875rem;
  color: var(--text-secondary);
}

.dark .thinking-status-section {
  border-bottom-color: rgba(255, 255, 255, 0.15);
}

.thinking-status-text {
  display: block;
  white-space: pre-line;
  line-height: 1.6;
}

.tool-calls-section {
  padding: 0.5rem 0;
  margin-bottom: 0.75rem;
  border-bottom: 1px dashed var(--border-light);
  font-size: 0.875rem;
  color: var(--text-secondary);
}

.tool-call-item {
  margin-bottom: 0.25rem;
}

.tool-call-item:last-child {
  margin-bottom: 0;
}

.tool-call-toggle {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  width: 100%;
  padding: 0.25rem 0.5rem;
  border: none;
  border-radius: 4px;
  background: transparent;
  color: var(--text-secondary);
  cursor: pointer;
  font-size: 0.875rem;
  text-align: left;
  transition: background-color 0.15s ease;
}

.tool-call-toggle:hover {
  background-color: rgba(0, 0, 0, 0.04);
}

.tool-call-toggle .tool-call-chevron {
  font-size: 0.7rem;
  width: 1rem;
  flex-shrink: 0;
  transition: transform 0.15s ease;
}

.tool-call-toggle .tool-call-name {
  font-weight: 600;
}

.tool-call-toggle .tool-call-status {
  margin-left: auto;
  font-size: 0.75rem;
}

.tool-call-content {
  overflow: auto;
  max-height: 30vh;
  padding: 0.5rem 0.75rem;
  margin: 0.25rem 0 0.5rem 1.4rem;
  border-left: 2px solid var(--border-light);
  font-size: 0.875rem;
}

.tool-call-content.is-hidden {
  display: none;
}

.tool-call-item--failed .tool-call-name::before {
  content: "";
  display: inline-block;
  width: 0.5rem;
  height: 0.5rem;
  margin-right: 0.4rem;
  border-radius: 50%;
  background-color: var(--color-danger-bg-solid);
  vertical-align: middle;
}

.tool-call-item--failed .tool-call-content {
  border-left-color: var(--color-danger-bg-solid);
}

.tool-call-open-link {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  margin-top: 0.5rem;
  font-size: 0.75rem;
  font-weight: 600;
}

.tool-call-open-link .icon {
  font-size: 0.7rem;
}

.tool-call-detail-json {
  overflow: auto;
  max-height: 60vh;
  padding: 0.75rem;
  background: rgba(0, 0, 0, 0.03);
  border-radius: 4px;
  font-size: 0.875rem;
  white-space: pre-wrap;
  word-break: break-word;
}

.dark .tool-call-detail-json {
  background: rgba(255, 255, 255, 0.05);
}

.tool-call-detail--failed {
  border-left: 3px solid var(--color-danger-bg-solid);
}

.message-actions {
  display: flex;
  justify-content: flex-end;
  margin-top: 0.25rem;
}

.message-actions .copy-answer-btn {
  opacity: 0;
  transition: opacity 0.15s ease;
}

@media (hover: none) {
  .message-actions .copy-answer-btn {
    opacity: 1;
  }
}

@media screen and (max-width: 768px) {
  .message-actions .copy-answer-btn__label {
    display: none;
  }
}

.message:hover .message-actions .copy-answer-btn,
.message:focus-within .message-actions .copy-answer-btn {
  opacity: 1;
}

.tool-call-detail {
  margin-bottom: 0.5rem;
}

.tool-call-detail:last-child {
  margin-bottom: 0;
}

.tool-call-detail > strong {
  display: block;
  margin-bottom: 0.25rem;
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--text-muted);
}

.tool-result-table {
  border-collapse: collapse;
  font-size: 0.875rem;
}

.tool-result-table td {
  padding: 0.15rem 0.4rem;
  vertical-align: top;
  border-bottom: 1px solid rgba(0, 0, 0, 0.05);
}

.tool-result-table .tool-kv-key {
  font-weight: 600;
  white-space: nowrap;
  color: var(--text-secondary);
}

.tool-result-table .tool-kv-value {
  text-wrap: wrap;
  overflow-wrap: anywhere;
  word-break: break-word;
  max-width: 45vw;
}

@media screen and (max-width: 768px) {
  .tool-result-table tr {
    display: flex;
    flex-direction: column;
  }
  .tool-result-table td {
    display: block;
    padding: 0.1rem 0;
  }
  .tool-result-table .tool-kv-key {
    font-size: 0.7rem;
    opacity: 0.7;
  }
  .tool-result-table .tool-kv-value {
    max-width: none;
  }
}

.tool-call-detail > .value-block > .tool-result-table {
  table-layout: fixed;
  width: 100%;
}

.tool-call-detail > .value-block > .tool-result-table > tbody > tr > .tool-kv-key {
  width: 120px;
}

.tool-result-longtext {
  text-wrap: wrap;
  white-space: pre-wrap;
  word-break: break-word;
  margin: 0;
  padding: 0.25rem;
  background: rgba(0, 0, 0, 0.02);
  border-radius: 3px;
  font-size: 0.875rem;
}

.value-inline {
  display: inline;
}

.value-block {
  display: block;
  margin-top: 0.15rem;
}

.tool-calls-placeholder .tool-calls-load-toggle {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.25rem 0.5rem;
  border: none;
  border-radius: 4px;
  background: transparent;
  color: var(--text-secondary);
  cursor: pointer;
  font-size: 0.875rem;
  transition: background-color 0.15s ease;
}

.tool-calls-placeholder .tool-calls-load-toggle:hover {
  background-color: rgba(0, 0, 0, 0.04);
}

.tool-calls-placeholder .tool-calls-load-toggle .tool-calls-summary {
  font-weight: 600;
}

.dark .tool-call-toggle {
  color: var(--text-muted);
}

.dark .tool-call-toggle:hover {
  background-color: rgba(255, 255, 255, 0.08);
}

.dark .tool-call-content {
  border-left-color: rgba(255, 255, 255, 0.15);
}

.dark .tool-result-table td {
  border-bottom-color: rgba(255, 255, 255, 0.08);
}

.dark .tool-result-longtext {
  background: rgba(255, 255, 255, 0.04);
}

.dark .tool-calls-placeholder .tool-calls-load-toggle {
  color: var(--text-muted);
}

.dark .tool-calls-placeholder .tool-calls-load-toggle:hover {
  background-color: rgba(255, 255, 255, 0.08);
}

.response-content {
  margin-top: 0.75rem;
}

.dark .thinking-content {
  background-color: rgba(0, 0, 0, 0.2);
  border-color: rgba(255, 255, 255, 0.1);
  color: var(--text-muted);
}

.dark .thinking-toggle {
  background-color: rgba(0, 0, 0, 0.2);
  border-color: rgba(255, 255, 255, 0.1);
  color: var(--text-muted);
}

.dark .thinking-toggle:hover {
  background-color: rgba(255, 255, 255, 0.1);
}

/* ---- Input area (files, voice status, inline compose row) ---- */
.chat-input-files {
  flex: 0 0 auto;
  min-width: 0;
  max-width: 100%;
  /* File pill: label scrollable, "x" always visible on the right (320px-safe) */
}

.chat-input-files .tags {
  margin: 0;
  flex-wrap: wrap;
  gap: 0.25rem;
  min-width: 0;
}

.chat-input-files .tag.chat-file-pill {
  display: inline-flex;
  align-items: center;
  max-width: 100%;
  padding-left: 0.5rem;
  padding-right: 0.25rem;
}

.chat-input-files .tag.chat-file-pill .chat-file-pill-label {
  min-width: 0;
  overflow-x: auto;
  overflow-y: hidden;
  white-space: nowrap;
  -webkit-overflow-scrolling: touch;
}

.chat-input-files .tag.chat-file-pill .delete {
  flex-shrink: 0;
  margin-left: 0.25rem;
}

/* Request-attachments list (IDEA-021): keep file names from overflowing */
.request-attachment-name {
  max-width: 100%;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.request-attachment-item {
  min-width: 0;
}

/* IDEA-129 — voice-status row holds the waveform canvas next to the
 * status-text div. The canvas is a sibling (NOT a child) of
 * #chat-voice-status so that ``showStatus()``'s
 * ``statusEl.textContent = …`` does not wipe the canvas, AND so the
 * ``.chat-voice-status:empty`` collapse-when-idle rule keeps working. */
.chat-voice-row {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

.chat-voice-status {
  /* Fill the left so the waveform (order:1) is pushed to the right edge,
     above the mic/record button (IDEA-149 step 11 2a smoke). */
  flex: 1 1 auto;
  min-width: 0;
  padding: 0.25rem 0;
  font-size: 0.875rem;
  color: var(--text-muted);
}

.chat-voice-status:empty {
  padding: 0;
  min-height: 0;
  overflow: hidden;
}

/* IDEA-129 — live frequency-bars visualizer canvas. Hidden until
 * audio_recorder.js sets ``.is-active`` on recording start; canvas
 * size is fixed in CSS, the JS scales the backing store for HiDPI. */
.chat-voice-waveform {
  display: none;
  width: 120px;
  height: 24px;
  vertical-align: middle;
  /* Render after the status text → sits at the RIGHT edge of the voice row,
     above the mic/record button (IDEA-149 step 11 2a smoke). */
  order: 1;
  flex: 0 0 auto;
}

.chat-voice-waveform.is-active {
  display: inline-block;
}

/* IDEA-117 — audio bubble + pre-upload chip audio styles.
 *
 * The bubble audio sits inside .message.user > .message-content (which is
 * right-aligned); the <audio> element spans the bubble width up to the
 * existing message-bubble max-width enforced by parent layout. The native
 * <audio controls> chrome itself follows the browser/OS theme — we only
 * recolour the wrapper + fallback link via CSS variables defined in
 * _variables.scss (light defaults at :root, dark overrides under .dark).
 */
.chat-bubble-audio {
  display: flex;
  justify-content: flex-end;
  align-items: center;
  background-color: var(--audio-wrapper-bg);
  border: 1px solid var(--audio-wrapper-border);
  border-radius: 0.375rem;
  padding: 0.125rem 0.25rem;
}

.chat-bubble-audio audio {
  width: 100%;
  max-width: 320px;
  height: 36px;
  /* Align the native controls nicely inside the bubble's right-aligned
     * content column. */
  display: block;
}

/* Pre-upload chip audio preview: compact inline <audio> inside the chip
 * next to the filename. Smaller height than the bubble player to keep the
 * chip height bounded; the chip already scrolls horizontally on overflow
 * (see .chat-file-pill-label above), so the audio stays adjacent to the
 * filename even for long paths. */
.chat-file-pill-audio {
  display: inline-block;
  vertical-align: middle;
  height: 28px;
  max-width: 200px;
}

/* IDEA-124 — fallback link rendered when the ``<audio>`` element fires
 * its native ``error`` event (Safari on webm/opus, etc.). Detection is
 * event-driven, not ``canPlayType``-based. The attachment is never
 * dropped from the message; this is a client-side playback affordance
 * only. WCAG-AA contrast inherits from the link colour token, which is
 * ``--color-primary-hover`` on dark mode. */
.audio-fallback-link {
  color: var(--audio-fallback-link-color);
  text-decoration: underline;
  font-size: 0.875rem;
  white-space: nowrap;
}

.audio-fallback-link:hover {
  text-decoration: none;
}

/* IDEA-124 — pre-upload chip "preview not available" slot: wraps the
 * audio + the fallback note so the ``error``-event-driven swap is
 * contained. Layout stays inline-flex so the chip's existing label
 * flows around it. */
.chat-file-pill-audio-slot {
  display: inline-flex;
  align-items: center;
  vertical-align: middle;
}

/* IDEA-124 — native <audio controls> chrome (timeline strip, play / volume
 * buttons) is rendered by the user-agent stylesheet and ignores our class
 * theme by default. ``color-scheme: dark`` is the standard CSS hint that
 * tells the browser to switch UA widgets to their dark variant. Setting it
 * on the <audio> element under .dark mode flips the control bar from white
 * to dark; light mode (no .dark class) leaves it alone. Supported in
 * Chrome 81+, Firefox 96+, Safari 13+.
 *
 * Selectors:
 * - .chat-bubble-audio audio       — chat-history bubbles (server partial)
 * - .chat-file-pill-audio-slot audio — pre-upload chip wrapper (live)
 * - audio.chat-file-pill-audio     — direct-class form (defensive) */
.dark .chat-bubble-audio audio,
.dark .chat-file-pill-audio-slot audio,
.dark audio.chat-file-pill-audio {
  color-scheme: dark;
}

/* IDEA-149 step 11 (2a smoke) — inline composer row (demo2 ``.comp`` contract).
   Attach + camera + textarea + mic + send on ONE bordered row, bottom-aligned,
   uniform icon-button size; the textarea grows between them up to a cap. This
   replaces the old 3-column buttons-left / container / buttons layout that
   collapsed into a vertical mess on narrow viewports. */
.chat-compose-row {
  display: flex;
  /* stretch → the left/right button stacks match the (taller) textarea height */
  align-items: stretch;
  gap: 0.25rem;
  border: 1px solid var(--border-primary);
  border-radius: 0.75rem;
  padding: 0.25rem 0.35rem;
  background-color: var(--bg-primary);
  transition: border-color 0.2s, box-shadow 0.2s;
  /* The mic recorder sits at a fixed icon size, so its in-button countdown
     timer is hidden here — recording feedback (waveform + status text) shows
     full-width in the .chat-voice-row above. */
  /* Left/right vertical button stacks (attach+camera | mic+send) — IDEA-149
     step 11 (2a smoke). Stacking the actions frees horizontal width for the
     textarea (was too narrow inline). Buttons fill the stack height: two split
     it, a lone button (the public-chat send) fills it. */
}

.chat-compose-row:focus-within {
  border-color: var(--color-primary);
  box-shadow: 0 0 0 3px rgba(160, 137, 20, 0.15);
}

.chat-compose-row .audio-recorder-timer {
  display: none;
}

.chat-compose-row .chat-compose-side {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  flex: 0 0 auto;
}

.chat-compose-row .chat-compose-side .chat-compose-btn {
  height: auto;
  flex: 1 1 0;
  align-self: stretch;
}

/* Borderless, transparent, auto-growing textarea (demo2). Overrides Bulma's
   .textarea border/shadow + the legacy resize:vertical. */
.chat-compose-input.textarea {
  flex: 1 1 auto;
  min-width: 0;
  border: none;
  background-color: transparent;
  box-shadow: none;
  resize: none;
  /* Taller default so the flanking 2-button stacks have room + the input is
     comfortably usable (user smoke); grows to the cap. */
  min-height: 4.75rem;
  max-height: 160px;
  padding: 0.4rem;
  line-height: 1.4;
}

.chat-compose-input.textarea:focus, .chat-compose-input.textarea:active {
  border: none;
  box-shadow: none;
}

.chat-compose-input.textarea.is-dragging {
  background-color: var(--bg-tertiary);
}

/* Uniform icon buttons (attach / camera / mic / send) — borderless ghost
   squares, bottom-aligned so they stay put as the textarea grows. Visible text
   labels (e.g. "Send") are hidden; the buttons are icon-only (aria-label/title
   keep them accessible). */
.chat-compose-btn.button {
  flex: 0 0 auto;
  align-self: flex-end;
  width: 2.25rem;
  height: 2.25rem;
  min-width: 0;
  padding: 0;
  border: none;
  background-color: transparent;
  box-shadow: none;
  border-radius: 0.5rem;
  color: var(--text-secondary);
  justify-content: center;
}

.chat-compose-btn.button .icon {
  margin: 0;
}

.chat-compose-btn.button span:not(.icon) {
  display: none;
}

.chat-compose-btn.button:hover {
  background-color: var(--bg-tertiary);
  color: var(--text-primary);
}

.chat-compose-btn.button:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

/* Send = the accent action. */
.chat-compose-send.button {
  background-color: var(--color-primary);
  color: var(--color-white);
}

.chat-compose-send.button:hover {
  background-color: var(--color-primary-hover, #8a7511);
  color: var(--color-white);
}

#voice-input-button {
  position: relative;
}

#voice-input-button.recording {
  background-color: var(--color-danger);
  color: var(--color-white);
  animation: pulse 1.5s ease-in-out infinite;
}

#voice-input-button.recording:hover {
  background-color: var(--color-danger-hover);
}

#voice-input-button:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

/* IDEA-111 Phase 1 — local audio recorder state styling. Engaged only when
   the button carries the data-recorder-state attribute (flag on). */
#voice-input-button.audio-recorder-button {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
}

#voice-input-button.audio-recorder-button[data-recorder-state="recording"] {
  background-color: var(--color-danger);
  color: var(--color-white);
  animation: pulse 1.5s ease-in-out infinite;
}

#voice-input-button.audio-recorder-button[data-recorder-state="recording"]:hover {
  background-color: var(--color-danger-hover);
}

#voice-input-button.audio-recorder-button[data-recorder-state="sending"] {
  opacity: 0.6;
  cursor: progress;
}

#voice-input-button.audio-recorder-button .audio-recorder-dot {
  display: inline-block;
  width: 0.65rem;
  height: 0.65rem;
  border-radius: 50%;
  background-color: var(--color-white);
  animation: pulse 1s ease-in-out infinite;
}

#voice-input-button.audio-recorder-button .audio-recorder-timer {
  font-family: var(--font-mono, ui-monospace, "SFMono-Regular", Consolas, monospace);
  font-variant-numeric: tabular-nums;
  font-size: 0.85em;
  line-height: 1;
}

.audio-preview-controls {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  flex-wrap: wrap;
}

.audio-preview-controls .audio-preview-duration {
  font-family: var(--font-mono, ui-monospace, "SFMono-Regular", Consolas, monospace);
  font-variant-numeric: tabular-nums;
  font-size: 0.85em;
  padding: 0 0.2rem;
}

.stt-icon-browser {
  display: inline;
}

@media (min-width: 769px) {
  .stt-icon-browser .stt-icon-browser-mobile {
    display: none;
  }
  .stt-icon-browser .stt-icon-browser-desktop {
    display: inline;
  }
}

#stt-mode-toggle {
  position: relative;
}

#stt-mode-toggle.active {
  background-color: var(--color-primary);
  color: var(--color-white);
}

#stt-mode-toggle.active:hover {
  background-color: var(--color-primary-hover);
}

#stt-mode-toggle:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

.tts-speaking-indicator {
  display: none;
  width: 8px;
  height: 8px;
  margin-left: 6px;
  vertical-align: middle;
  border-radius: 50%;
  background: var(--color-primary);
}

.tts-speaking-indicator.speaking {
  display: inline-block;
  animation: pulse 1.5s ease-in-out infinite;
}

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

/* ---- Connection status (sidebar ID or inline badge) ---- */
#connection-status {
  margin-bottom: 1rem;
  padding: 0.5rem 0.75rem;
  border-radius: 0.375rem;
  font-size: 0.875rem;
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-weight: 500;
}

#connection-status.connected {
  background-color: var(--color-success-bg);
  color: var(--color-success);
  border: 1px solid var(--color-success-border);
}

#connection-status.connecting {
  background-color: var(--color-warning-bg);
  color: var(--color-warning);
  border: 1px solid var(--color-warning-border);
}

#connection-status.disconnected {
  background-color: var(--color-danger-bg);
  color: var(--color-danger);
  border: 1px solid var(--color-danger-border);
}

#connection-status .icon {
  font-size: 0.75rem;
}

/* Context indicator: context window bar (current request) + total token cost for reference */
.context-usage-meter {
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
  margin-inline-end: 0.5rem;
  cursor: pointer;
}

.dark .context-usage-meter {
  color: var(--color-text-secondary);
}

.context-usage-meter .context-usage-meter-info {
  opacity: 0.4;
  font-size: 0.65rem;
}

.context-usage-meter:hover .context-usage-meter-info {
  opacity: 0.8;
}

.context-usage-meter-bar-wrap {
  width: 4rem;
  height: 0.5rem;
  border-radius: 0.25rem;
  background: var(--border-light);
  overflow: hidden;
}

.dark .context-usage-meter-bar-wrap {
  background: rgba(255, 255, 255, 0.08);
}

.context-usage-meter-bar {
  height: 100%;
  min-width: 0;
  border-radius: 0.25rem;
  background: var(--color-primary);
  transition: width 0.2s ease-out;
}

.dark .context-usage-meter-bar {
  background: var(--color-primary);
}

.context-usage-meter-total {
  font-size: 0.65rem;
  font-weight: 500;
  color: var(--color-text-secondary);
  white-space: nowrap;
  line-height: 1.2;
}

/* Token meter under the 3 buttons for all layouts (avoids spacing issues on tablet/desktop) */
.chat-header-right-inner {
  display: flex;
  flex-direction: row;
  gap: 0.5rem;
  align-items: center;
  flex-wrap: wrap;
  justify-content: flex-end;
}

.chat-header-right-inner .context-usage-meter {
  order: 1;
  margin-inline-start: 0;
  margin-inline-end: 0;
}

.chat-header-right-inner .chat-header-actions {
  order: 2;
  display: flex;
  gap: 0.375rem;
  align-items: center;
}

.chat-header-actions {
  display: inline-flex;
  gap: 0.375rem;
  align-items: center;
}

.chat-header-row {
  display: flex;
  justify-content: flex-end;
}

.chat-interface--public .chat-header,
.chat-interface--embed .chat-header {
  padding-top: 0.5rem;
  padding-bottom: 0.25rem;
}

.chat-interface--public .chat-header-subtitles,
.chat-interface--embed .chat-header-subtitles {
  margin-top: 0.25rem;
}

/* IDEA-224: the standalone public chat now shows the AI-generated conversation
   title (left) opposite the actions (right) — the `#chat-conversation-subtitle`
   target generateTitle() writes to. The base `.chat-header-row` is flex-end
   (actions-only); the public variant goes space-between. The embed variants keep
   flex-end (no title element added there). */
.chat-interface--public .chat-header-row {
  justify-content: space-between;
  align-items: center;
  gap: 0.5rem;
}

.chat-interface--public .chat-header-row .chat-header-left-inner {
  flex: 1 1 auto;
  min-width: 0;
}

.chat-interface--public .chat-header-row .chat-header-title {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.chat-interface--embed-public .chat-header .chat-header-subtitle-text {
  display: none;
}

.chat-interface--embed-public .chat-header .chat-header-row {
  justify-content: flex-end;
}

.connection-status-badge {
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
  padding: 0.375rem 0.625rem;
  border-radius: 0.375rem;
  font-size: 0.75rem;
  font-weight: 500;
  white-space: nowrap;
  cursor: pointer;
  background: none;
  border: 1px solid transparent;
  transition: opacity 0.15s ease;
}

.connection-status-badge:hover {
  opacity: 0.8;
}

.connection-status-badge.connected {
  background-color: var(--color-success-bg);
  color: var(--color-success);
  border-color: var(--color-success-border);
}

.connection-status-badge.connecting {
  background-color: var(--color-warning-bg);
  color: var(--color-warning);
  border-color: var(--color-warning-border);
}

.connection-status-badge.disconnected, .connection-status-badge.error {
  background-color: var(--color-danger-bg);
  color: var(--color-danger);
  border-color: var(--color-danger-border);
}

.connection-status-badge .icon {
  font-size: 0.625rem;
}

/* IDEA-149 step 12 — the connection badge was relocated into the nav
   (.navbar-item.shell-nav__connection), where `.navbar-item button { color:
   inherit }` greys it out (it inherits the nav's --text-secondary). Re-assert
   the status colours scoped under the wrapper so they win on specificity
   (0,3,0) regardless of stylesheet import order. Background/border come from
   the base .connection-status-badge.<status> rules (the nav only overrode
   `color`), so only colour needs re-asserting; the icon inherits it. */
.shell-nav__connection .connection-status-badge.connected {
  color: var(--color-success);
}

.shell-nav__connection .connection-status-badge.connecting {
  color: var(--color-warning);
}

.shell-nav__connection .connection-status-badge.disconnected, .shell-nav__connection .connection-status-badge.error {
  color: var(--color-danger);
}

/* ---- Context notification (article/event context display) ---- */
#context-notification {
  /* Make context item tags visibly interactive */
}

#context-notification.has-context {
  transition: all 0.3s ease;
}

#context-notification .tags .tag:not(.is-delete) {
  cursor: pointer;
  transition: filter 0.2s ease;
}

#context-notification .tags .tag:not(.is-delete):hover {
  filter: brightness(0.95);
}

/* Context toggle button - visual feedback when context is active */
#context-toggle-btn {
  white-space: nowrap;
}

#context-toggle-btn:not(.is-light) {
  font-weight: 600;
}

@media screen and (max-width: 768px) {
  #context-toggle-btn {
    min-width: 2.5rem;
    margin-right: 0.5rem;
  }
}

/* Mobile optimizations for context notification (< 768px) */
@media screen and (max-width: 768px) {
  #context-notification.has-context {
    padding: 0.75rem 1rem;
    margin: 0.5rem 1rem 0.5rem 1rem !important;
    font-size: 0.875rem;
  }
  #context-notification .context-content p {
    margin-bottom: 0.25rem !important;
  }
  #context-notification .context-content .icon {
    font-size: 0.875rem;
  }
  /* Make toggle button more prominent on mobile */
  #context-toggle-btn {
    margin-right: 0.5rem;
  }
}

/* ---- Chat Context Panel ---- */
.chat-context-panel {
  padding: 0.5rem 0.75rem;
  background-color: var(--bg-secondary);
  border-top: 1px solid var(--border-light);
  border-bottom: none;
  transition: all 0.3s ease;
}

.chat-context-panel .chat-context-panel-header {
  cursor: pointer;
}

.chat-context-panel .chat-context-panel-subtitle {
  font-weight: normal;
}

.chat-context-panel .context-item-tags {
  border: 1px solid transparent;
  border-radius: 5px;
  transition: border-color 0.2s;
  overflow: hidden;
}

.chat-context-panel .context-item-tags.is-pinned {
  border-color: var(--color-primary, #00d1b2);
}

.chat-context-panel .context-item-tags .context-preview-btn {
  text-decoration: none;
}

.chat-context-panel .context-item-tags .context-preview-btn .context-preview-img {
  border-radius: 4px 0 0 4px;
  overflow: hidden;
  flex-shrink: 0;
}

.chat-context-panel .context-item-tags .context-preview-btn .context-preview-img img {
  object-fit: cover;
  width: 100%;
  height: 100%;
}

.chat-context-panel .context-item-tags .context-pin-btn {
  cursor: pointer;
  padding: 0 0.5rem;
  border-left: 1px solid rgba(0, 0, 0, 0.1);
  border-right: 1px solid rgba(0, 0, 0, 0.1);
}

.dark .chat-context-panel .context-item-tags .context-pin-btn {
  border-left-color: rgba(255, 255, 255, 0.1);
  border-right-color: rgba(255, 255, 255, 0.1);
}

.chat-context-panel .context-item-tags .context-pin-btn .icon {
  transition: all 0.2s;
}

.chat-context-panel .context-item-tags .context-pin-btn .icon.is-pinned-icon {
  opacity: 1;
}

.chat-context-panel .context-item-tags .context-pin-btn .icon.is-unpinned-icon {
  opacity: 0.3;
}

.chat-context-panel .context-item-tags .context-delete-btn {
  cursor: pointer;
  text-decoration: none;
}

.chat-context-panel .chat-context-filters-wrapper.has-border-top {
  border-top: 1px solid rgba(0, 0, 0, 0.1);
}

.dark .chat-context-panel .chat-context-filters-wrapper.has-border-top {
  border-top-color: rgba(255, 255, 255, 0.1);
}

/* ---- IDEA-149 Phase 2 — workspace session navigator ---- */
/* Each row is a flex line: title left, context summary right. On a narrow
   workspace the summary WRAPS UNDER the title (flex-wrap + a title min-width
   floor) instead of squeezing the title into a char-by-char sliver — the
   "float right squeezes the title" glitch (user 2026-05-30). margin-left:auto
   keeps the summary hugging the right edge both inline and on its wrapped line. */
.chat-session-list .chat-session-link {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.15rem 0.5rem;
}

.chat-session-list .chat-session-title {
  flex: 1 1 auto;
  min-width: 7rem;
  overflow-wrap: break-word;
}

.chat-session-list .chat-session-context {
  flex: 0 0 auto;
  margin-left: auto;
  max-width: 100%;
}

.chat-session-list .chat-session-context .tag {
  max-width: 100%;
}

/* ---- IDEA-149 Phase 2 (step 12) — context bar + slide-down drawer ---- */
/* Compact strip at the top of the chat centre (count + pills + token meter +
   Manage) that expands into a slide-down context-item drawer. Replaces the
   retired bottom context panel; reuses theme custom props so it tracks the
   active theme. Visual contract: home-demo-v2.html .ctxbar/.ctxdraw. */
.ctxbar-wrap {
  flex-shrink: 0;
}

.ctxbar {
  display: flex;
  flex-wrap: nowrap;
  align-items: center;
  gap: 0.5rem;
  padding: 0.4rem 1rem;
  min-width: 0;
  overflow: hidden;
  border-bottom: 1px solid var(--border-light);
  cursor: pointer;
  /* whole bar toggles the drawer (except interactive children) */
}

.ctxbar .ctxbar-lead {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  flex-shrink: 0;
  white-space: nowrap;
  font-size: 0.72rem;
  color: var(--text-secondary);
  padding-right: 0.5rem;
  border-right: 1px solid var(--border-light);
}

.ctxbar .ctxbar-lead b {
  color: var(--text-primary);
}

.ctxbar .ctxbar-pills {
  display: flex;
  flex-wrap: nowrap;
  align-items: center;
  gap: 0.25rem;
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
}

.ctxbar .ctxbar-pills .tag {
  white-space: nowrap;
}

.ctxbar .ctxbar-more {
  cursor: pointer;
  flex-shrink: 0;
}

.ctxbar .ctx-pill-link {
  display: inline-flex;
  text-decoration: none;
  color: inherit;
  flex-shrink: 0;
}

.ctxbar .ctxbar-meter {
  margin-left: auto;
  flex-shrink: 0;
}

.ctxbar .ctxbar-manage {
  display: inline-flex;
  align-items: center;
  gap: 0.2rem;
  flex-shrink: 0;
  border: none;
  background: transparent;
  cursor: pointer;
  border-radius: 4px;
  padding: 0.2rem 0.45rem;
  font-size: 0.7rem;
  color: var(--text-secondary);
}

.ctxbar .ctxbar-manage:hover {
  background: var(--bg-tertiary);
}

.ctxdraw {
  max-height: 0;
  overflow: hidden;
  background: var(--bg-tertiary);
  transition: max-height 0.25s ease;
}

.ctxdraw.is-open {
  max-height: 320px;
  overflow-y: auto;
  border-bottom: 1px solid var(--border-light);
}

.ctxdraw .ctxdraw-items {
  padding: 0.4rem 1rem;
}

.ctxdraw .ctxdraw-item {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.3rem 0;
  border-bottom: 1px solid var(--border-light);
}

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

.ctxdraw .ctxdraw-item > .ctx-pill-link,
.ctxdraw .ctxdraw-item > .tag {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
}

.ctxdraw .ctxdraw-item .tag {
  max-width: 100%;
}

.ctxdraw .ctxdraw-item .tag .ml-1 {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.ctxdraw .ctxdraw-item .ctxdraw-item-actions {
  margin-left: auto;
  display: inline-flex;
  gap: 0.35rem;
  flex-shrink: 0;
}

.ctxdraw .ctxdraw-item .ctxdraw-item-actions a {
  cursor: pointer;
}

.ctxdraw .ctxdraw-empty {
  padding: 0.6rem 1rem;
}

/* The context-item pill is clickable (opens the object's preview drawer), so
   it shows the pointer cursor on hover — in the ctxbar line AND the drawer.
   The shared Badges rule ``.tag.is-light { cursor: default }`` (specificity
   0,2,0) otherwise wins over the anchor; every pill variant carries
   ``is-light``, so override it at 0,3,0 + force every descendant span.
   Verified via Playwright (test_chat_pill_cursor.py). */
.ctx-pill-link,
.ctx-pill-link *,
.ctx-pill-link .tag.is-light {
  cursor: pointer;
}

.ctx-pill-link {
  text-decoration: none;
  color: inherit;
}

/* ===========================================
   Navigation (navbar, dropdowns, logo)
   =========================================== */
.navbar {
  position: sticky;
  top: 0;
  z-index: 30;
  background-color: var(--bg-secondary);
  border-top: 3px solid var(--org-color, transparent);
  border-bottom: 1px solid var(--border-secondary);
  transition: transform 0.2s ease-out, max-height 0.2s ease-out;
  /* Language picker: same select pattern as dashboard/form (arrow on right, not after text) */
  /* Remove bottom padding to prevent hover highlight protrusion */
}

.navbar.navbar--hidden {
  /* M20 cycle 5 (2026-05-07, user observation: empty strip
       persists). Cycle 4 set ``max-height: 0`` to collapse the
       slot but missed Bulma's ``.navbar { min-height: 3.25rem
       }`` default. Per CSS spec, when ``min-height > max-
       height``, max-height is clamped UP to min-height — so
       max-height: 0 silently became max-height: 3.25rem and
       the slot never actually collapsed. ``shell-main``
       received no extra space → empty strip remained.
       Fix: also force min-height: 0 + padding 0 on the
       hidden state so the box can genuinely shrink. */
  transform: translateY(-100%);
  min-height: 0;
  max-height: 0;
  padding-top: 0;
  padding-bottom: 0;
  overflow: hidden;
}

.navbar .navbar-brand img {
  height: 2rem;
  width: auto;
  filter: drop-shadow(0 0 6px rgba(124, 58, 237, 0.35));
}

.navbar .navbar-brand .has-text-weight-bold {
  color: var(--color-brand) !important;
}

.navbar .navbar-item {
  color: var(--text-secondary);
}

.navbar .navbar-item:hover {
  color: var(--text-primary);
  background-color: var(--bg-tertiary);
}

.navbar .navbar-item button {
  background: none;
  border: none;
  padding: 0.5rem 0.75rem;
  font: inherit;
  color: inherit;
  cursor: pointer;
  text-decoration: none;
  width: 100%;
  text-align: left;
}

.navbar .navbar-item button:hover {
  color: inherit;
  background: none;
}

.navbar .navbar-link {
  color: var(--text-secondary);
}

.navbar .navbar-link:hover, .navbar .navbar-link.is-active {
  color: var(--text-primary);
  background-color: var(--bg-tertiary);
}

.navbar .navbar-item .select {
  min-width: 8rem;
}

.navbar .navbar-dropdown {
  padding-bottom: 0 !important;
  min-width: 16rem;
}

/* IDEA-143: user-menu submenu trigger collapses to a Google-
   style rounded-circle initials avatar at ALL viewports per
   user direction 2026-05-06 ("I want DESKTOP user menu to
   appear as mobile (compact)"). M17 cycle 5: harden the rules
   with ``!important`` everywhere because Bulma's mobile-touch
   defaults (``.navbar-link { padding-right: 2.5em; flex-grow: 1
   }`` and similar) keep winning specific properties through
   downstream cascade tricks. Avatar must be a pixel-perfect
   2.25rem circle with controlled colour regardless of viewport
   or theme. */
.shell-nav .navbar-item.has-dropdown:has(.shell-nav__trigger-text--mobile) {
  display: inline-flex !important;
  flex: 0 0 auto !important;
  align-items: center;
  justify-content: center;
  padding: 0 !important;
  margin-right: 0.25rem;
}

.shell-nav .navbar-item.has-dropdown:has(.shell-nav__trigger-text--mobile) > .navbar-link {
  display: inline-flex !important;
  flex: 0 0 auto !important;
  align-items: center;
  justify-content: center;
  /* Triple-pin the dimensions so Bulma can't expand the link
       to fill its parent (the brass-bar regression where the
       avatar background extends across the navbar). */
  width: 2.25rem !important;
  min-width: 2.25rem !important;
  max-width: 2.25rem !important;
  height: 2.25rem !important;
  min-height: 2.25rem !important;
  max-height: 2.25rem !important;
  padding: 0 !important;
  border-radius: 50%;
  background-color: var(--org-color, var(--color-secondary)) !important;
  /* ``--org-color-fg`` computed in shell.html via the ``on_color``
       filter (W3C luminance crossover Y=0.179). Fallback to
       near-black ``#181818`` instead of the previous ``#fff`` —
       most theme tokens are bright; near-black-on-coloured-bg
       reads better in the common case AND gives a graceful
       degradation when the var is missing entirely. */
  color: var(--org-color-fg, #181818) !important;
  font-weight: 600;
  font-size: 0.85rem;
  line-height: 1;
  cursor: pointer;
  text-decoration: none;
  /* Suppress Bulma's default ``::after`` chevron arrow on the
       link — we render a clean initials-only circle, no chev. */
  /* Hide the icon-text wrapper's icon (FontAwesome user) and
       the ``--full`` span (full name). Show only ``--mobile``
       (initials). Compact gap so the circle is centred on the
       initials text. */
}

.shell-nav .navbar-item.has-dropdown:has(.shell-nav__trigger-text--mobile) > .navbar-link::after {
  display: none !important;
}

.shell-nav .navbar-item.has-dropdown:has(.shell-nav__trigger-text--mobile) > .navbar-link:hover, .shell-nav .navbar-item.has-dropdown:has(.shell-nav__trigger-text--mobile) > .navbar-link:focus-visible {
  background-color: var(--org-color, var(--color-secondary)) !important;
  color: var(--org-color-fg, #181818) !important;
  box-shadow: 0 0 0 2px var(--bg-tertiary);
}

.shell-nav .navbar-item.has-dropdown:has(.shell-nav__trigger-text--mobile) > .navbar-link .icon-text {
  gap: 0;
  /* Bulma sets icon-text padding via the navbar-link cascade
         tokens; pin to 0 so the initials don't shift inside the
         circle. */
  padding: 0 !important;
}

.shell-nav .navbar-item.has-dropdown:has(.shell-nav__trigger-text--mobile) > .navbar-link .icon {
  display: none !important;
}

.shell-nav .navbar-item.has-dropdown:has(.shell-nav__trigger-text--mobile) > .navbar-link .shell-nav__trigger-text--full {
  display: none !important;
}

.shell-nav .navbar-item.has-dropdown:has(.shell-nav__trigger-text--mobile) > .navbar-link .shell-nav__trigger-text--mobile {
  display: inline !important;
  /* Inherit the ``color`` from the navbar-link override so
         Bulma's per-span color rules can't bleed through. */
  color: inherit !important;
}

/* M17 cycle 8 (2026-05-06): Bulma touch-range (≤1023px) overrides
   that need to fire on BOTH mobile and tablet. Earlier these were
   nested inside ``@include mobile`` (≤768px) — tablet kept Bulma's
   ``.navbar { display: block }`` + ``.navbar-menu { display: none }``
   defaults, leaving nav-end + dropdowns invisible on tablet. */
@media (max-width: 1023px) {
  .shell-nav {
    /* Force flex-row so brand + menu sit side-by-side instead of
       stacking vertically (Bulma's mobile burger pattern). */
    display: flex !important;
    flex-direction: row !important;
    flex-wrap: nowrap !important;
    align-items: stretch !important;
    /* Override Bulma's mobile-burger ``.navbar-menu { display:
       none; position: absolute }`` so the right-edge cluster is
       always visible inline. */
    /* Dropdown drops below + right-aligns. Per user direction
       2026-05-07: dropdowns slide in/out (transform + opacity),
       same pattern for both burger overflow AND user menu — match
       behaviour across mobile / tablet / desktop. Switched from
       ``display: none/block`` to ``opacity + transform + pointer-
       events`` so the open/close transitions can be CSS-animated. */
    /* Open state: hover (tablet pointer / desktop) AND Alpine
       ``.mobile-open`` toggle (mobile click). */
  }
  .shell-nav > .navbar-brand {
    flex: 0 1 auto !important;
    min-width: 0 !important;
  }
  .shell-nav > .navbar-menu {
    flex: 1 1 auto !important;
    min-width: 0 !important;
  }
  .shell-nav .navbar-menu {
    display: flex !important;
    position: static !important;
    flex-grow: 1;
    align-items: center;
    /* M17 cycle 9 (2026-05-06): force flex-wrap nowrap so
         navbar-start (primary nav row) + navbar-end (auth /
         lang / theme / user-menu) stay on the SAME row.
         Without this Bulma's tablet default lets navbar-end
         wrap below the primary nav, producing the
         user-reported "user menu in 2nd row" state. */
    flex-wrap: nowrap !important;
    min-width: 0 !important;
    background-color: transparent !important;
    border-top: none !important;
    box-shadow: none !important;
    padding: 0 !important;
  }
  .shell-nav .navbar-start {
    /* M17 cycle 10 (2026-05-06): Bulma's mobile-touch default
         sets ``.navbar-start { display: flex; flex-direction:
         column }`` — that's why the primary nav items were
         stacking/wrapping to multiple rows on tablet instead of
         flowing into the burger overflow. Force flex-row +
         nowrap + overflow:hidden so nav-overflow.js's measure-
         and-mirror pipeline works correctly. min-width: 0
         lifts the implicit min-content constraint so the row
         can shrink past its content's natural width. */
    display: flex !important;
    flex-direction: row !important;
    flex: 1 1 auto !important;
    min-width: 0 !important;
    flex-wrap: nowrap !important;
    overflow: hidden;
  }
  .shell-nav .navbar-end {
    /* Lock the right cluster to its natural width — never grow,
         never shrink. flex-shrink: 0 ensures the user-menu /
         theme / lang stay on the row even when the primary nav
         claims more horizontal space than fits.
         M17 cycle 11 (user 2026-05-07: "user menu on mobile
         regression — not sticky to right anymore") — re-added
         ``margin-left: auto`` which was dropped during c9. With
         the primary nav row hidden on mobile, navbar-end is
         the only visible flex child of navbar-menu; without
         the auto-margin it sits at the left edge instead of
         being pushed right. */
    display: flex !important;
    flex-direction: row !important;
    flex: 0 0 auto !important;
    margin-left: auto !important;
    align-items: center;
    flex-wrap: nowrap !important;
  }
  .shell-nav .navbar-end > * {
    flex: 0 0 auto !important;
  }
  .shell-nav .navbar-item.has-dropdown {
    position: relative;
  }
  .shell-nav .navbar-item.has-dropdown .navbar-dropdown {
    display: block !important;
    position: absolute !important;
    top: 100% !important;
    bottom: auto !important;
    left: auto !important;
    right: 0 !important;
    min-width: 14rem;
    box-shadow: 0 8px 16px rgba(0, 0, 0, 0.18);
    border-radius: 0.375rem;
    background-color: var(--bg-secondary);
    border: 1px solid var(--border-secondary);
    opacity: 0;
    transform: translateY(-8px);
    pointer-events: none;
    transition: opacity 0.18s ease-out, transform 0.18s ease-out;
  }
  .shell-nav .navbar-item.has-dropdown.is-hoverable:hover .navbar-dropdown,
.shell-nav .navbar-item.has-dropdown.is-hoverable:focus-within .navbar-dropdown,
.shell-nav .navbar-item.has-dropdown .navbar-dropdown.mobile-open {
    opacity: 1;
    transform: translateY(0);
    pointer-events: auto;
  }
}

/* IDEA-224: the former ``.shell-nav--public`` mobile-override + label-visible
   blocks (IDEA-212) are gone. The standalone public chat now renders the
   default ``<c-nav-bar>`` (same nav JS loaded) instead of a bespoke
   burger-dropdown variant, so there is no ``.shell-nav--public`` class to
   style — the shared ``.shell-nav`` rules cover every surface uniformly. */
/* Desktop range (≥1024px): apply the same dropdown slide pattern.
   User direction 2026-05-07: "user menu should slide out/in same
   as burger on mobile (also on desktop/tablet)" — single behaviour
   across viewports. Bulma's desktop dropdown defaults rely on
   ``display: none/block`` toggled by ``:hover``; we override to a
   transform+opacity transition so the slide animation is consistent
   with the touch-range rules above. */
@media (min-width: 1024px) {
  .shell-nav .navbar-item.has-dropdown .navbar-dropdown {
    display: block !important;
    opacity: 0;
    transform: translateY(-8px);
    pointer-events: none;
    transition: opacity 0.18s ease-out, transform 0.18s ease-out;
  }
  .shell-nav .navbar-item.has-dropdown.is-hoverable:hover .navbar-dropdown,
.shell-nav .navbar-item.has-dropdown.is-hoverable:focus-within .navbar-dropdown,
.shell-nav .navbar-item.has-dropdown .navbar-dropdown.mobile-open {
    opacity: 1;
    transform: translateY(0);
    pointer-events: auto;
  }
}

/* M10 cycle 7 (2026-05-07, user direction: "identify tablet size
   and fix there"). Tablet-only (769-1023px) flex gap between
   navbar-start and navbar-end so the last visible nav item has
   guaranteed visual separation from the user-menu avatar even
   if the JS cap calculation in nav-overflow.js drifts.
   Mobile (≤768px) is excluded — primary nav row is hidden via
   ``.shell-nav__items { display: none }`` further down so the
   gap is irrelevant there. Desktop (≥1024px) is excluded because
   default Bulma auto-margins already provide ample space. */
@media (min-width: 769px) and (max-width: 1023px) {
  .shell-nav .navbar-menu {
    gap: 1rem;
  }
}

@media screen and (max-width: 768px) {
  .navbar {
    padding-left: 1rem;
    padding-right: 1rem;
  }
  .navbar-menu {
    background-color: var(--bg-secondary);
    border-top: 1px solid var(--border-secondary);
  }
  /* Disable Bulma hover, use Alpine.js click instead. Per user
     2026-05-07: dropdowns slide in/out across all viewports —
     keep ``display: block`` always and toggle visibility via
     opacity + transform + pointer-events so the transition
     defined in the touch-range block above plays on mobile too.
     Earlier ``display: none/block !important`` here overrode the
     transition (display can't be transitioned), so mobile saw an
     instant snap while desktop/tablet got the slide. */
  .navbar-item.has-dropdown.is-hoverable:hover .navbar-dropdown,
.navbar-item.has-dropdown.is-hoverable .navbar-dropdown {
    /* Closed by default on mobile — keep box rendered but
         invisible so the transition can play. */
    opacity: 0;
    transform: translateY(-8px);
    pointer-events: none;
  }
  .navbar-item.has-dropdown.is-hoverable .navbar-dropdown.mobile-open {
    opacity: 1;
    transform: translateY(0);
    pointer-events: auto;
  }
  .dropdown.is-hoverable .dropdown-menu {
    display: none !important;
  }
  .dropdown.is-hoverable.is-active .dropdown-menu, .dropdown.is-active .dropdown-menu, .dropdown.is-hoverable .dropdown-menu.mobile-open {
    display: block !important;
  }
  /* M17 cycle 8 (2026-05-06): split the mobile-touch Bulma
     overrides (navbar-menu visibility, flex-row, dropdown
     position) from the mobile-only slim (hide primary nav, lang,
     theme, top burger). User regression: nav vanished on tablet
     because Bulma's ``.navbar-menu { display: none }`` mobile-
     touch default applies through ≤1023px, but my visibility
     override only fired ≤768px. Tablet kept Bulma's hide.
     Visibility + flex-row overrides are now keyed off
     ``@media (max-width: 1023px)`` (matches Bulma's touch range);
     the slim-the-cluster rules stay at ≤768px. */
  .shell-nav {
    /* Slim-only rules (mobile ≤768px): hide primary nav row,
       lang picker, theme toggle, top burger. These move to the
       bottom-tab nav + More sheet. */
    /* Mobile-only initials toggle for the user-menu trigger.
       Tablet keeps the desktop appearance (the avatar circle's
       own rules above already swap full→initials regardless
       of viewport, so this duplicate is harmless). */
    /* navbar-end push-right + dropdown positioning lifted into
       the @media (max-width: 1023px) block above so they apply
       at tablet too (cycle 8 split). */
  }
  .shell-nav .shell-nav__items {
    display: none !important;
  }
  .shell-nav .shell-nav__overflow-trigger {
    display: none !important;
  }
  .shell-nav .navbar-item:has(form[action*="setlang"]) {
    display: none !important;
  }
  .shell-nav .shell-nav__theme-toggle {
    display: none !important;
  }
  .shell-nav .shell-nav__trigger-text--full {
    display: none;
  }
  .shell-nav .shell-nav__trigger-text--mobile {
    display: inline;
  }
}

.logo {
  width: 4rem;
  height: 4rem;
  margin: 0 auto var(--space-lg);
  color: var(--color-primary);
}

/* ===========================================
   Shell primary nav (priority+ icon-overflow-burger)
   ===========================================
   Reuses the existing ``.navbar`` sticky-top + scroll-hide behaviour
   (handled by ``navbar-scroll.js``) and layers shell-specific classes
   on top so visual identity stays consistent across legacy and new
   shells during the migration window.

   Per IDEA-137 plan decision 9: tablet/desktop = icon + label, mobile
   = icon-only. The burger overflow dropdown absorbs items that don't
   fit the inline row at any breakpoint. JS handles the measurement
   (see nav-overflow.js); CSS handles the per-breakpoint label
   collapse and the overflow-hidden visual state.
*/
.shell-nav {
  /* Items that JS marked as overflowing; CSS collapses them so the
       row reflows without leaving a gap. The burger picks them up via
       the cloned-into-dropdown mechanism. */
  /* Hard-clip the inline items container so any sub-rAF frame where
       the JS hasn't yet hidden an item doesn't visually overflow the
       nav. Without this the row briefly wraps before the rAF tick
       reduces it. */
  /* Mobile: hide labels, keep icons. Burger absorbs anything that
       still doesn't fit the icon row. */
}

.shell-nav .shell-nav__item--overflow-hidden {
  display: none !important;
}

.shell-nav .shell-nav__items {
  flex-wrap: nowrap;
  overflow: hidden;
  min-width: 0;
}

.shell-nav .shell-nav__item {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  white-space: nowrap;
}

.shell-nav .shell-nav__item--active {
  background-color: var(--bg-tertiary);
  color: var(--text-primary);
  font-weight: 600;
}

.shell-nav .shell-nav__item .shell-nav__item-icon {
  flex: 0 0 auto;
}

.shell-nav .shell-nav__item .shell-nav__item-label {
  flex: 0 1 auto;
}

@media screen and (max-width: 768px) {
  .shell-nav .shell-nav__item .shell-nav__item-label {
    display: none;
  }
}

.shell-nav .shell-nav__overflow-menu {
  min-width: 12rem;
}

.shell-nav .shell-nav__overflow-menu .shell-nav__overflow-item {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  /* Always show labels in the overflow dropdown — the dropdown
               is where the user goes to see WHAT was hidden. */
}

.shell-nav .shell-nav__overflow-menu .shell-nav__overflow-item .shell-nav__item-label {
  display: inline;
}

/* ===========================================
   Shell drawer primitive (workspace + preview)
   ===========================================
   See web/teisutis_ui/templates/cotton/drawer.html for the markup
   contract. Width is driven by the ``--shell-drawer-width`` custom
   property the Alpine component writes via ``widthStyle()``.

   Modes:
   * ``collapsible`` (workspace) — never fully closes; collapses to a
     thin rail at ``min-width``.
   * ``closeable`` (preview) — fully hidden when ``isOpen=false``.

   Amended by IDEA-143 (2026-05-06) Phase 2: drawers are no longer
   fixed-overlay on mobile. They become full-pane children of the
   ``.shell-pane-snap`` container in ``_shell.scss``; width comes
   from the parent flex/snap (100% of pane width). The width
   transition is suppressed on mobile so the native browser
   scroll-snap engine drives motion without fighting a CSS width
   tween. The resize handle stays hidden via Alpine's
   ``x-show="!isMobile"``.
*/
.shell-drawer {
  --shell-drawer-width: 0px;
  position: relative;
  flex: 0 0 auto;
  width: var(--shell-drawer-width);
  background-color: var(--bg-secondary);
  border-color: var(--border-secondary);
  overflow: hidden;
  transition: width 0.18s ease-out;
  /* When collapsed-to-rail, hide every body / header bit so only the
       toggle button remains visible at the inner edge — that's the
       affordance to expand again. The wrapper itself stays at
       ``min_width`` (set via the ``--shell-drawer-width`` CSS var by
       drawer.js's ``widthStyle()``). */
  /* Suppress the width tween while the user is holding the resize
       handle — without this, every mousemove animates over 0.18s and
       the handle visibly lags behind the cursor. The transition stays
       intact for open/close/collapse/expand state changes, which DO
       want easing. */
  /* Unified edge control — the full-height vertical strip at the
       drawer's inner edge. Replaces the IDEA-137 prototype's separate
       collapse-toggle + resize-handle pair with one affordance that
       handles tap (toggle), drag (resize), and drag-past-threshold
       (dismiss). See drawer.js startResize / _onResizeMove / _onResizeEnd
       for the lifecycle.

       Visual: thin coloured strip; chevron icon at top; thickens on
       hover. Mobile: the same strip is a touch-friendly drag target
       since the only meaningful gesture there is dismiss. */
  /* Drag-past-threshold visual: dim the drawer + slightly translate
       inward so the user gets feedback that releasing now will dismiss.
       Drag back inside the live zone removes this state. */
  /* IDEA-143 Phase 2 cross-IDEA amendment: mobile pane mode.
       Drawers are no longer fixed-overlay on mobile — they become
       direct flex children of ``.shell-pane-snap`` (defined in
       _shell.scss) at 100% pane width. The fixed-overlay branch is
       deliberately removed because it would fight the parent's
       scroll-snap layout. */
}

.shell-drawer--left {
  border-right: 1px solid var(--border-secondary);
}

.shell-drawer--right {
  border-left: 1px solid var(--border-secondary);
}

.shell-drawer--bottom {
  border-top: 1px solid var(--border-secondary);
}

.shell-drawer--collapsed {
  overflow: hidden;
}

.shell-drawer--collapsed .shell-drawer__body, .shell-drawer--collapsed .shell-drawer__header {
  display: none;
}

.shell-drawer--closed {
  width: 0;
  border: none;
}

.shell-drawer--resizing {
  transition: none;
}

.shell-drawer__header {
  position: sticky;
  top: 0;
  z-index: 2;
  /* Reserve inner-edge padding as a no-go zone over header text for
           the edge-control. IDEA-201: derive it from --shell-edge-gutter so
           it cascades to the mobile value (the edge-control is hidden ≤768px,
           so the wide desktop reserve isn't needed there). */
  padding: 0.75rem var(--shell-edge-gutter, 1.5rem) 0.75rem 1rem;
  background-color: var(--bg-secondary);
  border-bottom: 1px solid var(--border-secondary);
}

.shell-drawer--right .shell-drawer__header {
  padding: 0.75rem 1rem 0.75rem var(--shell-edge-gutter, 1.5rem);
}

.shell-drawer__body {
  padding: 0.75rem var(--shell-edge-gutter, 1.5rem) 0.75rem 1rem;
  overflow-y: auto;
  height: 100%;
  overflow-wrap: anywhere;
  word-break: break-word;
  min-width: 0;
}

.shell-drawer__body .button {
  white-space: normal;
  height: auto;
  min-height: 2.5em;
}

.shell-drawer--right .shell-drawer__body {
  padding: 0.75rem 1rem 0.75rem var(--shell-edge-gutter, 1.5rem);
}

.shell-drawer__edge-control {
  /* IDEA-201: shared edge-lip visual (transparent strip + 2px spine +
           hover tokens) extracted to %shell-edge-lip so the mobile pane
           edge-lip rails stay consistent. Drawer-specific bits below. */
  background: transparent;
  border: 0;
  color: var(--text-secondary);
  display: flex;
  justify-content: center;
  transition: background-color 0.12s ease-out, color 0.12s ease-out;
  /* Centred vertical spine. */
  position: absolute;
  top: 0;
  bottom: 0;
  width: 0.75rem;
  z-index: 3;
  padding: 0;
  margin: 0;
  cursor: ew-resize;
  align-items: flex-start;
  /* chevron at the top of the bar */
  padding-top: 0.5rem;
}

.shell-drawer__edge-control::before {
  content: '';
  position: absolute;
  top: 0;
  bottom: 0;
  left: 50%;
  transform: translateX(-50%);
  width: 2px;
  background-color: var(--border-secondary);
  transition: background-color 0.12s ease-out, width 0.12s ease-out;
}

.shell-drawer__edge-control:hover, .shell-drawer__edge-control:focus-visible {
  background-color: var(--bg-tertiary);
  color: var(--text-primary);
}

.shell-drawer__edge-control:hover::before, .shell-drawer__edge-control:focus-visible::before {
  background-color: var(--text-secondary);
  width: 3px;
}

.shell-drawer__edge-control:focus-visible {
  outline: 2px solid var(--bulma-link, #485fc7);
  outline-offset: -2px;
}

@media screen and (max-width: 768px) {
  .shell-drawer__edge-control {
    /* IDEA-201: hidden on mobile. This is the DESKTOP resize/collapse
               affordance; on mobile the pane edge-lip rail (pane_lips.js) is
               the single edge affordance. Showing both produced "double
               triangles" at the drawer edge (M-walk 2026-05-29). Dismiss on
               mobile is the drawer close (×) + swipe / the return-rail. */
    display: none;
  }
}

.shell-drawer__collapse-chevron {
  /* IDEA-201: shared chevron badge (%shell-edge-lip-chevron). */
  position: relative;
  z-index: 1;
  background-color: var(--bg-secondary);
  padding: 0.125rem 0.1rem;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: transform 0.18s ease-out;
}

.shell-drawer__collapse-chevron--collapsed {
  transform: rotate(180deg);
}

.shell-drawer--left .shell-drawer__edge-control {
  right: 0;
}

.shell-drawer--right .shell-drawer__edge-control {
  left: 0;
  /* Right-edge drawer's natural close direction is rightward, so
           the chevron points right (rotate the base ``fa-chevron-left``
           by 180°). When collapsed, rotate back to point left. */
}

.shell-drawer--right .shell-drawer__edge-control .shell-drawer__collapse-chevron {
  transform: rotate(180deg);
}

.shell-drawer--right .shell-drawer__edge-control .shell-drawer__collapse-chevron--collapsed {
  transform: rotate(0deg);
}

.shell-drawer--dismiss-pending, .shell-drawer--pane-dismiss-pending {
  opacity: 0.6;
  transition: opacity 0.12s ease-out;
}

@media (max-width: 768px) {
  .shell-drawer {
    transition: none;
  }
  .shell-drawer__body {
    -webkit-overflow-scrolling: touch;
  }
  .shell-drawer__body .card-content {
    padding-left: 0;
    padding-right: 0;
  }
}

/* ===========================================
   Preview-drawer cotton (IDEA-159)
   ===========================================
   Styles the `<c-preview-drawer>` chrome rendered inside the right-edge
   `<c-drawer name="preview" mode="closeable">` (see _drawer.scss).

   The outer `<aside class="shell-drawer">` already handles width, scroll
   shell, and the resize edge control. This partial scopes the inner
   chrome: a sticky header strip (back-affordance + title + close button)
   and a scrollable body host that the previewSurface JS API populates
   via push / pop / open / update.

   Layout contract — the drawer is column flex:
     header: fixed-height row, sticky to the top of the body host
     body:   fills remaining height, overflow-y: auto, padded gutter

   The host element fills its `shell-drawer__body` parent (which already
   has `height: 100%` + `overflow-y: auto`); we re-establish a flex column
   so the sticky header anchors against the same scroll container.
   =========================================== */
.ui-preview-drawer {
  display: flex;
  flex-direction: column;
  min-height: 100%;
}

.ui-preview-drawer__header {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: center;
  column-gap: 0.5rem;
  row-gap: 0.25rem;
  padding: 0.75rem 0.75rem 0.75rem 1rem;
  margin: 0 -0.5rem 0.5rem;
  background-color: var(--bg-secondary);
  border-bottom: 1px solid var(--border-secondary);
}

.ui-preview-drawer__back {
  grid-column: 1 / -1;
  justify-self: start;
  max-width: 100%;
  padding: 0.25rem 0.5rem;
  background: transparent;
  border: 0;
  color: var(--text-secondary);
  font-size: 0.875rem;
  line-height: 1.25;
  text-align: left;
  cursor: pointer;
  border-radius: 0.25rem;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  transition: background-color 0.12s ease-out, color 0.12s ease-out;
}

.ui-preview-drawer__back:hover, .ui-preview-drawer__back:focus-visible {
  background-color: var(--bg-tertiary);
  color: var(--text-primary);
}

.ui-preview-drawer__back:focus-visible {
  outline: 2px solid var(--bulma-link, #485fc7);
  outline-offset: -2px;
}

.ui-preview-drawer__title {
  grid-column: 1;
  margin: 0 !important;
  font-size: 1.125rem;
  font-weight: 600;
  line-height: 1.25;
  color: var(--text-primary);
  min-width: 0;
}

.ui-preview-drawer__title-inner {
  display: block;
  overflow-x: auto;
  overflow-y: hidden;
  white-space: nowrap;
  scrollbar-width: thin;
  scrollbar-color: var(--scrollbar-thumb) transparent;
}

.ui-preview-drawer__title-inner::-webkit-scrollbar {
  height: 4px;
}

.ui-preview-drawer__title-inner::-webkit-scrollbar-thumb {
  background-color: var(--scrollbar-thumb);
  border-radius: 2px;
}

.ui-preview-drawer__title-inner::-webkit-scrollbar-track {
  background: transparent;
}

@media screen and (max-width: 768px) {
  .ui-preview-drawer__title-inner {
    scrollbar-width: none;
  }
  .ui-preview-drawer__title-inner::-webkit-scrollbar {
    display: none;
  }
}

.ui-preview-drawer__close {
  grid-column: 2;
  grid-row: auto;
  align-self: center;
}

.ui-preview-drawer__body {
  flex: 1 1 auto;
  min-height: 0;
  padding: 0 0.5rem 1rem;
}

@media screen and (max-width: 768px) {
  .ui-preview-drawer__body {
    padding-left: 0;
    padding-right: 0;
  }
}

.ui-preview-drawer__body h1, .ui-preview-drawer__body h2, .ui-preview-drawer__body h3, .ui-preview-drawer__body h4 {
  font-size: 1.125rem;
  font-weight: 600;
  line-height: 1.25;
  margin: 0 0 0.75rem;
  color: var(--text-primary);
}

.ui-preview-drawer__body h3, .ui-preview-drawer__body h4 {
  font-size: 1rem;
}

.ui-preview-drawer__body p {
  margin: 0 0 0.75rem;
  line-height: 1.5;
}

.ui-preview-drawer__body p:last-child {
  margin-bottom: 0;
}

.ui-preview-drawer__body code {
  font-family: "SF Mono", "Monaco", "Inconsolata", "Roboto Mono", monospace;
  font-size: 0.95em;
}

.c-collapsible {
  margin-bottom: 0.5rem;
}

.c-collapsible__trigger {
  display: flex;
  list-style: none;
  align-items: center;
  width: 100%;
  padding: 0.5rem 0.25rem;
  cursor: pointer;
  font: inherit;
  color: inherit;
}

.c-collapsible__trigger::-webkit-details-marker {
  display: none;
}

.c-collapsible__trigger:hover {
  background: var(--bulma-scheme-main-bis, #fafafa);
}

.c-collapsible__trigger:focus-visible {
  outline: 2px solid var(--bulma-link, #485fc7);
  outline-offset: -2px;
}

.c-collapsible__chevron {
  display: inline-flex;
  margin-right: 0.5rem;
  transition: transform 0.15s ease-out;
  transform: rotate(0);
}

.c-collapsible__summary {
  flex: 1 1 auto;
  font-weight: 600;
}

.c-collapsible__body {
  padding: 0.25rem 0 0.25rem 1.5rem;
}

.c-collapsible__loading {
  display: inline-block;
  padding: 0.5rem 0;
  color: var(--bulma-text-light, #7a7a7a);
  font-style: italic;
}

.c-collapsible[open] > .c-collapsible__trigger > .c-collapsible__chevron {
  transform: rotate(90deg);
}

.c-collapsible__sr-expand {
  display: inline;
}

.c-collapsible__sr-collapse {
  display: none;
}

.c-collapsible[open] > .c-collapsible__trigger > .c-collapsible__sr-expand {
  display: none;
}

.c-collapsible[open] > .c-collapsible__trigger > .c-collapsible__sr-collapse {
  display: inline;
}

.c-collapsible--boxed {
  border: 1px solid var(--bulma-border, #dbdbdb);
  border-radius: 4px;
  background: var(--bulma-scheme-main, #fff);
}

.c-collapsible--boxed > .c-collapsible__trigger {
  padding: 0.5rem 0.75rem;
}

.c-collapsible--boxed > .c-collapsible__body {
  padding: 0.5rem 0.75rem 0.75rem 1.75rem;
  border-top: 1px solid var(--bulma-border-light, #ededed);
}

.c-collapsible--danger > .c-collapsible__trigger {
  color: var(--bulma-danger, #f14668);
}

.c-collapsible--warning > .c-collapsible__trigger {
  color: var(--bulma-warning-dark, #946c00);
}

.c-collapsible--success > .c-collapsible__trigger {
  color: var(--bulma-success, #48c78e);
}

.c-collapsible--info > .c-collapsible__trigger {
  color: var(--bulma-info, #3e8ed0);
}

.c-copy-button__label {
  margin-left: 0.25rem;
}

.c-copy-button--misconfigured {
  outline: 2px dashed var(--bulma-warning, #ffe08a);
  outline-offset: 2px;
  display: inline-block;
}

/* ===========================================
   c-search-input — filter-form search field (IDEA-156 R4/R8)
   =========================================== */
.c-search-input {
  /* Positioning context for the clear-✕ button. */
  position: relative;
  /* Suppress the webkit native search-cancel button so the custom clear-✕
     is the single ✕ (IDEA-156 R8). */
  /* Clear-✕ button — occupies the right slot reserved by Bulma's
     ``.has-icons-right`` (which adds the input's right padding). Bulma only
     auto-positions ``.icon.is-right``; this is a real <button>, positioned
     here. */
  /* Visibility: hide the clear-✕ while the field is empty (placeholder
     showing). Requires a non-empty ``placeholder`` on the input — the
     component defaults one. No JS needed for show/hide. */
}

.c-search-input input[type="search"]::-webkit-search-cancel-button, .c-search-input input[type="search"]::-webkit-search-decoration {
  -webkit-appearance: none;
  appearance: none;
}

.c-search-input__clear {
  /* Centred on the input's vertical midline exactly like Bulma's native
       <select> ::after arrow (top:50% + translateY) — not Bulma's
       has-icons-right .icon box (height:2.5em, top:0) which mis-centres on
       is-small inputs. The glyph is a direct child (no .icon wrapper) so that
       rule can't grab it. */
  position: absolute;
  top: 50%;
  right: 0.625em;
  transform: translateY(-50%);
  z-index: 4;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  margin: 0;
  border: none;
  background: transparent;
  color: var(--text-muted, #888);
  cursor: pointer;
  pointer-events: auto;
  font-size: 0.875em;
  line-height: 1;
}

.c-search-input__clear:hover {
  color: var(--text-primary, #363636);
}

.c-search-input input[type="search"]:placeholder-shown ~ .c-search-input__clear {
  display: none;
}

/* ===========================================
   Shell layout (top nav + workspace + center + preview)
   ===========================================
   Three-region flexbox body below the sticky top nav. Drawer widths
   are driven by the ``--shell-drawer-width`` custom property the
   drawer Alpine component writes; this layer just gives each region
   its slot in the row.

   Amended by IDEA-160 (2026-05-06): per-pane scroll containment.
   ``html.shell-html`` + ``.shell-body`` are fixed-height + overflow-
   hidden — the document never scrolls. Every scroll happens inside
   one of the named panes (``.shell-drawer__body`` for the two
   drawers, ``.shell-center`` for the centre). Defeats Bulma's default
   ``html { overflow-y: scroll }`` for shell-extending surfaces only;
   legacy ``base.html`` pages don't carry ``.shell-html`` so they keep
   the document-scroll behaviour. See
   ``docs/archive/2026-05-idea-160-independent-pane-scroll-fixed-viewport/``
   for the rationale + manual-eval scenarios.

   Amended by IDEA-143 (2026-05-06) Phase 2: pane-snap layout. On
   mobile (≤768px) the workspace + centre + preview triplet becomes
   a horizontally-scrollable scroll-snap container (``.shell-pane-snap``)
   so users swipe between full-viewport panes. Above 768px the rules
   neutralise (``overflow-x: visible; scroll-snap-type: none``) and
   the existing flex row layout owns the cascade. Preview pane
   collapses to ``flex: 0 0 0`` when ``previewSurface.depth === 0``
   via the ``shell-drawer--no-preview`` marker class (architect F1 —
   not ``display:none`` to avoid the iOS Safari snap-engine reflow
   race vs ``scrollIntoView``). See
   ``docs/archive/2026-05-idea-143-mobile-bottom-nav-pane-swipe-ios/``
   for the full plan + manual-eval scenarios.
*/
html.shell-html {
  height: 100vh;
  height: 100dvh;
  overflow: hidden;
  --shell-edge-gutter: 1.5rem;
}

@media (max-width: 768px) {
  html.shell-html {
    --shell-edge-gutter: 1rem;
  }
}

.shell-body {
  display: flex;
  flex-direction: column;
  height: 100vh;
  height: 100dvh;
  overflow: hidden;
}

.shell-main {
  display: flex;
  flex-direction: row;
  flex: 1 1 auto;
  align-items: stretch;
  min-height: 0;
}

/* M20 cycle 3 (2026-05-06): the cycle-2 ``margin-top:
   -3.25rem`` approach broke sticky-positioning inside the
   drawer scroll containers — the flex height chain stopped
   producing a real scroll context, so ``.ui-preview-drawer__
   header`` no longer pinned at top:0 (ended up scrolling with
   body content + leaving paragraph-1 tail visible above the
   pinned title). Reverted the margin shift.
   Trade-off: when the navbar hides on scroll-down, an empty
   strip appears at the top of the shell where the navbar
   used to be (the navbar's translateY(-100%) keeps its layout
   slot reserved). Accepted as the lesser evil vs the broken
   sticky preview titles + the dropdown clipping that
   alternative cycle-1 ``overflow: hidden`` introduced. M20
   stays 🔴 OPEN for a future redesign (likely
   ``position: fixed`` on the navbar with body padding-top,
   which keeps the flex chain intact). */
.shell-center {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  container-type: inline-size;
  container-name: shell-center;
  min-width: calc(320px + 2 * 1.25rem);
  min-height: 0;
  overflow-y: auto;
  padding: 1.25rem;
  overflow-wrap: anywhere;
  word-break: break-word;
  /* No explicit background — body's org-color tint
       (``color-mix(in srgb, var(--org-color) 5%, var(--bg-primary))`` in
       _layout.scss) shows through. Setting an explicit background here
       would override the tint. */
}

.shell-center .button {
  white-space: normal;
  height: auto;
  min-height: 2.5em;
}

.shell-workspace {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  height: 100%;
}

.invitation-list-card {
  flex: 1 0 auto;
  min-height: 100%;
}

@media (max-width: 768px) {
  .invitation-list-card > .card-content,
.invitation-list-card > .card-header,
.invitation-list-card > .card-header-title {
    padding-left: 0;
    padding-right: 0;
  }
  .invitation-list-card > .card-content > .table-scroll-container,
.invitation-list-card > .card-content > div[style*="overflow-x"] {
    margin-left: 0;
    margin-right: 0;
    width: 100%;
  }
}

.shell-workspace__label {
  font-size: 0.875rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text-secondary);
  margin: 0 0 0.25rem 0;
  /* IDEA-197 user steer 2026-05-28: hyphenate long uppercase labels
     * (e.g. lt "PRENUMERATOS / KVIETIMAI") on narrow workspace widths.
     * Same pattern as the table-header hyphenation in _org_dashboard.scss;
     * relies on the browser's dictionary keyed off ``<html lang="...">``. */
  hyphens: auto;
  -webkit-hyphens: auto;
  -moz-hyphens: auto;
  -ms-hyphens: auto;
  overflow-wrap: break-word;
}

.shell-pane-snap {
  display: flex;
  flex-direction: row;
  flex: 1 1 auto;
  align-items: stretch;
  min-height: 0;
  min-width: 0;
  height: 100%;
  width: 100%;
  overflow-x: visible;
  scroll-snap-type: none;
}

.shell-pane-snap > #shell-swap-target {
  display: contents;
}

.shell-pane-snap > .shell-pane-snap__workspace-wrapper,
.shell-pane-snap > .shell-pane-snap__preview-wrapper,
.shell-pane-snap > #shell-swap-target > .shell-pane-snap__workspace-wrapper {
  display: flex;
  flex: 0 0 auto;
  align-items: stretch;
  min-height: 0;
  height: 100%;
}

/* M6 cycle 2 (2026-05-06): apply the mobile-style 0.5rem
   padding ceiling across BOTH mobile AND tablet (≤1024px) per
   user direction — "when either panel is open, gaps are too
   generous" on tablet. Desktop (≥1025px) keeps the wider
   defaults. The bottom-tab reservation stays mobile-only (it
   only renders ≤768px). */
@media (max-width: 1024px) {
  .shell-center {
    padding: 0.5rem;
    min-width: calc(320px + 2 * 0.5rem);
  }
  .shell-drawer__body {
    padding: 0.5rem;
  }
}

.shell-pane-lip[x-cloak] {
  display: none !important;
}

@media (min-width: 769px) {
  .shell-pane-lip {
    display: none;
  }
}

@media (max-width: 768px) {
  .shell-main {
    position: relative;
  }
  .shell-center {
    /* IDEA-195: drop horizontal padding on mobile so section cards
           (which now have ``padding-left/right: 0`` on the org dashboard
           per ``_org_dashboard.scss``) fill the full pane width edge to
           edge. The 0.5rem inherited from the tablet block compressed
           wide tables visually past the card boundary even after the
           card-content padding was zeroed. Vertical padding kept
           (top via inherited 0.5rem; bottom via the bottom-nav +
           burger-trigger reservation rules below). */
    padding-left: var(--shell-edge-gutter);
    padding-right: 0;
    width: 100%;
    min-width: 0;
    -webkit-overflow-scrolling: touch;
    padding-bottom: calc(56px + env(safe-area-inset-bottom, 0px));
  }
  /* IDEA-149 cross-IDEA amendment (amends IDEA-143/160/195): when the mobile
       navs retract on scroll-down (body.navbar-is-hidden), reclaim the bottom-
       tab's reserved 56px so the centre — the chat composer especially — sticks
       to the TRUE bottom instead of leaving a gap where the slid-away nav was.
       Transition matches the nav's own translateY(100%) 0.2s slide so the
       composer glides down in lockstep. */
  .shell-center {
    transition: padding-bottom 0.2s ease-out;
  }
  body.navbar-is-hidden .shell-center {
    padding-bottom: env(safe-area-inset-bottom, 0px);
  }
  .shell-pane-snap.is-preview-active .shell-center {
    padding-right: var(--shell-edge-gutter);
  }
  .shell-pane-lip {
    background: transparent;
    border: 0;
    color: var(--text-secondary);
    display: flex;
    justify-content: center;
    transition: background-color 0.12s ease-out, color 0.12s ease-out;
    /* Centred vertical spine. */
    position: fixed;
    top: 0;
    bottom: 0;
    z-index: 10;
    width: var(--shell-edge-gutter);
    align-items: center;
    padding: 0;
    margin: 0;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
  }
  .shell-pane-lip::before {
    content: '';
    position: absolute;
    top: 0;
    bottom: 0;
    left: 50%;
    transform: translateX(-50%);
    width: 2px;
    background-color: var(--border-secondary);
    transition: background-color 0.12s ease-out, width 0.12s ease-out;
  }
  .shell-pane-lip:hover, .shell-pane-lip:focus-visible {
    background-color: var(--bg-tertiary);
    color: var(--text-primary);
  }
  .shell-pane-lip:hover::before, .shell-pane-lip:focus-visible::before {
    background-color: var(--text-secondary);
    width: 3px;
  }
  .shell-pane-lip:focus-visible {
    outline: 2px solid var(--bulma-link, #485fc7);
    outline-offset: -2px;
  }
  .shell-pane-lip.shell-pane-lip--left {
    left: 0;
  }
  .shell-pane-lip.shell-pane-lip--right {
    right: 0;
  }
  .shell-pane-lip .shell-pane-lip__chevron {
    position: relative;
    z-index: 1;
    background-color: var(--bg-secondary);
    padding: 0.125rem 0.1rem;
    border-radius: 50%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 0.75rem;
    line-height: 1;
    pointer-events: none;
  }
  .shell-pane-snap {
    display: flex;
    overflow-x: auto;
    overflow-y: hidden;
    scroll-snap-type: x mandatory;
    overscroll-behavior-x: contain;
    height: 100%;
    width: 100%;
  }
  .shell-pane-snap > .shell-pane-snap__workspace-wrapper,
.shell-pane-snap > .shell-center,
.shell-pane-snap > .shell-pane-snap__preview-wrapper,
.shell-pane-snap > #shell-swap-target > .shell-pane-snap__workspace-wrapper,
.shell-pane-snap > #shell-swap-target > .shell-center {
    flex: 0 0 100%;
    scroll-snap-align: start;
    min-width: 0;
    height: 100%;
  }
  .shell-pane-snap > .shell-pane-snap__workspace-wrapper,
.shell-pane-snap > .shell-pane-snap__preview-wrapper,
.shell-pane-snap > #shell-swap-target > .shell-pane-snap__workspace-wrapper {
    display: flex;
    flex-direction: column;
  }
  .shell-pane-snap > .shell-pane-snap__workspace-wrapper > .shell-drawer,
.shell-pane-snap > .shell-pane-snap__preview-wrapper > .shell-drawer,
.shell-pane-snap > #shell-swap-target > .shell-pane-snap__workspace-wrapper > .shell-drawer {
    flex: 1 1 auto;
    width: 100%;
    min-width: 0;
    height: 100%;
  }
  .shell-pane-snap > .shell-pane-snap__preview-wrapper.shell-drawer--no-preview-wrapper {
    flex: 0 0 0;
    min-width: 0;
    overflow: hidden;
    scroll-snap-align: none;
  }
}

/* ===========================================
   Dropdowns (card clipping, viewport positioning)
   =========================================== */
/* Suppress Bulma’s dropdown-trigger .button ::after when we use an explicit icon (e.g. angle-down). */
.dropdown-trigger .button.is-arrowless::after {
  display: none !important;
}

.dropdown {
  position: relative;
}

.dropdown .dropdown-menu {
  position: absolute;
  z-index: 30;
  min-width: 12rem;
  max-width: 20rem;
  padding-top: 4px;
  padding-bottom: 4px;
  background-color: var(--bg-secondary);
  border-radius: 6px;
  box-shadow: 0 0.5em 1em -0.125em var(--shadow-color), 0 0 0 1px var(--border-light);
  border: none;
  overflow: hidden;
}

.dropdown .dropdown-menu.viewport-adjusted {
  transition: transform 0.1s ease-out;
}

.dropdown .dropdown-menu .dropdown-item {
  display: flex;
  align-items: center;
  gap: 0.5em;
  padding: 0.375rem 1rem;
  color: var(--text-primary);
}

.dropdown .dropdown-menu .dropdown-item .icon {
  width: 1em;
  height: 1em;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  margin: 0 !important;
  flex-shrink: 0;
}

.dropdown .dropdown-menu .dropdown-item:hover {
  background-color: var(--bg-tertiary);
  color: var(--text-primary);
}

.dropdown.is-right .dropdown-menu {
  right: 0;
  left: auto;
}

.dropdown.is-left .dropdown-menu {
  left: 0;
  right: auto;
}

/* Right-align when inside level-right or card header icon */
.level-right .dropdown .dropdown-menu,
.card-header-icon .dropdown .dropdown-menu {
  right: 0;
  left: auto;
}

/* Card context: overflow + z-index → _cards.scss */
/* ---------------------------------------------
   IDEA-176: click-toggle replaces :hover when
   dropdown-toggle.js is loaded
   ---------------------------------------------
   When the global click-toggle handler is active (it adds
   .js-dropdown-toggle to <body> at init), suppress Bulma's :hover
   rule on .dropdown.is-hoverable so visibility is driven exclusively
   by .is-active (toggled via click). The :not(.is-active) clause
   keeps the swap clean — when the dropdown IS active, the menu
   stays visible regardless of cursor position.

   When JS is disabled (or the module fails to load), .js-dropdown-toggle
   never lands on <body>, the override doesn't apply, and Bulma's
   default :hover behaviour is preserved as a graceful fallback.

   Selector intentionally does NOT match navbar-item dropdowns
   (.navbar-item.has-dropdown.is-hoverable) — those have their own
   Alpine handling and are not in scope. */
body.js-dropdown-toggle .dropdown.is-hoverable:not(.is-active):hover .dropdown-menu {
  display: none;
}

body.js-dropdown-toggle .dropdown.is-hoverable.is-active .dropdown-menu {
  display: block;
}

/* ===========================================
   Notifications, messages container, alerts
   =========================================== */
/* Messages inside .container: vertical padding only (horizontal from container) */
/* Sticky below navbar (navbar height ~3.25rem) so notifications stay visible on long pages */
#messages-container {
  position: sticky;
  top: 3.25rem;
  z-index: 25;
  padding: 0.5rem 0;
  margin: 0;
}

#messages-container:empty {
  padding: 0;
  min-height: 0;
  overflow: hidden;
}

#messages-container .notification {
  padding: 0.5rem 0.75rem;
  font-size: 0.875rem;
  margin-bottom: 0.25rem;
}

#messages-container .notification:last-child {
  margin-bottom: 0;
}

@media screen and (max-width: 768px) {
  #messages-container {
    padding: 0.5rem 0;
  }
}

.notification {
  position: relative;
  border-radius: 6px;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
  animation: slideIn 0.3s ease-out;
}

.notification .delete {
  position: absolute;
  top: 0.5rem;
  right: 0.5rem;
  opacity: 0.7;
  transition: opacity 0.2s ease;
}

.notification .delete:hover {
  opacity: 1;
}

.notification.is-danger {
  background-color: rgba(220, 38, 38, 0.1);
  border: 1px solid var(--color-danger);
  color: var(--color-danger);
}

.notification.is-danger .title {
  color: var(--color-danger);
}

.notification.fade-out {
  animation: fadeOut 0.3s ease-out forwards;
}

.dark .notification {
  /* Fully opaque backgrounds so content behind never shows through (no text-over-text) */
}

.dark .notification.is-info.is-light {
  background-color: #273553;
  color: var(--text-primary);
}

.dark .notification.is-success {
  background-color: #24432f;
  color: var(--text-primary);
}

.dark .notification.is-danger {
  background-color: #502828;
  color: var(--text-primary);
}

.dark .notification.is-warning {
  background-color: #523921;
  color: var(--text-primary);
}

.dark .notification.is-primary {
  background-color: #423d24;
  color: var(--text-primary);
}

@keyframes slideIn {
  from {
    opacity: 0;
    transform: translateY(-10px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

@keyframes fadeOut {
  from {
    opacity: 1;
    transform: translateY(0);
  }
  to {
    opacity: 0;
    transform: translateY(-10px);
  }
}

/* ===========================================
   Toast notifications (IDEA-138)
   ===========================================
   Top-anchored stacking notification surface. Single instance per
   page, owned by the Alpine ``toastStack`` factory in ``notify.js``.

   Positioning:
   * Top anchor on all viewports — bottom is contested by the chat
     composer (today) and IDEA-143 mobile bottom-tab nav (future).
   * iOS notch / dynamic-island honoured via env(safe-area-inset-top).
   * Mobile (≤768px): full-width with edge margins.
   * Tablet+ (>768px): top-right with max-width 400px.

   Stacking:
   * z-index 60 — above drawers (~30/40 in _drawer.scss) AND above modals
     (50/51 in _modal.scss). Toasts must stay topmost so a success/error
     toast triggered BY a modal action remains visible AND interactable
     above the modal that triggered it (e.g. form-modal POST fails →
     fragment_error() → sticky error toast must overlay the still-open
     modal, AND its dismiss control must not be intercepted by the modal
     backdrop). Amended from 50 → 60 by IDEA-141.
   * Newest toast unshift'd to the top of the stack (first in array =
     top of visible column). The column flows downward; older toasts
     drift down as new ones arrive.
   =========================================== */
.toast-stack {
  position: fixed;
  top: calc(env(safe-area-inset-top, 0px) + 1rem);
  z-index: 60;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  pointer-events: none;
  /* container itself is not interactive */
  left: 1rem;
  right: 1rem;
}

@media (min-width: 769px) {
  .toast-stack {
    left: auto;
    right: 1rem;
    width: auto;
    max-width: 400px;
    min-width: 280px;
  }
}

.toast-stack[inert] {
  pointer-events: none;
}

.toast {
  pointer-events: auto;
  cursor: pointer;
  margin-bottom: 0;
  padding: 0.75rem 2.25rem 0.75rem 1rem;
  box-shadow: 0 4px 12px rgba(10, 10, 10, 0.18);
  font-size: 0.875rem;
  line-height: 1.4;
  position: relative;
  animation: toast-slide-in 180ms ease-out;
}

.toast__body {
  word-break: break-word;
}

.toast__dismiss {
  position: absolute;
  top: 0.5rem;
  right: 0.5rem;
}

.toast--success {
  /* uses Bulma is-success; reserved for future overrides */
}

.toast--info {
  /* uses Bulma is-info */
}

.toast--warning {
  /* uses Bulma is-warning */
}

.toast--error {
  /* uses Bulma is-danger */
}

.toast-stack__overflow {
  pointer-events: auto;
  align-self: flex-start;
  background: rgba(10, 10, 10, 0.7);
  color: white;
  padding: 0.25rem 0.75rem;
  border-radius: 4px;
  font-size: 0.75rem;
  font-weight: 500;
}

@media screen and (min-width: 769px) and (max-width: 1024px) {
  .toast-stack__overflow {
    align-self: flex-end;
  }
}

@keyframes toast-slide-in {
  from {
    transform: translateY(-1rem);
    opacity: 0;
  }
  to {
    transform: translateY(0);
    opacity: 1;
  }
}

/* ===========================================
   Modal primitives (IDEA-141)
   ===========================================
   Two cotton primitives — `<c-confirm-modal>` (alertdialog) and
   `<c-form-modal>` (dialog) — render once per page in shell.html and
   base.html as singleton overlays. JS API `ui.modal.confirm()` /
   `ui.modal.form()` populates content + opens. Coordinator at
   `Alpine.store('uiModalCoordinator')` enforces modal-from-modal
   refusal (max stack depth 1).

   Stacking (canonical ordering for overlay surfaces):
   * z-index 50 — backdrop
   * z-index 51 — card
   * Drawer mobile overlay sits at 40 (below modal — see _drawer.scss).
   * Toast container sits at 60 (above modal — see _toast.scss). Toasts
     overlay modals so a success/error toast triggered BY a modal action
     remains visible AND interactable above the still-open modal.

   Scope:
   * The `.ui-modal` class scopes IDEA-141 styles. The legacy `.modal`
     class (Bulma default, used by the four legacy partials) is NOT
     touched — keeps existing modals working unchanged through the
     IDEA-145–155 surface-migration window.
   * IDEA-158 cleanup retires the legacy partials + this scoping
     concern goes away.
   =========================================== */
.ui-modal {
  z-index: 50;
  animation: ui-modal-backdrop-fade 150ms ease-out;
}

.ui-modal .modal-card {
  z-index: 51;
  animation: ui-modal-card-slide-in 200ms ease-out;
  box-shadow: 0 8px 24px rgba(10, 10, 10, 0.25);
}

@media (max-width: 768px) {
  .ui-modal .modal-card {
    width: calc(100vw - 1rem);
    max-width: calc(100vw - 1rem);
    max-height: calc(100vh - 2rem);
  }
}

.ui-modal .modal-card-head {
  align-items: center;
}

.ui-modal .modal-card-head .icon {
  flex-shrink: 0;
}

.ui-modal .modal-card-body {
  min-height: 4rem;
}

.ui-modal .modal-card-foot {
  justify-content: flex-end;
}

.ui-modal--primary .modal-card-head .icon {
  color: var(--bulma-primary, #00d1b2);
}

.ui-modal--warning .modal-card-head .icon {
  color: var(--bulma-warning, #ffdd57);
}

.ui-modal--danger .modal-card-head .icon {
  color: var(--bulma-danger, #f14668);
}

.ui-modal__body--loading {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 8rem;
}

.ui-modal__body--loading .ui-modal__loading-indicator {
  font-size: 1.5rem;
  color: var(--bulma-text-light, #b5b5b5);
}

.ui-modal__error {
  margin-top: 0.5rem;
}

.ui-modal__reason {
  margin-top: 0.75rem;
}

@keyframes ui-modal-backdrop-fade {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

@keyframes ui-modal-card-slide-in {
  from {
    transform: translateY(-1rem);
    opacity: 0;
  }
  to {
    transform: translateY(0);
    opacity: 1;
  }
}

/* ===========================================
   Form controls
   =========================================== */
/* Single pattern for native <select>: wrap in .select; arrow stays right-aligned.
   Use .is-small or .is-fullwidth as needed. Do not add custom icons inside the trigger. */
.select:not(.is-multiple):not(.is-loading) select {
  padding-right: 2.5em;
  /* room for Bulma’s ::after arrow */
}

.control.has-icons-left .icon {
  color: var(--text-muted);
}

/* Grouped form fields (e.g. inline buttons) - spacing between controls */
.field.is-grouped .control {
  margin-right: 0.75rem;
}

.field.is-grouped .control:last-child {
  margin-right: 0;
}

/* Form inputs: distinct background from container */
.input,
.textarea,
.select select {
  background-color: var(--bg-primary) !important;
  color: var(--text-primary) !important;
  border-color: var(--border-primary) !important;
}

.input::placeholder,
.textarea::placeholder,
.select select::placeholder {
  color: var(--text-muted) !important;
}

.input:focus, .input:active,
.textarea:focus,
.textarea:active,
.select select:focus,
.select select:active {
  border-color: var(--color-primary) !important;
  box-shadow: 0 0 0 2px rgba(124, 58, 237, 0.15) !important;
}

.dark .input, .dark .textarea, .dark .select select {
  background-color: var(--bg-primary) !important;
  border-color: var(--border-primary) !important;
  color-scheme: dark;
}

.dark .input:focus, .dark .input:active, .dark .textarea:focus, .dark .textarea:active, .dark .select select:focus, .dark .select select:active {
  border-color: var(--color-secondary) !important;
  box-shadow: 0 0 0 2px rgba(124, 58, 237, 0.25) !important;
}

/* Native select dropdown options: dark theme (where supported) */
.dark .select select,
.dark select.input {
  color-scheme: dark;
}

.dark .select select option,
.dark select.input option {
  background-color: var(--bg-primary);
  color: var(--text-primary);
}

/* Event reminder snooze: one arrow only (native select); select and Snooze button strictly same size */
.event-reminder-alarm-wrap .event-reminder-snooze-form {
  display: inline-flex;
  align-items: stretch;
  gap: 0.25rem;
}

.event-reminder-alarm-wrap .event-reminder-snooze-form .select,
.event-reminder-alarm-wrap .event-reminder-snooze-form .button {
  width: 7rem;
  min-width: 7rem;
  flex-shrink: 0;
}

.event-reminder-alarm-wrap .event-reminder-snooze-form .select::after {
  display: none !important;
}

.event-reminder-alarm-wrap .event-reminder-snooze-form .select select {
  width: 100%;
  box-sizing: border-box;
}

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

/* Single-submit / in-flight primary button (sync POST or HTMX); toggled by sync_form_submit.js */
.sync-submit-button:not(.sync-submit-button--in-flight) .sync-submit-button__idle {
  display: inline-flex !important;
  align-items: center;
  gap: 0.35em;
}

.sync-submit-button:not(.sync-submit-button--in-flight) .sync-submit-button__in-flight-label {
  display: none !important;
}

.sync-submit-button.sync-submit-button--in-flight {
  cursor: wait;
}

.sync-submit-button.sync-submit-button--in-flight .sync-submit-button__idle {
  display: none !important;
}

.sync-submit-button.sync-submit-button--in-flight .sync-submit-button__in-flight-label {
  display: inline-flex !important;
  align-items: center;
  gap: 0.35em;
}

.help-icon-btn {
  display: inline-flex;
  align-items: center;
  background: none;
  border: none;
  padding: 0 0 0 0.3rem;
  cursor: pointer;
  color: var(--color-text-secondary, #888);
  font-size: 0.7rem;
  line-height: 1;
  opacity: 0.55;
  vertical-align: middle;
  transition: opacity 0.15s, color 0.15s;
}

.help-icon-btn:hover, .help-icon-btn:focus-visible {
  opacity: 1;
  color: var(--color-primary);
  outline: none;
}

.help-popover {
  position: absolute;
  z-index: 9000;
  width: max-content;
  max-width: 360px;
  max-height: 280px;
  overflow-y: auto;
  overflow-x: auto;
  overflow-wrap: anywhere;
  background: var(--bulma-scheme-main, #fff);
  border: 1px solid var(--border-light, #e5e7eb);
  border-radius: 0.5rem;
  box-shadow: 0 6px 20px var(--shadow-color-medium, rgba(0, 0, 0, 0.15));
  padding: 0.75rem 1rem;
  font-size: 0.825rem;
  line-height: 1.5;
  color: var(--bulma-text, #363636);
}

@media (max-width: 376px) {
  .help-popover {
    max-width: calc(100vw - 16px);
  }
}

.dark .help-popover {
  background: var(--bulma-scheme-main, #1e2129);
  border-color: var(--border-light, #374151);
  color: var(--bulma-text, #d1d5db);
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.4);
}

.help-popover .help-popover-content p,
.help-popover .help-popover-content li {
  margin-bottom: 0.4rem;
}

.help-popover .help-popover-content strong {
  color: var(--bulma-text-strong, inherit);
  font-weight: 600;
}

.help-popover .help-popover-content em {
  color: var(--color-text-secondary, #6b7280);
  font-style: italic;
}

.help-popover .help-popover-content br + em,
.help-popover .help-popover-content ul {
  margin-top: 0.25rem;
}

/* ===========================================
   Form widgets: icon picker, color picker, tag picker
   Picker mixins are local (used only here).
   =========================================== */
/* ---- Picker mixins (icon/color swatch shared base) ---- */
/* ---- Picker fieldsets (shared reset for accessibility) ---- */
.tag-picker-fieldset,
.color-picker-fieldset,
.icon-picker-fieldset {
  border: 0;
  padding: 0;
  margin: 0;
  min-width: 0;
}

.tag-picker-fieldset legend,
.color-picker-fieldset legend,
.icon-picker-fieldset legend {
  float: left;
  width: 100%;
  padding: 0;
  margin: 0;
}

/* ---- Icon picker ---- */
.icon-picker {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.icon-picker .icon-swatch input[type="radio"] {
  position: absolute !important;
  opacity: 0 !important;
  width: 0 !important;
  height: 0 !important;
  pointer-events: none !important;
  visibility: hidden !important;
  display: none !important;
}

.icon-swatch {
  position: relative;
  width: 2.5rem;
  height: 2.5rem;
  border-radius: 0.375rem;
  border: 2px solid var(--border-light);
  cursor: pointer;
  transition: all 0.2s ease;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 1px 3px var(--shadow-color);
  outline: none;
  color: var(--text-secondary);
  background: var(--bg-secondary);
}

.icon-swatch:focus {
  outline: 2px solid var(--color-primary);
  outline-offset: 2px;
}

.icon-swatch:hover {
  transform: scale(1.05);
  box-shadow: 0 4px 8px var(--shadow-color-medium);
  border-color: var(--color-primary);
}

.icon-swatch.is-selected {
  border-color: var(--color-primary);
  box-shadow: 0 0 0 3px var(--picker-selected-ring);
}

.icon-swatch:hover i {
  color: var(--color-primary);
}

.icon-swatch.is-selected {
  background: var(--bg-primary);
}

.icon-swatch.is-selected i {
  color: var(--color-primary);
}

.icon-swatch i {
  font-size: 1rem;
  transition: color 0.2s ease;
}

.dark .icon-swatch {
  border-color: var(--border-primary);
  background: var(--bg-tertiary);
  color: var(--text-secondary);
}

.dark .icon-swatch:hover {
  box-shadow: 0 4px 8px var(--shadow-color-strong);
  border-color: var(--color-primary);
}

.dark .icon-swatch.is-selected {
  border-color: var(--color-primary);
  box-shadow: 0 0 0 3px var(--picker-selected-ring);
}

.dark .icon-swatch.is-selected {
  background: var(--bg-secondary);
}

.icon-picker-responsive {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(2.5rem, 1fr));
  gap: 0.5rem;
  justify-items: center;
}

.icon-picker-responsive .icon-swatch {
  width: 100%;
  max-width: 2.5rem;
}

/* ---- Color picker ---- */
.color-picker {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.color-picker .color-swatch input[type="radio"] {
  position: absolute !important;
  opacity: 0 !important;
  width: 0 !important;
  height: 0 !important;
  pointer-events: none !important;
  visibility: hidden !important;
  display: none !important;
}

.color-picker.color-picker-responsive {
  display: grid !important;
  grid-template-columns: repeat(auto-fill, 2.5rem) !important;
  gap: 0.5rem !important;
  justify-content: start !important;
}

.color-picker.color-picker-responsive .color-swatch {
  width: 2.5rem !important;
  height: 2.5rem !important;
}

.color-swatch {
  position: relative;
  width: 2.5rem;
  height: 2.5rem;
  border-radius: 0.375rem;
  border: 2px solid var(--border-light);
  cursor: pointer;
  transition: all 0.2s ease;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 1px 3px var(--shadow-color);
  outline: none;
}

.color-swatch:focus {
  outline: 2px solid var(--color-primary);
  outline-offset: 2px;
}

.color-swatch:hover {
  transform: scale(1.05);
  box-shadow: 0 4px 8px var(--shadow-color-medium);
  border-color: var(--color-primary);
}

.color-swatch.is-selected {
  border-color: var(--color-primary);
  box-shadow: 0 0 0 3px var(--picker-selected-ring);
}

.color-swatch.is-selected .checkmark {
  opacity: 1;
}

.color-swatch .checkmark {
  color: var(--color-white);
  font-size: 0.875rem;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.5);
  z-index: 1;
  opacity: 0;
  transition: opacity 0.2s ease;
}

.color-swatch .checkmark i {
  filter: drop-shadow(0 1px 1px var(--shadow-color-strong));
}

.dark .color-swatch {
  border-color: var(--border-primary);
}

.dark .color-swatch:hover {
  box-shadow: 0 4px 8px var(--shadow-color-strong);
  border-color: var(--color-primary);
}

.dark .color-swatch.is-selected {
  border-color: var(--color-primary);
  box-shadow: 0 0 0 3px var(--picker-selected-ring);
}

/* Light colors: dark checkmark for contrast (class set by Python luminance check) */
.color-swatch.is-light {
  border-color: var(--border-secondary);
}

.color-swatch.is-light .checkmark {
  color: var(--bg-accent);
  text-shadow: 0 1px 2px rgba(255, 255, 255, 0.5);
}

.color-swatch.is-light .checkmark i {
  filter: drop-shadow(0 1px 1px rgba(255, 255, 255, 0.5));
}

/* ---- Tag picker ---- */
.tag-picker-responsive {
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem;
  align-items: flex-start;
}

/* Tag checkbox: set --tag-color via inline style, CSS handles all states.
   Unselected = faded, selected = filled, with dark theme support.
   cursor: pointer for filter/form contexts (labels are clickable). */
.tag-checkbox,
.tag-picker .tag-checkbox,
#article-filters .tag-checkbox {
  position: relative;
  border-radius: 0.25rem;
  cursor: pointer;
  transition: all 0.15s ease;
  user-select: none;
  padding: 0.25rem 0.5rem;
  display: inline-block;
  font-size: 0.875rem;
  background-color: color-mix(in srgb, var(--tag-color, #6b7280) 22%, transparent);
  color: var(--text-primary);
  border: 1px solid color-mix(in srgb, var(--tag-color, #6b7280) 35%, transparent);
}

.tag-checkbox input[type="checkbox"],
.tag-picker .tag-checkbox input[type="checkbox"],
#article-filters .tag-checkbox input[type="checkbox"] {
  position: absolute !important;
  opacity: 0 !important;
  width: 0 !important;
  height: 0 !important;
  pointer-events: none !important;
  visibility: hidden !important;
  display: none !important;
}

.tag-checkbox:hover,
.tag-picker .tag-checkbox:hover,
#article-filters .tag-checkbox:hover {
  background-color: color-mix(in srgb, var(--tag-color, #6b7280) 40%, transparent);
  border-color: color-mix(in srgb, var(--tag-color, #6b7280) 55%, transparent);
  transform: translateY(-1px);
  box-shadow: 0 2px 4px var(--shadow-color);
}

.tag-checkbox.is-selected,
.tag-picker .tag-checkbox.is-selected,
#article-filters .tag-checkbox.is-selected {
  background-color: var(--tag-color, #6b7280);
  color: #ffffff;
  text-shadow: 0 1px 1px rgba(0, 0, 0, 0.2);
  border-color: var(--tag-color, #6b7280);
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--tag-color, #6b7280) 30%, transparent);
}

.tag-checkbox.is-selected:hover,
.tag-picker .tag-checkbox.is-selected:hover,
#article-filters .tag-checkbox.is-selected:hover {
  filter: brightness(1.1);
}

.dark .tag-checkbox, .dark .tag-picker .tag-checkbox, .dark #article-filters .tag-checkbox {
  background-color: color-mix(in srgb, var(--tag-color, #6b7280) 18%, transparent);
  border-color: color-mix(in srgb, var(--tag-color, #6b7280) 30%, transparent);
}

.dark .tag-checkbox:hover, .dark .tag-picker .tag-checkbox:hover, .dark #article-filters .tag-checkbox:hover {
  background-color: color-mix(in srgb, var(--tag-color, #6b7280) 35%, transparent);
  border-color: color-mix(in srgb, var(--tag-color, #6b7280) 50%, transparent);
}

.dark .tag-checkbox.is-selected, .dark .tag-picker .tag-checkbox.is-selected, .dark #article-filters .tag-checkbox.is-selected {
  background-color: color-mix(in srgb, var(--tag-color, #6b7280) 75%, #000000);
  border-color: color-mix(in srgb, var(--tag-color, #6b7280) 60%, transparent);
  color: #ffffff;
}

/* ---- Tag list/display (grid of tag cards, not the picker) ---- */
.tag-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(17.5rem, 1fr));
  gap: 1rem;
}

.tag-card {
  border-left: 4px solid var(--border-secondary);
  background: var(--bg-primary);
  border: 1px solid var(--border-primary);
  border-left-width: 4px;
  border-radius: 0.375rem;
  padding: 1rem;
  transition: all 0.2s;
  position: relative;
}

.tag-card:hover {
  box-shadow: 0 2px 8px var(--shadow-color);
  border-color: var(--border-secondary);
}

.tag-card:hover .tag-actions {
  opacity: 1;
}

.tag-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 0.5rem;
}

.tag-name {
  font-weight: 600;
  font-size: 1.125rem;
  color: var(--text-primary);
}

.tag-actions {
  opacity: 0;
  transition: opacity 0.2s;
}

.tag-meta {
  font-size: 0.875rem;
  color: var(--text-muted);
}

.tag-scope {
  background: var(--bg-tertiary);
  padding: 0.125rem 0.5rem;
  border-radius: 0.75rem;
  font-size: 0.75rem;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.03em;
}

/* ---- HTMX Autocomplete widget ---- */
.autocomplete-container {
  position: relative;
  display: block;
  width: 100%;
}

.autocomplete-container input[type="text"] {
  width: 100%;
  display: block;
}

.autocomplete-container input[type="text"].autocomplete-input {
  width: 100%;
}

.autocomplete-input-wrapper {
  position: relative;
  display: flex;
  align-items: stretch;
  width: 100%;
}

.autocomplete-input {
  width: 100%;
  flex: 1;
  padding-right: 2.5rem;
}

.autocomplete-dropdown-trigger {
  position: absolute;
  right: 0;
  top: 0;
  bottom: 0;
  width: 2.5rem;
  min-width: 2.5rem;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  margin: 0;
  background: transparent;
  border: none;
  border-left: 1px solid var(--border-primary);
  cursor: pointer;
  color: var(--text-secondary);
  transition: background-color 0.2s ease, color 0.2s ease;
  z-index: 10;
}

.autocomplete-dropdown-trigger:hover, .autocomplete-dropdown-trigger:focus {
  outline: none;
  background-color: var(--bg-tertiary);
  color: var(--text-primary);
}

.autocomplete-dropdown-trigger .fas {
  font-size: 0.875rem;
  pointer-events: none;
}

.autocomplete-results {
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  z-index: 1000;
  margin-top: -1px;
  max-height: 200px;
  overflow-y: auto;
  background-color: var(--bg-secondary);
  border: 1px solid var(--border-primary);
  border-top: none;
  border-radius: 0 0 4px 4px;
  box-shadow: 0 2px 4px var(--shadow-color);
}

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

.autocomplete-item {
  padding: 0.75rem 1rem;
  cursor: pointer;
  border-bottom: 1px solid var(--border-light);
  transition: background-color 0.2s ease;
  color: var(--text-primary);
}

.autocomplete-item:hover, .autocomplete-item.is-active {
  background-color: var(--bg-tertiary);
}

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

.autocomplete-item.disabled {
  color: var(--text-muted);
  cursor: default;
  background-color: var(--bg-tertiary);
}

.autocomplete-item.disabled:hover {
  background-color: var(--bg-tertiary);
}

.dark .autocomplete-results {
  background-color: var(--bg-secondary);
  border-color: var(--border-primary);
}

.dark .autocomplete-dropdown-trigger {
  border-left-color: var(--border-primary);
  color: var(--text-secondary);
}

.dark .autocomplete-dropdown-trigger:hover {
  background-color: var(--bg-tertiary);
  color: var(--text-primary);
}

.dark .autocomplete-item {
  color: var(--text-primary);
  border-bottom-color: var(--border-primary);
}

.dark .autocomplete-item:hover, .dark .autocomplete-item.is-active {
  background-color: var(--bg-tertiary);
}

.dark .autocomplete-item.disabled {
  color: var(--text-muted);
  background-color: var(--bg-tertiary);
}

.dark .autocomplete-item.disabled:hover {
  background-color: var(--bg-tertiary);
}

/* .spinner, @keyframes spin → components/_utilities.scss */
/* ---- Address widget (org first + Google Places) ---- */
.address-widget {
  position: relative;
  display: block;
}

.address-widget .address-widget-input {
  width: 100%;
}

.address-widget .address-widget-dropdown {
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  z-index: 1000;
  margin-top: -1px;
  max-height: 200px;
  overflow-y: auto;
  background-color: var(--bg-secondary);
  border: 1px solid var(--border-primary);
  border-top: none;
  border-radius: 0 0 4px 4px;
  box-shadow: 0 2px 4px var(--shadow-color);
}

.address-widget .address-widget-item {
  padding: 0.75rem 1rem;
  cursor: pointer;
  border-bottom: 1px solid var(--border-light);
  transition: background-color 0.2s ease;
  color: var(--text-primary);
}

.address-widget .address-widget-item:hover {
  background-color: var(--bg-tertiary);
}

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

.address-widget .address-widget-item.disabled {
  color: var(--text-muted);
  cursor: default;
}

.address-widget .address-widget-item.address-widget-other {
  font-style: italic;
}

/* Google Places Autocomplete dropdown (.pac-container): dark theme.
   Rendered by Maps JS on body; use theme variables so it matches app. */
.dark .pac-container,
[data-theme='dark'] .pac-container {
  background-color: var(--bg-primary) !important;
  border-color: var(--border-primary) !important;
  color: var(--text-primary) !important;
}

.dark .pac-item,
[data-theme='dark'] .pac-item {
  color: var(--text-primary) !important;
  border-top-color: var(--border-primary) !important;
}

.dark .pac-item:hover, .dark .pac-item.pac-item-selected,
[data-theme='dark'] .pac-item:hover,
[data-theme='dark'] .pac-item.pac-item-selected {
  background-color: var(--bg-secondary) !important;
}

.dark .pac-item-query,
[data-theme='dark'] .pac-item-query {
  color: var(--text-primary) !important;
}

.dark .pac-matched,
[data-theme='dark'] .pac-matched {
  color: var(--color-primary) !important;
}

/* ---- Date input (form widget) ---- */
input[type="date"].input {
  width: auto;
  min-width: 150px;
  max-width: 300px;
  box-sizing: border-box;
}

/* ---- Searchable select / multi-select widgets (#208) ---- */
/* Container positioning and dropdown overlay come from .autocomplete-container
   and .autocomplete-results / .autocomplete-item shared classes above. */
.autocomplete-item.autocomplete-create {
  color: var(--link);
  font-weight: 600;
}

.searchable-multi-select-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem;
  margin-bottom: 0.25rem;
}

.searchable-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  border-radius: 0.25rem;
  padding: 0.15rem 0.5rem;
  font-size: 0.875rem;
  background-color: color-mix(in srgb, var(--tag-color, #6b7280) 22%, transparent);
  color: var(--text-primary);
  border: 1px solid color-mix(in srgb, var(--tag-color, #6b7280) 40%, transparent);
}

/* ===========================================
   Attachment Preview Modal (teisutis_kb)
   =========================================== */
.attachment-preview-modal {
  max-width: 95vw;
  max-height: 95vh;
  width: 95vw;
  height: 95vh;
  display: flex;
  flex-direction: column;
  /* Media previews (IDEA-088 Phase 3 PR F): the <audio>/<video> elements
     are rendered inside the flex #previewModalContent. Browsers default
     <audio> to display: inline, which ignores width and collapses the
     controls bar to w=0 inside a flex row. Forcing block + max-width
     keeps the width styling from loadAudioPreview / loadVideoPreview
     actually honoured. */
  /* Save / error feedback stays inside the modal (global #messages-container sits under .modal) */
}

.attachment-preview-modal .modal-card-head {
  flex-shrink: 0;
  padding: 0.75rem 1rem;
}

.attachment-preview-modal .modal-card-head .modal-card-title {
  margin: 0;
}

.attachment-preview-modal .modal-card-body {
  padding: 0.5rem;
  overflow: hidden;
  flex: 1;
  display: flex;
  flex-direction: column;
  min-height: 0;
}

.attachment-preview-modal #previewModalContent {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 0;
  overflow: hidden;
}

.attachment-preview-modal .attachment-audio-preview,
.attachment-preview-modal .attachment-video-preview {
  display: block;
  width: 100%;
  margin: 0 auto;
}

.attachment-preview-modal .attachment-audio-preview {
  max-width: 640px;
}

.attachment-preview-modal .attachment-video-preview {
  max-height: 70vh;
}

.attachment-preview-modal #previewModalDescription {
  flex-shrink: 0;
  padding-top: 1rem;
  border-top: 1px solid var(--border-light, #e5e7eb);
  margin-top: 0.5rem;
}

.attachment-preview-modal #previewDescriptionFeedback {
  flex-shrink: 0;
  margin-bottom: 0.75rem;
}

.attachment-preview-modal .modal-card-foot {
  flex-shrink: 0;
  padding: 0.75rem 1rem;
}

.attachment-preview-modal #previewModalResetZoom,
.attachment-preview-modal #previewModalSaveDescription {
  display: none;
}

/* ===========================================
   Assign Attachment Modal – selected item
   ===========================================
   Block-level box for selected article/event/FAQ.
   Replaces badge/pill (.tag) to support long text
   without overflow. */
#assignModal .assign-selected {
  display: flex;
  align-items: flex-start;
  gap: 0.5rem;
  padding: 0.5rem 0.75rem;
  border: 1px solid var(--border-light, #e5e7eb);
  border-radius: 0.25rem;
  background: var(--bg-secondary, #f9fafb);
  max-width: 100%;
}

#assignModal .assign-selected__text {
  flex: 1;
  min-width: 0;
  overflow-wrap: break-word;
  word-break: break-word;
  font-size: 0.875rem;
  line-height: 1.4;
}

#assignModal .assign-selected__clear {
  flex-shrink: 0;
  padding: 0;
  width: 1.25rem;
  height: 1.25rem;
  min-width: 1.25rem;
  min-height: 1.25rem;
  border: none;
  border-radius: 0.25rem;
  background: transparent;
  color: var(--text-secondary, #6b7280);
  font-size: 1rem;
  line-height: 1;
  cursor: pointer;
}

#assignModal .assign-selected__clear:hover {
  background: var(--border-light, #e5e7eb);
  color: var(--text-primary, #111);
}

#assignModal .assign-selected--article {
  border-left: 3px solid var(--bulma-primary);
}

#assignModal .assign-selected--event {
  border-left: 3px solid var(--bulma-info);
}

#assignModal .assign-selected--faq {
  border-left: 3px solid var(--bulma-warning);
}

/* ===========================================
   c-attachment-preview cotton (IDEA-159)
   ===========================================
   Mounts inside `<c-preview-drawer>` body host. Replaces the legacy
   `.attachment-preview-modal` (still used by un-migrated surfaces while
   IDEAs 145–158 finish the migration window). The drawer is a narrow
   column (~380px default), so the layout drops the 95vw/95vh modal-card
   sizing and stacks filename → content → description → actions
   vertically inside the body's available height.

   Loaders inside `data-preview-content` are populated by
   `Alpine.data('uiAttachmentPreview')` (panzoom image / PDF iframe /
   HTML5 audio-video / text / CSV / markdown / code highlight). Each
   loader sets specific child markup; this partial defines the
   container envelope that hosts those loaders.
   =========================================== */
.ui-attachment-preview {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

.ui-attachment-preview__filename {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--text-primary);
  word-break: break-word;
}

.ui-attachment-preview__filename .icon {
  flex: 0 0 auto;
  color: var(--text-secondary);
}

.ui-attachment-preview__content {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 12rem;
  max-height: 60vh;
  overflow: auto;
  background-color: var(--bg-tertiary);
  border-radius: 0.25rem;
  padding: 0.5rem;
}

.ui-attachment-preview__content img,
.ui-attachment-preview__content video,
.ui-attachment-preview__content iframe {
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
}

.ui-attachment-preview__content audio {
  display: block;
  width: 100%;
}

.ui-attachment-preview__content .icon.is-large {
  color: var(--text-secondary);
}

.ui-attachment-preview__description .label {
  color: var(--text-secondary);
  margin-bottom: 0.25rem;
}

.ui-attachment-preview__description .textarea {
  font-size: 0.875rem;
  line-height: 1.4;
}

.ui-attachment-preview__description [data-preview-description-feedback] {
  font-size: 0.875rem;
}

.ui-attachment-preview__actions {
  display: flex;
  justify-content: flex-end;
  flex-wrap: wrap;
  gap: 0.5rem;
  padding-top: 0.75rem;
  border-top: 1px solid var(--border-light);
}

.ui-attachment-preview__actions .buttons {
  margin-bottom: 0;
  flex-wrap: wrap;
  justify-content: flex-end;
}

/* ===========================================
   c-attachment-chip — singular pill primitive (IDEA-142)
   =========================================== */
/* Inline pill: preview affordance + filename + size + optional remove.
   Used internally by <c-file-uploader> for the "Selected files:" preview
   AND directly by future surfaces (IDEA-149 chat composer pending-files,
   IDEA-146/147/148 article/event/FAQ attachment lists in compact mode).

   Container classes are scoped to ``ui-attachment-chip`` so legacy
   ``.attachment-chip`` / ``.chat-file-pill`` styles in teisutis_core /
   teisutis_ai SCSS keep working unchanged for the legacy chat composer
   (until IDEA-149 swaps it). */
.ui-attachment-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.25rem 0.5rem 0.25rem 0.25rem;
  background: var(--bg-tertiary);
  border: 1px solid var(--border-primary);
  color: var(--text-primary);
  border-radius: 4px;
  font-size: 0.875rem;
  line-height: 1.2;
  max-width: 100%;
  box-sizing: border-box;
}

.ui-attachment-chip__preview {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  background: var(--bg-secondary);
  border-radius: 3px;
  overflow: hidden;
}

.ui-attachment-chip__preview--image img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.ui-attachment-chip__preview--audio {
  /* Audio element is wider than the preview slot — let it expand
           to a sensible compact width while staying inside the chip. */
  width: auto;
  height: 32px;
  min-width: 180px;
  background: transparent;
}

.ui-attachment-chip__preview--audio audio {
  width: 100%;
  height: 32px;
  display: block;
  /* Let the browser's native audio chrome render; we only
               reset baseline alignment. */
}

.ui-attachment-chip__preview--icon {
  color: var(--text-secondary);
  font-size: 1rem;
}

.ui-attachment-chip__body {
  flex: 1 1 auto;
  display: inline-flex;
  flex-direction: column;
  min-width: 0;
  /* allow ellipsis truncation */
}

.ui-attachment-chip__name {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  font-weight: 500;
}

.ui-attachment-chip__size {
  font-size: 0.75rem;
  color: var(--text-muted);
}

.ui-attachment-chip__remove {
  flex: 0 0 auto;
  margin-left: 0.25rem;
}

.ui-attachment-chip__remove:focus-visible {
  outline: 2px solid var(--color-primary);
  outline-offset: 2px;
}

/* Mobile: chips wrap and the audio preview takes full chip width. */
@media (max-width: 480px) {
  .ui-attachment-chip {
    max-width: 100%;
    flex-wrap: wrap;
  }
  .ui-attachment-chip__preview--audio {
    min-width: 0;
    flex: 1 1 100%;
  }
  .ui-attachment-chip__body {
    flex: 1 1 calc(100% - 40px);
  }
}

/* ===========================================
   c-file-uploader (IDEA-142)
   =========================================== */
/* Drop zone, drag/upload states, progress bar, chip-list layout.
   Container class scoped to ``ui-file-uploader`` so the legacy
   ``.attachment-upload-zone`` class (still co-applied via the cotton
   template for backwards-compat with existing styles in
   teisutis_core/teisutis_kb SCSS) keeps working unchanged. */
.ui-file-uploader {
  /* Inherit existing ``.attachment-upload-zone box`` look-and-feel
       from teisutis_core SCSS for the legacy adapter path; this rule
       set adds primitive-specific affordances on top. */
  /* Misconfigured stub (R15 loud-failure) — visible inline so
       reviewer notices instead of "silently never uploads". */
}

.ui-file-uploader__chip-list {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  align-items: flex-start;
}

.ui-file-uploader--misconfigured {
  margin: 1rem 0;
}

/* Mobile breakpoint — drop zone padding shrinks, chip wrap is the
   chip primitive's responsibility. */
@media (max-width: 480px) {
  .ui-file-uploader .attachment-drop-area {
    padding: 1rem 0.5rem;
  }
  .ui-file-uploader .buttons {
    flex-direction: column;
    align-items: stretch;
  }
}

/* ===========================================
   c-audio-recorder (IDEA-142)
   =========================================== */
/* Standalone audio recorder primitive. Inherits the existing
   .chat-voice-waveform / .chat-voice-status styles via co-applied
   classes (the cotton template renders both ``ui-audio-recorder__waveform``
   AND ``chat-voice-waveform`` so the existing _chat.scss rules render the
   visualizer canvas correctly). New rules below scope to
   ``.ui-audio-recorder`` so legacy chat layouts keep working. */
.ui-audio-recorder {
  display: inline-flex;
  align-items: center;
  /* The canvas itself uses the existing .chat-voice-waveform rules
       (display: none until .is-active); we only define a primitive-
       scoped fallback for surfaces that don't include _chat.scss. */
}

.ui-audio-recorder--misconfigured {
  margin: 1rem 0;
}

.ui-audio-recorder__row {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
}

.ui-audio-recorder__button {
  position: relative;
  min-width: 3rem;
  transition: background-color 0.15s ease-in-out;
}

.ui-audio-recorder__button:focus-visible {
  outline: 2px solid var(--color-primary);
  outline-offset: 2px;
}

.ui-audio-recorder__timer {
  margin-left: 0.5rem;
  font-variant-numeric: tabular-nums;
  font-size: 0.875rem;
}

.ui-audio-recorder__waveform {
  display: none;
  width: 120px;
  height: 24px;
  vertical-align: middle;
}

.ui-audio-recorder__waveform.is-active {
  display: inline-block;
}

.ui-audio-recorder__status {
  padding: 0.25rem 0;
  font-size: 0.875rem;
  color: var(--text-muted);
}

.ui-audio-recorder__status:empty {
  padding: 0;
  min-height: 0;
  overflow: hidden;
}

/* Mobile breakpoint — recorder row stacks. */
@media (max-width: 480px) {
  .ui-audio-recorder__row {
    flex-wrap: wrap;
  }
  .ui-audio-recorder__waveform {
    width: 100%;
    min-width: 0;
  }
}

/* ===========================================
   Badges (status / label pills)
   Use Bulma .tag is-success/warning/danger/info/light. No Bootstrap .badge.
   =========================================== */
/* Bulma .tag used as status (Write, Read, DNS OK, etc.) – filled-bg badges
 * (IDEA-197): semantic bg-solid + darkened pill-fg text + 6px radius. Replaces
 * the outline-only rendering (low-contrast on dark; ellipsis-clipping at
 * narrow widths). .tag.is-light keeps its pre-existing chrome below. */
.tag.is-success,
.tag.is-warning,
.tag.is-danger,
.tag.is-info {
  border: 0;
  border-radius: var(--border-radius-md);
  font-size: 0.75rem;
  font-weight: 500;
  padding: 2px 7px;
  white-space: nowrap;
  cursor: default;
}

.tag.is-success {
  color: var(--color-text-success);
  background-color: var(--color-background-success);
}

.tag.is-warning {
  color: var(--color-text-warning);
  background-color: var(--color-background-warning);
}

.tag.is-danger {
  color: var(--color-text-danger);
  background-color: var(--color-background-danger);
}

.tag.is-info {
  color: var(--color-text-info);
  background-color: var(--color-background-info);
}

.tag.is-light {
  border-radius: 9999px;
  font-weight: 500;
  cursor: default;
  border: 1px solid var(--border-secondary);
  color: var(--text-secondary);
  background-color: var(--bg-tertiary);
}

.dark .tag.is-light {
  border-color: var(--border-primary);
  color: var(--text-muted);
  background-color: var(--bg-secondary);
}

/* Links inside pills use pill color (GH #170 – no white links in light theme) */
.tag a,
.tag-pill-tag a,
.tag-pill-category a {
  color: inherit;
}

/* Unified category/tag pills: outline style, full path in category, tag icon in tag – same in list and detail views */
/* Each pill is the scrollable container: max-width 80vw, overflow-x auto. Internals are inline (no flex) for performance with many badges. */
.tag-pill-category,
.tag-pill-tag {
  border-radius: 9999px;
  font-weight: 500;
  cursor: default;
  padding: 0.125rem 0.5rem;
  /* Light theme: use darkened --pill-color-fg when set (GH #170); dark theme uses --pill-color */
  border: 1px solid var(--pill-color-fg, var(--pill-color, var(--border-secondary)));
  background-color: transparent;
  color: var(--pill-color-fg, var(--pill-color, var(--text-secondary)));
  display: inline-block;
  max-width: 80vw;
  min-width: 0;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  white-space: nowrap;
  /* Dark theme: use original --pill-color (not darkened -fg) so pills stay readable and keep hue */
}

.tag-pill-category .icon.is-small,
.tag-pill-tag .icon.is-small {
  display: inline-block;
  vertical-align: middle;
  margin-left: 0 !important;
  margin-right: 0 !important;
  margin-inline-start: 0 !important;
  margin-inline-end: 0 !important;
  opacity: 0.9;
}

.dark .tag-pill-category, [data-theme='dark'] .tag-pill-category, .dark .tag-pill-tag, [data-theme='dark'] .tag-pill-tag {
  border-color: var(--pill-color, var(--border-primary));
  color: var(--pill-color, var(--text-muted));
}

/* ===========================================
   Category tree (KB: nested categories, root indicator, expand toggle)
   Used by teisutis_kb partials + category-tree.js (adds .tree-toggle).
   =========================================== */
/* 20px - node indent and connector width */
/* 8px - spacing between icon/name/actions */
.category-tree {
  position: relative;
}

.category-node {
  position: relative;
  margin-left: 1.25rem;
}

.category-node::before {
  content: '';
  position: absolute;
  top: 0;
  left: -1.25rem;
  width: 1.25rem;
  height: 100%;
  border-left: 1px solid var(--border-primary);
  border-bottom: 1px solid var(--border-primary);
}

.category-content {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.5rem;
  /* spacing between name, description, actions (gh#154, gh#155) */
  padding: 0.5rem 0.75rem;
  margin-bottom: 0.25rem;
  background: var(--bg-primary);
  border: 1px solid var(--border-primary);
  border-radius: 0.25rem;
  transition: all 0.2s;
}

.category-content:hover {
  background: var(--bg-secondary);
  border-color: var(--border-secondary);
}

.category-content:hover .category-actions {
  opacity: 1;
}

.category-inactive .category-content {
  background-color: rgba(162, 162, 162, 0.2);
  opacity: 0.7;
}

.category-icon {
  width: 1rem;
  text-align: center;
  font-size: 0.875rem;
}

.category-name {
  flex: 1;
  min-width: 0;
  font-weight: 500;
}

.category-description {
  flex-basis: 100%;
  order: 1;
  /* render below name/actions row (gh#154, gh#155) */
}

.category-actions {
  order: 0;
  /* keep on same row as name, aligned right via gap */
  opacity: 0;
  transition: opacity 0.2s;
}

/* Mobile: avoid accidental taps on hidden buttons — move actions to own row, always visible */
@media screen and (max-width: 768px) {
  .category-actions {
    flex-basis: 100%;
    order: 2;
    /* below name row (0) and description (1) */
    opacity: 1;
    margin-top: 0.5rem;
    padding-top: 0.375rem;
    border-top: 1px solid var(--border-light);
  }
}

.tree-toggle {
  cursor: pointer;
  color: var(--text-muted);
  margin-right: 0.5rem;
  padding: 0.25rem;
  border-radius: 3px;
  transition: all 0.2s;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 1.25rem;
  min-height: 1.25rem;
}

.tree-toggle:hover {
  color: var(--color-primary);
  background: var(--bg-tertiary);
}

.root-level-indicator {
  position: relative;
  margin-bottom: 0.5rem;
  padding: 0.75rem;
  border: 2px solid var(--border-secondary);
  border-radius: 0.25rem;
  background: var(--bg-tertiary);
  color: var(--text-muted);
  text-align: center;
  min-height: 2.5rem;
  display: flex;
  align-items: center;
  justify-content: center;
}

.root-level-content {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.875rem;
  font-weight: 500;
}

.root-level-content i {
  font-size: 1rem;
}

/* ===========================================
   Entity colors (Org / Scope / Property accents)
   =========================================== */
/* Scope left, property right: Teisutis visual convention.
   See docs/reference/entity_color_convention.md */
/* Article/event cards, boxes: left = scope, right = property */
.scope-color-border {
  border-left: 3px solid transparent;
  border-right: 3px solid transparent;
}

/* Table rows: left = scope (first cell), right = property (last cell) */
.conversation-list-table tr.scope-color-border td:first-child {
  border-left: 3px solid var(--scope-color, transparent);
}

.conversation-list-table tr.scope-color-border td:last-child {
  border-right: 3px solid var(--property-color, transparent);
}

/* Entity-colored select: color as left border on the select box itself */
.select-with-color {
  --entity-accent-color: transparent;
}

.select-with-color .select.select--entity-color {
  border-left: 3px solid var(--entity-accent-color);
  border-radius: var(--bulma-control-radius, 4px);
}

/* IDEA-156 — vertical workspace filter: scope/property selects (compact
   ``.select-with-color``) go full-width to match the category select + search
   input. The shared compact partial omits ``is-fullwidth`` (correct for the
   legacy horizontal layout); restore it scoped to the workspace forms only.

   IDEA-145 (amends IDEA-156): consolidated onto ONE shared base class
   ``.shell-filters-workspace`` instead of the divergent per-surface list
   (``article-filters-workspace`` … ``chat-filters-workspace``). The
   per-surface class names are JS hooks (tag-filters.js) + form ids and stay
   on the markup; this rule now keys off the shared base every workspace
   filter form ALSO carries — so a new shell surface (dashboard, future
   entities) inherits full-width selects by adding the base class, never by
   re-implementing the rule. Mirrors the ``neutralize-card-table-bleed``
   shared-mixin precedent from the mobile-table fix (commit 863584e3). */
.shell-filters-workspace .select-with-color,
.shell-filters-workspace .select-with-color .select,
.shell-filters-workspace .select-with-color select {
  width: 100%;
  max-width: 100%;
}

.entity-color-dot {
  display: inline-block;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  flex-shrink: 0;
  border: 1px solid var(--border-secondary);
}

/* Article/event detail sidebar: Property/Scope info items with color accent */
.entity-info-item {
  border-left: 3px solid var(--entity-color, transparent);
  padding-left: 0.5rem;
  margin-bottom: 0.5rem;
}

/* Org detail tables: left color accent on property/scope rows */
.entity-color-row .entity-color-cell {
  border-left: 3px solid var(--entity-row-color, transparent);
  padding-left: calc(0.75em - 3px);
}

/* Permissions table: scope column headers with colored bottom bar.
   Inset shadow stays visible when header is sticky on scroll. */
.scope-color-header {
  box-shadow: 0 2px 4px var(--shadow-color), inset 0 -3px 0 0 var(--scope-color, transparent) !important;
}

/* IDEA-123 — TipTap WYSIWYG editor surface.
 *
 * The host div replaces the textarea visually while WYSIWYG mode is
 * active; flipping into source mode reveals the underlying textarea
 * again. Style both with the same Bulma-style border + focus ring so the
 * user sees the same field shape regardless of mode.
 *
 * Selectors mirror `.input, .textarea, .select select` in
 * `components/_forms.scss`.
 */
.tiptap-host {
  background-color: var(--bg-primary);
  color: var(--text-primary);
  border: 1px solid var(--border-primary);
  border-radius: 4px;
  padding: 0.5rem 0.75rem;
  min-height: 4rem;
  font-size: 1rem;
  line-height: 1.5;
}

.tiptap-host:focus-within {
  border-color: var(--color-primary);
  box-shadow: 0 0 0 2px rgba(124, 58, 237, 0.15);
}

.dark .tiptap-host {
  background-color: var(--bg-primary);
  border-color: var(--border-primary);
  color-scheme: dark;
}

.dark .tiptap-host:focus-within {
  border-color: var(--color-secondary);
  box-shadow: 0 0 0 2px rgba(124, 58, 237, 0.25);
}

.tiptap-host .tiptap-content {
  outline: none;
  min-height: 4rem;
  /* The contentEditable inherits the host's typography; reset Bulma's
   * `.content` indent on top-level paragraphs to match the prior
   * textarea baseline. */
}

.tiptap-host .tiptap-content p {
  margin-bottom: 0.75em;
}

.tiptap-host .tiptap-content p:last-child {
  margin-bottom: 0;
}

.tiptap-host .tiptap-content img {
  max-width: 100%;
  height: auto;
}

.tiptap-host .tiptap-content pre {
  background-color: var(--bg-secondary);
  color: var(--text-primary);
  padding: 0.75rem 1rem;
  border-radius: 4px;
  overflow-x: auto;
}

.tiptap-host .tiptap-content code {
  background-color: var(--bg-secondary);
  color: var(--text-primary);
  padding: 0.1em 0.35em;
  border-radius: 3px;
  font-size: 0.9em;
}

.tiptap-host .tiptap-content blockquote {
  border-left: 3px solid var(--border-primary);
  padding-left: 0.75rem;
  color: var(--text-secondary);
}

.tiptap-toolbar {
  /* Toolbar lives just above the editor host; remove the bottom margin
   * Bulma's `.buttons` ships so the toolbar visually attaches to the
   * field below. */
}

.tiptap-toolbar.buttons {
  margin-bottom: 0.25rem;
}

.tiptap-hint {
  /* Inline hint that pairs with the source-toggle button. Slightly
   * de-emphasised so it doesn't compete with the field label. */
  margin-top: 0;
  margin-bottom: 0.5rem;
}

/* ===========================================
   Mobile bottom-tab navigation (IDEA-143)
   ===========================================
   See web/teisutis_ui/templates/cotton/mobile_bottom_nav.html for
   the markup contract. Mobile-only (≤768px); above the breakpoint
   the element is fully hidden via ``display: none``.

   Layout: fixed-bottom row of 5 equal-width slots (4 primary +
   "More"). Honours ``env(safe-area-inset-bottom)`` to clear the
   home indicator on notched iPhones.

   Slide-down hide animation mirrors the top-nav ``.navbar--hidden``
   pattern (negative ``translateY``); bottom variant uses
   ``translateY(100%)``. Toggled by ``navbar-scroll.js`` shell-aware
   branch (IDEA-143 Phase 4).
   =========================================== */
.shell-mobile-nav {
  display: none;
}

@media screen and (max-width: 768px) {
  .shell-mobile-nav {
    display: flex;
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    z-index: 30;
    background-color: var(--bg-secondary);
    border-top: 1px solid var(--border-secondary);
    padding-bottom: env(safe-area-inset-bottom, 0px);
    transition: transform 0.2s ease-out;
  }
  .shell-mobile-nav--hidden {
    transform: translateY(100%);
  }
}

.shell-mobile-nav__item {
  flex: 1 1 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.125rem;
  padding: 0.4rem 0.25rem;
  min-height: 56px;
  color: var(--text-secondary);
  background: none;
  border: none;
  text-decoration: none;
  cursor: pointer;
  font: inherit;
  text-align: center;
}

.shell-mobile-nav__item:hover, .shell-mobile-nav__item:focus-visible {
  color: var(--text-primary);
  background-color: var(--bg-tertiary);
}

.shell-mobile-nav__item--active, .shell-mobile-nav__item--more-active {
  color: var(--color-brand);
}

.shell-mobile-nav__item-icon {
  font-size: 1.1rem;
  line-height: 1;
}

.shell-mobile-nav__item-label {
  font-size: 0.7rem;
  line-height: 1.1;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
}

/* IDEA-157: content clearance for base_public (lite-chrome) pages. In the full
   shell the 56px bottom-tab reservation lives on .shell-center (_shell.scss);
   base_public pages render base_minimal's `.main` instead and have no
   .shell-center, so without this the fixed bar covers the last ~56px of content
   on mobile. The reservation lives on `body` (NOT `.main`) because the common
   ancestor of every in-flow surface a base_public page can render is the body:
   `landing.html` renders its marketing footer in `{% block footer %}`, which
   base_minimal places AFTER `</main>` (outside `.main`) — padding only `.main`
   would leave that footer under the bar (bugbot review 4443903442 #1). The
   fixed bar is out of flow, so body padding pushes main + footer up without
   moving the bar. Keyed off the bar's DOM presence via :has() so it applies
   exactly when base_public emits the bottom-tab (gated on
   `mobile_bottom_nav_items`) and never on bare base_minimal or in the shell.

   navbar-scroll.js slides the bar away on scroll-down (`shell-mobile-nav--hidden`)
   and stamps `body.navbar-is-hidden`; the shell reclaims its 56px via
   `_shell.scss:394` (`body.navbar-is-hidden .shell-center`). Mirror that here so
   the body padding glides back to 0 in lockstep with the bar's slide — otherwise
   a blank 56px strip lingers below the content when the bar is hidden (bugbot
   review 4443903442 #2). Transition matches the bar's own 0.2s translateY slide.

   SCOPE: `:not(:has(.shell-center))` restricts this to LITE-CHROME pages only.
   The full shell (`shell.html`) already reserves the 56px on `.shell-center`
   (_shell.scss), and it ALSO renders `.shell-mobile-nav`, so a bare
   `body:has(.shell-mobile-nav)` would stack a SECOND body reservation on top of
   the shell's — double clearance on authed mobile shell pages (bugbot review
   4443931618). The shell has `.shell-center`; base_public / base_minimal have
   `.main` and no `.shell-center` — so the negation applies the body reservation
   exactly on the lite-chrome surfaces that lack their own and never on the shell.

   NOTE: the 56px must match `.shell-mobile-nav__item` min-height above — a shared
   `$mobile-bottom-nav-height` SCSS var is the proper DRY fix (also covers
   _shell.scss / _shell_section_nav.scss / _file_manager.scss which hardcode it)
   → /compound candidate. */
@media screen and (max-width: 768px) {
  body:has(.shell-mobile-nav):not(:has(.shell-center)) {
    padding-bottom: calc(56px + env(safe-area-inset-bottom, 0px));
    transition: padding-bottom 0.2s ease-out;
  }
  body.navbar-is-hidden:has(.shell-mobile-nav):not(:has(.shell-center)) {
    padding-bottom: env(safe-area-inset-bottom, 0px);
  }
}

/* ===========================================
   Mobile "More" bottom sheet (IDEA-143 R17)
   ===========================================
   See web/teisutis_ui/templates/cotton/mobile_more_sheet.html for
   the markup contract. Mobile-only (≤768px); above the breakpoint
   the wrapper is fully hidden via ``display: none``.

   Layout: backdrop + bottom-anchored sliding panel. The wrapper
   itself is a fixed-position container that tap-dismisses through
   its backdrop child; the panel slides up from below via
   translateY. Slide animation matches the drawer's 0.18s ease-out.
   =========================================== */
.shell-mobile-more-sheet {
  display: none;
}

@media screen and (max-width: 768px) {
  .shell-mobile-more-sheet {
    display: block;
    position: fixed;
    inset: 0;
    z-index: 50;
    pointer-events: none;
    /* Backdrop is interactive only when the sheet is open; the
       outer wrapper otherwise lets clicks fall through to the
       page underneath (matching ``x-cloak`` semantics). */
  }
  .shell-mobile-more-sheet--open {
    pointer-events: auto;
  }
  .shell-mobile-more-sheet--open .shell-mobile-more-sheet__backdrop {
    opacity: 1;
    pointer-events: auto;
  }
  .shell-mobile-more-sheet--open .shell-mobile-more-sheet__panel {
    transform: translateY(0);
  }
}

.shell-mobile-more-sheet__backdrop {
  position: fixed;
  inset: 0;
  background-color: rgba(0, 0, 0, 0.4);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.18s ease-out;
}

.shell-mobile-more-sheet__panel {
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  max-height: 70vh;
  overflow-y: auto;
  background-color: var(--bg-secondary);
  border-top: 1px solid var(--border-secondary);
  border-top-left-radius: 0.75rem;
  border-top-right-radius: 0.75rem;
  box-shadow: 0 -8px 24px rgba(0, 0, 0, 0.16);
  padding: 0.75rem 0.5rem calc(0.75rem + env(safe-area-inset-bottom, 0px));
  transform: translateY(100%);
  transition: transform 0.18s ease-out;
}

.shell-mobile-more-sheet__theme, .shell-mobile-more-sheet__lang {
  /* Both partials wrap their interactive widget in ``.navbar-item``;
       the More sheet is not a navbar context, so neutralise the
       navbar-item-specific spacing. Theme toggle and language picker
       share the slot styling — both render full-width inside the
       sheet panel. */
  display: flex;
  justify-content: center;
  padding: 0.25rem 0.5rem;
}

.shell-mobile-more-sheet__theme .navbar-item, .shell-mobile-more-sheet__lang .navbar-item {
  width: 100%;
  padding: 0;
}

.shell-mobile-more-sheet__theme .select,
.shell-mobile-more-sheet__theme select, .shell-mobile-more-sheet__lang .select,
.shell-mobile-more-sheet__lang select {
  width: 100%;
}

.shell-mobile-more-sheet__theme {
  /* Theme toggle's button is a ``button.is-ghost`` icon-only
       affordance; centre + give it a touch-friendly minimum
       footprint inside the sheet. */
}

.shell-mobile-more-sheet__theme .button.is-ghost {
  width: 100%;
  justify-content: center;
  min-height: 2.5rem;
}

.shell-mobile-more-sheet__divider {
  height: 1px;
  margin: 0.5rem 0.25rem;
  background-color: var(--border-secondary);
}

.shell-mobile-more-sheet__list {
  list-style: none;
  margin: 0;
  padding: 0;
}

.shell-mobile-more-sheet__item {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.75rem 0.75rem;
  color: var(--text-secondary);
  text-decoration: none;
  border-radius: 0.375rem;
}

.shell-mobile-more-sheet__item:hover, .shell-mobile-more-sheet__item:focus-visible {
  color: var(--text-primary);
  background-color: var(--bg-tertiary);
}

.shell-mobile-more-sheet__item--active {
  color: var(--color-brand);
}

.shell-mobile-more-sheet__item-icon {
  width: 1.25rem;
  text-align: center;
  font-size: 1rem;
}

.shell-mobile-more-sheet__item-label {
  flex: 1 1 auto;
  font-size: 0.95rem;
}

/* ===========================================
   Org pill — tenant chip + switcher (IDEA-143 R18)
   ===========================================
   Cross-viewport. Sits next to the brand link in the top
   ``<c-nav-bar>``. Two variants:

   * Static (single-org user): bordered pill with icon + name.
   * Switcher (multi-org user): same pill body wrapped in a
     ``<button>`` with chev affordance + inline dropdown menu.

   Visual lineage: docs/artefacts/by-topic/ux-overhaul/2026-04-30-home-demo-v2.html
   § TOP BAR. Switcher amendment per user direction 2026-05-06.

   Mobile (≤768px): truncate the org name with ellipsis to keep
   the right-cluster from being pushed off-screen on narrow phones.
   The full name remains accessible via the ``title`` tooltip /
   long-press.
   =========================================== */
.shell-nav__org-pill {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.25rem 0.625rem;
  margin: 0 0.5rem;
  border: 1px solid var(--border-secondary);
  border-radius: 0.375rem;
  font-size: 0.78rem;
  color: var(--text-secondary);
  background-color: var(--bg-secondary);
  position: relative;
  /* Switcher variant carries an inner <button>; reset the default
     button chrome so the pill body matches the static variant. */
  /* Reserve a fixed-width column for the checkmark whether the
     entry is current or not — keeps every menu item visually
     left-aligned on the org name. */
  /* Mobile (≤768px): truncate the visible org name aggressively
     so the right cluster (user-menu, theme-toggle) doesn't get
     pushed off-screen. The dropdown menu width is unchanged so
     the full name remains visible there for switcher users. */
}

.shell-nav__org-pill--switcher {
  padding: 0;
  border: none;
  background: transparent;
}

.shell-nav__org-pill__trigger {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.25rem 0.625rem;
  border: 1px solid var(--border-secondary);
  border-radius: 0.375rem;
  background-color: var(--bg-secondary);
  color: var(--text-secondary);
  font: inherit;
  cursor: pointer;
}

.shell-nav__org-pill__trigger:hover, .shell-nav__org-pill__trigger:focus-visible {
  color: var(--text-primary);
  background-color: var(--bg-tertiary);
}

.shell-nav__org-pill__icon {
  color: var(--color-brand);
}

.shell-nav__org-pill__name {
  font-weight: 500;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 16rem;
}

.shell-nav__org-pill__chev {
  font-size: 0.65rem;
  color: var(--text-muted, var(--text-secondary));
  margin-left: 0.125rem;
}

.shell-nav__org-pill__menu {
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  min-width: 14rem;
  max-width: 22rem;
  padding: 0.25rem;
  background-color: var(--bg-secondary);
  border: 1px solid var(--border-secondary);
  border-radius: 0.375rem;
  box-shadow: 0 8px 16px rgba(0, 0, 0, 0.16);
  z-index: 31;
  display: flex;
  flex-direction: column;
  gap: 0.125rem;
}

.shell-nav__org-pill__menu-item {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.5rem 0.625rem;
  color: var(--text-secondary);
  text-decoration: none;
  border-radius: 0.25rem;
  font-size: 0.85rem;
}

.shell-nav__org-pill__menu-item:hover, .shell-nav__org-pill__menu-item:focus-visible {
  color: var(--text-primary);
  background-color: var(--bg-tertiary);
}

.shell-nav__org-pill__menu-item--current {
  cursor: default;
  color: var(--text-primary);
  font-weight: 500;
}

.shell-nav__org-pill__menu-item--disabled {
  cursor: not-allowed;
  opacity: 0.6;
}

.shell-nav__org-pill__menu-check {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1rem;
  color: var(--color-brand);
}

.shell-nav__org-pill__menu-label {
  flex: 1 1 auto;
  word-break: break-word;
}

@media screen and (max-width: 768px) {
  .shell-nav__org-pill {
    margin: 0 0.25rem;
  }
  .shell-nav__org-pill .shell-nav__org-pill__name {
    max-width: 8rem;
  }
}

/* ===========================================
   Org-management dashboard surface (IDEA-150)
   ===========================================
   Dashboard reframe (inverted shell layout): the org NAVIGATOR lives in the
   workspace left drawer, the selected org's DASHBOARD occupies the centre
   (a stack of section cards), and drill-downs / create-edit / per-user-perm
   editors ride the preview drawer.

   Functional + clean — no heavy theming; leans on the existing card +
   table primitives. Scoped under the surface roots
   (``[data-org-navigator]`` / ``[data-org-dashboard]``) so it can't leak
   into other shells.
   =========================================== */
/* --- Workspace: navigator list ------------------------------------ */
.org-workspace-actions {
  /* "New org" sits above the navigator list (superuser only). */
  margin-bottom: 0.75rem;
}

.org-navigator-search {
  margin-bottom: 0.75rem;
}

[data-org-navigator] .org-navigator-list {
  /* Reset Bulma menu-list spacing for the drawer-width vertical list. */
  margin: 0;
}

[data-org-navigator] .org-navigator-item {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.5rem 0.75rem;
  border-radius: 0.375rem;
  color: var(--text-secondary);
  text-decoration: none;
  font-size: 0.9rem;
  line-height: 1.3;
  /* Selected/VIEWED org — the one whose dashboard fills the centre
       (Alpine ``active`` follows clicks; seeded from the viewed pk). NOT the
       request tenant — that's ``[data-org-current]`` + the ● marker below. */
  /* Current request-tenant marker (the org you're operating under) —
       distinct from the active/selected highlight. Subtle accent dot. */
}

[data-org-navigator] .org-navigator-item:hover, [data-org-navigator] .org-navigator-item:focus-visible {
  color: var(--text-primary);
  background-color: var(--bg-tertiary);
}

[data-org-navigator] .org-navigator-item.is-active {
  color: var(--text-primary);
  font-weight: 600;
  background-color: var(--bg-tertiary);
}

[data-org-navigator] .org-navigator-item__name {
  flex: 1 1 auto;
  min-width: 0;
  word-break: break-word;
}

[data-org-navigator] .org-navigator-item__current {
  flex: 0 0 auto;
  color: var(--accent, var(--link, #3273dc));
  font-size: 0.6rem;
  line-height: 1;
}

/* --- Centre: dashboard section-card stack ------------------------- */
[data-org-dashboard] {
  /* Each re-housed section is a card; keep the rhythm even when a
     section render fn returns an empty string (e.g. embed-api for a
     non-admin) — the flex ``gap`` collapses around empty nodes. */
}

[data-org-dashboard] .org-dashboard-sections {
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
  margin-top: 1rem;
}

[data-org-dashboard] .card[data-org-section],
[data-org-dashboard] [data-org-section] > .card {
  margin-bottom: 0;
}

/* IDEA-195 follow-on: tighten section cards on mobile so wide content
   (tables, button rows) doesn't appear to "explode out" of the card.
   Bulma's default ``.card-content { padding: 1.5rem }`` eats 3rem
   horizontal on a 320-425px viewport, which forces tables and
   multi-column flex rows to either shrink illegibly or visibly burst
   past the card boundary. User steer 2026-05-28.

   Scoped under ``[data-org-dashboard]`` so the change is local to the
   org-management surface — other shell surfaces (articles / events /
   faq) keep Bulma defaults. Padding-only — no margin change to the
   cards themselves (the surrounding ``.org-dashboard-sections`` gap
   handles inter-card breathing room). */
@media screen and (max-width: 768px) {
  [data-org-dashboard] {
    /* Section-card header rows that pack an input + multiple action
       buttons (e.g. domains card: "Add domain" form + "Refresh status"
       button) cram into a flex row by default. At sub-375px viewports
       the row can't fit, so children shrink and their internal text
       wraps mid-button instead of the whole button moving to a new
       line. Force the row to wrap and prevent button shrinkage —
       layout cleanly stacks rows when crowded. User steer 2026-05-28.
       Scoped to ``.is-flex`` inside ``.card-content`` so we don't
       touch unrelated rows. Buttons retain their natural width via
       ``flex-shrink: 0``. */
    /* Zero horizontal padding on mobile so wide content (tables,
       wrapping button rows) uses the full card width and never
       visually escapes the card boundary. Vertical padding kept so
       header/body breathing room is preserved. Tables retain their
       per-cell padding (Bulma default) so text doesn't kiss the card
       edge. Non-table content (text labels, paragraphs) becomes
       flush with the card edges — the deliberate trade-off per
       user steer 2026-05-28 (tables-fit-card wins over text-inset). */
  }
  [data-org-dashboard] .org-dashboard-sections {
    gap: 0.5rem;
  }
  [data-org-dashboard] [data-org-section] .card-content > .is-flex,
[data-org-dashboard] [data-domains-card] .card-content > .is-flex {
    flex-wrap: wrap;
  }
  [data-org-dashboard] [data-org-section] .card-content > .is-flex > .button,
[data-org-dashboard] [data-org-section] .card-content > .is-flex > form > .button,
[data-org-dashboard] [data-org-section] .card-content > .is-flex > .field.has-addons,
[data-org-dashboard] [data-domains-card] .card-content > .is-flex > .button,
[data-org-dashboard] [data-domains-card] .card-content > .is-flex > form > .button,
[data-org-dashboard] [data-domains-card] .card-content > .is-flex > .field.has-addons {
    flex-shrink: 0;
  }
  [data-org-dashboard] [data-org-section] {
    /* Neutralise the ``_cards.scss`` mobile table-bleed (shared mixin —
         IDEA-145 extraction; was an inline copy here). With this surface's
         horizontal padding zeroed above, the bleed's negative margins are
         uncompensated and the table extends PAST the card edge; the mixin
         resets it so the table fits exactly inside the card. */
    /* Table headers wrap with hyphens on mobile so multi-syllable
         Lithuanian column labels (e.g. "Pagrindinis" / "Atnaujinta")
         break at syllable boundaries with a hyphen instead of arbi-
         trary mid-word breaks ("Pagrindin"+"is", "Atnauj"+"a") that
         the inherited ``overflow-wrap: anywhere`` produces. Browser
         hyphenation dictionaries are language-aware via the
         ``<html lang="lt">`` attribute. User steer 2026-05-28. */
  }
  [data-org-dashboard] [data-org-section] .card-content,
[data-org-dashboard] [data-org-section] .card-header,
[data-org-dashboard] [data-org-section] .card-header-title {
    padding-left: 0;
    padding-right: 0;
  }
  [data-org-dashboard] [data-org-section] .card-content > .table-scroll-container,
[data-org-dashboard] [data-org-section] .card-content > div[style*="overflow-x"] {
    margin-left: 0;
    margin-right: 0;
    width: 100%;
  }
  [data-org-dashboard] [data-org-section] .table th {
    hyphens: auto;
    -webkit-hyphens: auto;
    -moz-hyphens: auto;
    -ms-hyphens: auto;
  }
}

/* IDEA-195 follow-on: billing section action-button spacing.

   The other org-section action buttons get their labels truncated to
   the first word by ``table-action-truncate.js`` — billing stays
   full-text but its action buttons render flush with no breathing room
   (user steer 2026-05-28). Adds a modest left margin between adjacent
   buttons in billing table cells + form action groups. Targets
   adjacent-sibling buttons (``.button + .button``) AND a form's
   action button following another button/control via the
   ``is-grouped`` field wrapper convention. */
[data-org-section="billing"] {
  /* Every button picks up a small bottom-margin so wrapping (mobile,
     narrow viewports where buttons stack instead of inlining) creates
     a clear y-gap between rows. Combined with the adjacent-sibling
     left-margin below, this covers BOTH the inline case AND the wrap
     case without depending on a specific parent class. */
  /* Cell-level inline x-gap: cancel-auto-renew etc. */
  /* IDEA-197 cosmetic follow-on 2026-05-28 (user steer): on narrow
   * viewports the adjacent-sibling margin-left bleeds when buttons wrap
   * to new lines — the 2nd button rendered 0.5rem indented from the
   * card's left edge while the 1st sat flush. Zero out left-margin in
   * mobile so wrapped buttons left-align uniformly; bottom-margin above
   * keeps the y-gap. */
  /* Form-group action buttons (Bulma .field.is-grouped) — apply the
     same gap to all ``.control`` siblings inside a grouped field so
     the action button doesn't kiss the preceding control. */
}

[data-org-section="billing"] .button {
  margin-bottom: 0.5rem;
}

[data-org-section="billing"] .button + .button {
  margin-left: 0.5rem;
}

@media screen and (max-width: 768px) {
  [data-org-section="billing"] .button + .button {
    margin-left: 0;
  }
}

[data-org-section="billing"] .field.is-grouped .control + .control {
  margin-left: 0.5rem;
}

/* ===========================================
   Shell section nav — chip strip (desktop) + burger sheet (mobile)
   (IDEA-195)
   ===========================================
   Two affordances rendered from the same cotton ``chips`` list:

   * ``.shell-section-nav`` — horizontal chip strip below the top
     navbar (desktop only). Sticky-to-body-flex via flex chain;
     hide-on-scroll via ``body.navbar-is-hidden``.
   * ``.shell-section-nav-mobile`` — burger trigger pinned above the
     mobile bottom-nav (mobile only). Tap unfolds a slide-up panel
     listing the same sections as a vertical menu (mirrors the
     ``<c-mobile-more-sheet>`` idiom from IDEA-143).

   Mobile placement is ABOVE the bottom-nav, NOT above the branding
   bar — user steer 2026-05-28 (revised from the original mobile-
   above-navbar capture once horizontal-strip placement at 320px
   proved unfeasible: chips overflow + label collapse left no usable
   surface).
*/
/* === Desktop horizontal chip strip ===================================
   Visible ≥769px; hidden on mobile via the breakpoint block at the
   bottom. */
.shell-section-nav {
  background-color: var(--bg-secondary);
  border-bottom: 1px solid var(--border-secondary);
  transition: transform 0.2s ease-out, max-height 0.2s ease-out;
  flex: 0 0 auto;
  z-index: 25;
  /* Mirror the canonical top-nav item style — see
       ``_nav_overflow.scss::.shell-nav__item`` + ``_navigation.scss::
       .navbar-item``. Default text-secondary, no bg, no pill; hover
       shifts to ``--bg-tertiary`` + text-primary; active uses the same
       bg with ``--color-brand`` text accent so it's distinguishable
       from hover WITHOUT a font-weight change (user steer 2026-05-28
       — bolding-on-active during scroll-spy shifts chip widths, which
       ripples through sibling chips and feels glitchy). Drops the
       prior pill shape (border-radius / always-on bg) so the strip
       reads as a top-nav-adjacent sub-row, not a band of pills. */
}

.shell-section-nav__chips {
  /* Top-nav-style horizontal row of button-shaped items. No
           explicit gap — each chip's padding provides spacing, matching
           the ``.shell-nav__items`` strip in the top navbar (no gap
           between adjacent ``.shell-nav__item`` elements, just inherent
           padding). */
  display: flex;
  flex-direction: row;
  align-items: stretch;
  margin: 0;
  padding: 0 0.5rem;
  list-style: none;
  overflow-x: auto;
  overflow-y: hidden;
  scrollbar-width: thin;
}

.shell-section-nav__chip-item {
  flex: 0 0 auto;
}

.shell-section-nav__chip {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.5rem 0.85rem;
  color: var(--text-secondary);
  text-decoration: none;
  font-size: 0.875rem;
  line-height: 1.2;
  white-space: nowrap;
  transition: background-color 0.15s ease-out, color 0.15s ease-out;
}

.shell-section-nav__chip:hover, .shell-section-nav__chip:focus-visible {
  color: var(--text-primary);
  background-color: var(--bg-tertiary);
}

.shell-section-nav__chip:focus-visible {
  outline: 2px solid var(--org-color, var(--link, #2563eb));
  outline-offset: -2px;
}

.shell-section-nav__chip.is-active {
  background-color: var(--bg-tertiary);
  color: var(--color-brand);
}

.shell-section-nav__chip-icon {
  /* Match top-nav icon rendering — no shrink, lets the icon size
           track font-size naturally. */
  flex: 0 0 auto;
}

/* Hide-on-scroll: mirror ``.navbar--hidden`` exactly so the chip strip
   slides up together with the navbar on viewports where navbar-scroll
   fires (desktop chip strip is always visible since navbar-scroll only
   hides on mobile, but the rule is here for symmetry — any future
   desktop-narrow scroll-hide picks it up automatically). */
body.navbar-is-hidden .shell-section-nav {
  transform: translateY(-100%);
  min-height: 0;
  max-height: 0;
  padding-top: 0;
  padding-bottom: 0;
  overflow: hidden;
}

/* === Mobile burger + slide-up panel =================================
   Hidden by default; only painted on ≤768px via the breakpoint block. */
.shell-section-nav-mobile {
  display: none;
}

/* Scroll-margin-top on the target section cards so the section heading
   isn't clipped under the chip strip when clicked. The ``.shell-center``
   scroll container reads this when ``scrollIntoView({ block: 'start' })``
   fires. */
[data-org-section] {
  scroll-margin-top: 0.75rem;
}

@media (max-width: 768px) {
  /* Hide the desktop horizontal strip entirely — burger affordance
       replaces it. */
  .shell-section-nav {
    display: none;
  }
  .shell-section-nav-mobile {
    display: block;
  }
  /* Trigger: fixed-bottom bar, just above the mobile bottom-nav.
       Bottom-nav is 56px tall + safe-area-inset-bottom; trigger sits
       directly above that.  Slide-down hide via the ``--hidden`` class
       toggled by ``navbar-scroll.js``'s ``setNavbarHidden`` (which also
       toggles ``.shell-mobile-nav--hidden`` — same lifecycle as the
       bottom-nav linked hide). */
  .shell-section-nav-mobile__trigger {
    position: fixed;
    left: 0;
    right: 0;
    bottom: calc(56px + env(safe-area-inset-bottom, 0px));
    z-index: 28;
    /* below bottom-nav (30) so panel can dim it */
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    min-height: 36px;
    padding: 0.4rem 1rem;
    background-color: var(--bg-secondary);
    border: none;
    border-top: 1px solid var(--border-secondary);
    color: var(--text-secondary);
    font: inherit;
    font-size: 0.875rem;
    font-weight: 500;
    cursor: pointer;
    text-decoration: none;
    transition: transform 0.2s ease-out, background-color 0.15s ease-out, color 0.15s ease-out;
  }
  .shell-section-nav-mobile__trigger:hover, .shell-section-nav-mobile__trigger:focus-visible {
    color: var(--text-primary);
    background-color: var(--bg-tertiary);
  }
  .shell-section-nav-mobile__trigger:focus-visible {
    outline: 2px solid var(--org-color, var(--link, #2563eb));
    outline-offset: -2px;
  }
  .shell-section-nav-mobile__trigger--open {
    color: var(--color-brand);
    background-color: var(--bg-tertiary);
  }
  /* Link the trigger's slide-down to the bottom-nav hide lifecycle
       so chrome moves cohesively when the user scrolls down. */
  body.navbar-is-hidden .shell-section-nav-mobile__trigger {
    /* trigger sits ABOVE bottom-nav; both slide down together —
           but trigger needs to travel further (its own height + bottom-
           nav height) so it doesn't peek above the screen edge while
           the bottom-nav vanishes. translateY(100%) is enough because
           it relocates the trigger box to fully below its own bottom
           position (which is bottom: 56px) — combined with the bottom-
           nav's own translateY(100%), nothing pokes through. */
    transform: translateY(calc(100% + 56px + env(safe-area-inset-bottom, 0px)));
  }
  /* Backdrop covers everything UNDER the bottom-nav cluster — gives
       the user a clear tap-to-dismiss target. */
  .shell-section-nav-mobile__backdrop {
    position: fixed;
    inset: 0;
    background-color: rgba(0, 0, 0, 0.4);
    z-index: 27;
    /* below trigger so the trigger stays tappable */
  }
  /* Slide-up panel sits ABOVE the trigger (which is above the bottom-
       nav). Vertical menu list mirroring ``<c-mobile-more-sheet>``. */
  .shell-section-nav-mobile__panel {
    position: fixed;
    left: 0;
    right: 0;
    /* trigger height + bottom-nav height + safe-area-inset */
    bottom: calc(36px + 56px + env(safe-area-inset-bottom, 0px));
    z-index: 29;
    /* above backdrop, below bottom-nav */
    max-height: 60vh;
    overflow-y: auto;
    background-color: var(--bg-secondary);
    border-top: 1px solid var(--border-secondary);
    box-shadow: 0 -4px 12px rgba(0, 0, 0, 0.15);
  }
  .shell-section-nav-mobile__list {
    list-style: none;
    margin: 0;
    padding: 0.25rem 0;
  }
  .shell-section-nav-mobile__item {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 0.75rem 1.25rem;
    color: var(--text-primary);
    font-size: 1rem;
    text-decoration: none;
    border-bottom: 1px solid var(--border-secondary);
    transition: background-color 0.15s ease-out;
    /* Mobile menu item active state — bg + brand-color text only;
           NO font-weight change (consistent with desktop chip — see
           desktop active state comment above). Even though the mobile
           menu is layout-stable when open, dropping the weight change
           keeps the two representations visually identical. */
  }
  .shell-section-nav-mobile__item:hover, .shell-section-nav-mobile__item:focus-visible {
    background-color: var(--bg-tertiary);
  }
  .shell-section-nav-mobile__item.is-active {
    background-color: var(--bg-tertiary);
    color: var(--color-brand);
  }
  .shell-section-nav-mobile__item-icon {
    font-size: 1rem;
    min-width: 1.5rem;
    text-align: center;
  }
  /* Reserve the burger trigger's 36px of bottom padding on
       ``.shell-center`` ONLY when the section-nav affordance is
       actually visible. ``shell-section-nav.js`` toggles
       ``body.has-active-section-nav`` to drive this — the cotton
       renders the burger element body-level (outside
       ``#shell-swap-target``) so it survives shell-nav swaps even
       on surfaces that don't supply ``surface_section_nav``; the JS
       hides it via ``style.display = none`` on those surfaces and
       also removes the body class, so this padding rule doesn't
       fire there. Without the body-class gate the inherited
       ``_shell.scss`` mobile rule (``padding-bottom: calc(56px +
       env(safe-area-inset-bottom, 0px))``) is double-padded by 36px
       on surfaces without the trigger (bugbot finding 3317363648).
       Bottom-nav 56px reservation continues to come from
       ``_shell.scss``. */
  body.has-active-section-nav .shell-center {
    padding-bottom: calc(56px + 36px + env(safe-area-inset-bottom, 0px));
  }
  /* x-transition fallbacks (in case Alpine transitions aren't smooth
       across these positions). Keep modest. */
  .shell-section-nav-mobile__panel--enter {
    animation: shell-section-nav-mobile-slide-up 0.18s ease-out;
  }
  .shell-section-nav-mobile__panel--leave {
    animation: shell-section-nav-mobile-slide-down 0.15s ease-in;
  }
}

@keyframes shell-section-nav-mobile-slide-up {
  from {
    transform: translateY(20%);
    opacity: 0;
  }
  to {
    transform: translateY(0);
    opacity: 1;
  }
}

@keyframes shell-section-nav-mobile-slide-down {
  from {
    transform: translateY(0);
    opacity: 1;
  }
  to {
    transform: translateY(20%);
    opacity: 0;
  }
}

/* ===========================================
   File manager — mobile sticky bulk-assign bar (IDEA-161)
   ===========================================
   On desktop the bulk-assign bar (``#file-bulk-bar``) lives in the workspace
   pane (left column). On mobile (≤768px) that pane is off-canvas behind the
   left edge-lip rail (IDEA-201 adjacent-pane model), so ticking a file
   produced NO visible confirmation/Assign affordance in the thumb zone — the
   action was hidden in a pane the user couldn't see (discoverability gap
   surfaced in IDEA-161 mobile review).

   Fix: pin the SAME bar (one ``#file-bulk-bar`` id covers both the free-mode
   picker AND the fixed-target ``_file_assign_banner`` variant) to a bottom
   sheet directly above the mobile bottom-nav, so the action surfaces where the
   selection happens. ``position: fixed`` lifts it out of the off-canvas pane's
   flow regardless of its DOM parent — no duplicate markup, no second form. The
   bar's existing ``x-show="$store.fileSelect.count > 0"`` (free mode) still
   gates visibility; the fixed-target banner stays persistent (target reminder +
   Done). Desktop layout is untouched.
   =========================================== */
@media screen and (max-width: 768px) {
  #file-bulk-bar {
    position: fixed;
    left: var(--shell-edge-gutter);
    right: var(--shell-edge-gutter);
    bottom: calc(56px + env(safe-area-inset-bottom, 0px));
    z-index: 31;
    margin-bottom: 0;
    max-height: 55vh;
    overflow-y: auto;
    border-radius: 8px;
    box-shadow: 0 -4px 16px rgba(0, 0, 0, 0.18);
  }
  #file-list {
    padding-bottom: 7rem;
  }
}

/* ===========================================
   Mobile/desktop overrides → distributed to components
   Uses @mixin mobile / @mixin desktop from _mixins.scss
   ===========================================
   Hero, Phase 1 base, breadcrumb, titles, dropdowns, table overflow,
   article list, attachment cards → components/_layout.scss
   Chat viewport, header, messages, input, badge, STT icon → components/_chat.scss
   Navbar padding/menu → components/_navigation.scss
   Level-right buttons, .buttons.is-compact → components/_buttons.scss
   Card, card-content, stats-grid, info-grid → components/_cards.scss
   =========================================== */
