/* ═══════════════════════════════════════════════════════════════
   CSS PRIMITIVES — Task 287
   Reusable building blocks for modals, forms, buttons, save bars.
   Pairs with views/primitives/modalShell.js and modules/saveBar.js.
   See docs/architecture/thinking/settings-ui-standard/design-system.md
   for the canonical recipes and migration cookbook.
   ═══════════════════════════════════════════════════════════════ */

/* Hides safety-net fallback when this file loads — paired with inline #cssFailedFallback block in index.html. */
#cssFailedFallback { display: none; }

/* ── Modal Shell ──────────────────────────────────────────────── */

.modal-shell {
  position: fixed;
  inset: 0;
  z-index: var(--z-modal);
  display: none;
  align-items: center;
  justify-content: center;
  background: rgba(15, 23, 42, 0.55);
  padding: var(--space-4);
}

.modal-shell.visible {
  display: flex;
  animation: modal-shell-fade-in var(--duration-base) var(--ease-standard);
}

/* Depth=2 modifier: source-order after .modal-shell wins the cascade tie
   at equal specificity (0,1,0 vs 0,1,0). Do not compound — see decisions.md. */
.modal-shell--stacked {
  z-index: var(--z-modal-stacked);
}

.modal-shell__panel {
  background: var(--bg-card);
  color: var(--text-primary);
  border-radius: var(--radius-lg);
  box-shadow: var(--elevation-4);
  width: min(960px, 100%);
  max-height: min(720px, 90vh);
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.modal-shell__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--space-3) var(--space-5);
  border-bottom: 1px solid var(--border);
  flex: 0 0 auto;
}

.modal-shell__title {
  margin: 0;
  font-size: var(--font-size-xl);
  font-weight: var(--font-weight-semibold);
  line-height: var(--line-height-tight);
  color: var(--text-primary);
}

.modal-shell__close {
  background: transparent;
  border: 0;
  width: 32px;
  height: 32px;
  border-radius: var(--radius-sm);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--text-secondary);
  cursor: pointer;
  transition: background var(--duration-fast) var(--ease-standard);
}

.modal-shell__close:hover {
  background: var(--bg-hover);
  color: var(--text-primary);
}

.modal-shell__body {
  flex: 1 1 auto;
  display: flex;
  min-height: 0;
  overflow: hidden;
}

.modal-shell__footer {
  flex: 0 0 auto;
  border-top: 1px solid var(--border);
  background: var(--bg-card);
}

/* ── Confirm Dialog (Task 294) ───────────────────────────────── */

.confirm-dialog__panel {
  width: min(440px, 100%);
  max-height: none;
}

.confirm-dialog__body {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding: var(--space-4) var(--space-6);
  color: var(--text-primary);
  font-size: var(--font-size-base);
  line-height: var(--line-height-normal);
}

.confirm-dialog__body p {
  margin: 0;
}

.confirm-dialog__error {
  color: var(--accent-red);
  font-size: var(--font-size-sm);
  min-height: 0;
}

.confirm-dialog__error:empty {
  display: none;
}

.confirm-dialog__footer {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-5);
}

/* ── Form Section ─────────────────────────────────────────────── */

.form-section {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  padding: var(--space-5) 0;
  border-bottom: 1px solid var(--border-subtle);
}

.form-section:last-of-type {
  border-bottom: 0;
}

.form-section__title {
  margin: 0;
  font-size: var(--font-size-md);
  font-weight: var(--font-weight-semibold);
  color: var(--text-primary);
}

.form-section__hint {
  margin: 0;
  font-size: var(--font-size-sm);
  color: var(--text-secondary);
  line-height: var(--line-height-normal);
}

.form-section__body {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}

/* ── Form Row ─────────────────────────────────────────────────── */

.form-row {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.form-row--split {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-4);
}

@media (max-width: 640px) {
  .form-row--split {
    grid-template-columns: 1fr;
  }
}

/* ── Modal form layout (shared, opt-in) ──────────────────────────
   Apply class="modal-shell__form" on a modal's <form> to lay out each
   .form-field as label-inline-with-input on the same row. Labels align
   in a fixed column and inputs are bounded so they don't sprawl across
   the panel. The error span wraps to a full row below the input. Use
   .form-field--block on a field to opt out (textareas etc). */

.modal-shell__form .form-field {
  flex-direction: row;
  align-items: center;
  gap: var(--space-3);
  flex-wrap: wrap;
}
.modal-shell__form .form-field__label {
  flex: 0 0 80px;
  text-align: right;
}
.modal-shell__form .form-field__control {
  /* basis:0 + grow:1 = fill remaining space alongside label.
     max-width caps the control so inputs don't sprawl in wide modals.
     basis:360 with shrink would wrap because flex-wrap evaluates
     hypothetical size (= basis) before shrinking. */
  flex: 1 1 0;
  max-width: 360px;
  min-width: 0;
}
.modal-shell__form .form-field__error {
  flex: 0 0 100%;
}
.modal-shell__form .form-field--block {
  flex-direction: column;
  align-items: stretch;
  gap: var(--space-1);
}
.modal-shell__form .form-field--block .form-field__label,
.modal-shell__form .form-field--block .form-field__control {
  flex: initial;
}

/* ── OAuth provider icon ──────────────────────────────────────────
   SVG logo placed inside an OAuth-flow button (Continue with Google,
   Connect with Microsoft, etc). Icon dimensions live on the SVG
   itself; this rule just stops the button's flex layout from
   shrinking the logo when the label text is long. The :has() rule
   widens the gap between icon and label vs the default .btn gap. */
.oauth-icon {
  flex-shrink: 0;
}
.btn:has(.oauth-icon) {
  gap: var(--space-3);
}

/* ── Section label ────────────────────────────────────────────────
   Small uppercase secondary heading. Use for non-form section
   headings ("Conversations", "Conflicts", etc). Owns its own
   vertical breathing room (margin top + bottom) so consumers
   don't need to add gap/margin to space the heading from its
   siblings. NOTE: in a flex parent with a `gap`, margins stack
   with the gap — override `margin: 0` on the label if that
   doubling is unwanted. */
.section-label {
  font-size: 12px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text-secondary);
  margin-top: var(--space-3);
  margin-bottom: var(--space-2);
}

/* ── Output Review Control (Task 411) ─────────────────────────── */

.output-review-control {
  position: relative;
  display: inline-grid;
  place-items: center;
  min-width: 96px;
  height: 28px;                            /* aligns to .btn-sm */
  padding: var(--space-1) var(--space-3);  /* aligns to .btn-sm */
  border: 1px solid transparent;           /* flat — no visible border (matches .btn box model) */
  border-radius: var(--radius-sm);         /* aligns to .btn */
  background: var(--bg-active);            /* flat, non-transparent default fill */
  color: var(--text-primary);
  font-family: var(--font-sans);
  font-size: var(--font-size-xs);          /* aligns to .btn-sm */
  font-weight: var(--font-weight-medium);  /* aligns to .btn */
  line-height: 1;
  white-space: nowrap;
  cursor: pointer;
  overflow: hidden;  /* clip the hover colour-wipe to the rounded shape */
  transition: background var(--duration-fast) var(--ease-standard);
}

/* Hover/focus sweeps a colour wipe left → right across the button so the whole
   button changes colour, not just the label cross-fade. The wipe reveals the
   TARGET action's colour (green=approve, blue/amber=revoke target), so the
   button visually becomes the next state — matching the label swap below.
   Gated to :not(:disabled) so the in-flight pending state stays inert. */
.output-review-control::before {
  content: '';
  position: absolute;
  inset: 0;
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform var(--duration-base) var(--ease-standard);
  pointer-events: none;
  z-index: 0;
}

.output-review-control[data-output-review-target-status="approved"]::before {
  background: var(--accent-green);
}
.output-review-control[data-output-review-target-status="user_draft"]::before {
  background: var(--accent-blue);
}
.output-review-control[data-output-review-target-status="ai_draft"]::before {
  background: var(--accent-amber);
}

.output-review-control:hover:not(:disabled)::before,
.output-review-control:focus-visible:not(:disabled)::before {
  transform: scaleX(1);
}

.output-review-control__current,
.output-review-control__target {
  grid-area: 1 / 1;
  position: relative;  /* sit above the ::before colour-wipe */
  z-index: 1;
  transition: opacity var(--duration-fast) ease;
}

.output-review-control__target {
  opacity: 0;
}

.output-review-control:hover:not(:disabled) .output-review-control__current,
.output-review-control:focus-visible:not(:disabled) .output-review-control__current {
  opacity: 0;
}

.output-review-control:hover:not(:disabled) .output-review-control__target,
.output-review-control:focus-visible:not(:disabled) .output-review-control__target {
  opacity: 1;
}

.output-review-control:focus-visible {
  outline: 2px solid var(--border-focus);
  outline-offset: 2px;
}

.output-review-control--disabled {
  cursor: not-allowed;
}

.output-review-control--ai-draft {
  background: var(--accent-amber);
  color: #ffffff;
}

.output-review-control--user-draft {
  background: var(--accent-blue);
  color: #ffffff;
}

.output-review-control--approved {
  background: var(--accent-green);
  color: #ffffff;
}

/* In-flight: the approve/revoke request is running. The schedule-clean approve
   re-renders and converts via Microsoft Graph, which can take several seconds —
   show a neutral, non-interactive button with a spinner so the click clearly
   registered. inline-flex overrides the base inline-grid label layering. */
.output-review-control--pending {
  display: inline-flex;
  gap: 6px;
  background: var(--bg-active);
  color: var(--text-secondary);
  cursor: progress;
}

@media (prefers-reduced-motion: reduce) {
  .output-review-control__current,
  .output-review-control__target,
  .output-review-control::before {
    transition: none;
  }
}

/* ── Step Progress Indicator (Task 414) ───────────────────────── */

.step-progress-indicator {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  gap: var(--space-1);
  color: var(--text-secondary);
  font-family: var(--font-sans);
  font-size: var(--font-size-xs);
  font-weight: var(--font-weight-medium);
  line-height: 1;
  white-space: nowrap;
}

.step-progress-indicator__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  line-height: 1;
}

.step-progress-indicator__label {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
}

.step-progress-indicator--header {
  min-width: 96px;
  max-width: 160px;
  height: 28px;
  padding: var(--space-1) var(--space-3);
  border-radius: var(--radius-sm);
  background: var(--bg-active);
}

.step-progress-indicator--rail {
  width: 18px;
  height: 18px;
  font-size: 12px;
}

.step-progress-indicator--pending {
  color: var(--text-secondary);
}

.step-progress-indicator--running {
  color: var(--accent-blue);
}

.step-progress-indicator--completed {
  color: var(--accent-green);
}

.step-progress-indicator--failed {
  color: var(--accent-red);
}

.step-progress-indicator--blocked {
  color: var(--text-secondary);
  opacity: 0.72;
}

.step-progress-indicator--header.step-progress-indicator--pending {
  background: var(--bg-hover);
}

.step-progress-indicator--header.step-progress-indicator--running {
  background: var(--accent-blue-bg);
}

.step-progress-indicator--header.step-progress-indicator--completed {
  background: var(--accent-green-bg);
}

.step-progress-indicator--header.step-progress-indicator--failed {
  background: var(--accent-red-bg);
}

.step-progress-indicator--header.step-progress-indicator--blocked {
  background: var(--bg-hover);
}

.step-progress-indicator .spinner-small {
  width: 12px;
  height: 12px;
  min-width: 12px;
  min-height: 12px;
  border-width: 1.5px;
}

@media (prefers-reduced-motion: reduce) {
  .step-progress-indicator .spinner-small {
    animation: none !important;
  }
}

/* When .section-label is a direct child of .form-section (a flex column
   with its own gap), drop its own margins — the parent's gap handles
   sibling spacing. Without this, the label's margins compound with the
   gap and the section's top padding (see design-system.md §2 NOTE). */
.form-section > .section-label {
  margin-top: 0;
  margin-bottom: 0;
}

/* ── Form Field ───────────────────────────────────────────────── */

.form-field {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}

/* Defensive: adjacent .form-field children of a bare <form> get vertical
   gap. Containers like .form-section__body / .form-row--split already own
   their own gap and stay direct-child-scoped, so this rule doesn't double up.
   Migrated modal forms that own a flex/grid gap on the <form> itself MUST
   opt out via the neutralizer block below — otherwise gap + margin compound. */
form > .form-field + .form-field {
  margin-top: var(--space-4);
}

/* Neutralizer for forms that already provide vertical gap via display:flex
   + gap on the form element. When migrating a new modal that owns its form
   layout (matching the .participant-modal__form / .client-detail-modal__form
   / .client-editor__form precedent), add the form class here. */
.participant-modal__form > .form-field + .form-field,
.client-detail-modal__form > .form-field + .form-field,
.client-editor__form > .form-field + .form-field,
.profile-form > .form-field + .form-field {
  margin-top: 0;
}

.form-field__label {
  font-size: var(--font-size-sm);
  font-weight: var(--font-weight-medium);
  color: var(--text-primary);
}

.form-field__control {
  display: flex;
  align-items: stretch;
  gap: var(--space-2);
}

.form-field__control--with-action {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: var(--space-2);
}

.form-field__control input,
.form-field__control select,
.form-field__control textarea {
  width: 100%;
  /* 2026-04-27 tightening pass: literal 6px / 10px / 1.35 are off-token by
     design — see §2 rationale at the end of design-system.md. */
  padding: 6px 10px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--bg-card);
  color: var(--text-primary);
  font-family: var(--font-sans);
  font-size: var(--font-size-base);
  line-height: 1.35;
  transition: border-color var(--duration-fast) var(--ease-standard),
              box-shadow var(--duration-fast) var(--ease-standard);
}

.form-field__control input:focus,
.form-field__control select:focus,
.form-field__control textarea:focus {
  outline: none;
  border-color: var(--border-focus);
  box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.15);
}

.form-field__hint {
  font-size: var(--font-size-xs);
  color: var(--text-secondary);
  line-height: var(--line-height-normal);
}

.form-field--error .form-field__control input,
.form-field--error .form-field__control select,
.form-field--error .form-field__control textarea,
.form-field--error input,
.form-field--error select,
.form-field--error textarea,
.form-field--error [contenteditable="true"] {
  border-color: var(--accent-red);
  box-shadow: 0 0 0 3px rgba(239, 68, 68, 0.15);
}

[data-field-error] {
  font-size: var(--font-size-xs);
  color: var(--accent-red);
  line-height: var(--line-height-normal);
  min-height: 0;
}

[data-field-error]:empty {
  display: none;
}

/* ── Toggle ───────────────────────────────────────────────────── */

.toggle {
  display: inline-flex;
  align-items: center;
  gap: var(--space-3);
  cursor: pointer;
  user-select: none;
}

.toggle__input {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  border: 0;
}

.toggle__track {
  position: relative;
  display: inline-block;
  width: 36px;
  height: 20px;
  border-radius: var(--radius-pill);
  background: var(--bg-active);
  transition: background var(--duration-base) var(--ease-standard);
  flex-shrink: 0;
}

.toggle__thumb {
  position: absolute;
  top: 2px;
  left: 2px;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: #ffffff;
  box-shadow: var(--elevation-1);
  transition: transform var(--duration-base) var(--ease-standard);
}

.toggle__input:checked + .toggle__track {
  background: var(--accent-blue);
}

.toggle__input:checked + .toggle__track .toggle__thumb {
  transform: translateX(16px);
}

.toggle__input:focus-visible + .toggle__track {
  box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.3);
}

.toggle__label {
  font-size: var(--font-size-sm);
  color: var(--text-primary);
}

/* ── Buttons ──────────────────────────────────────────────────── */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  border-radius: var(--radius-sm);
  font-family: var(--font-sans);
  font-weight: var(--font-weight-medium);
  cursor: pointer;
  border: 1px solid transparent;
  transition: background var(--duration-fast) var(--ease-standard),
              border-color var(--duration-fast) var(--ease-standard),
              color var(--duration-fast) var(--ease-standard);
}

.btn:disabled {
  cursor: not-allowed;
  opacity: 0.55;
}

.btn-sm {
  padding: var(--space-1) var(--space-3);
  font-size: var(--font-size-xs);
  height: 28px;
  gap: 6px;
}

.btn-sm svg {
  width: 14px;
  height: 14px;
}

.btn-md {
  padding: var(--space-2) var(--space-4);
  font-size: var(--font-size-sm);
  height: 36px;
}

.btn-lg {
  padding: var(--space-3) var(--space-5);
  font-size: var(--font-size-base);
  height: 44px;
}

/* ── Menu panel ─────────────────────────────────────────────────
   Shared dropdown-panel chrome. Visual standard set by the workflow
   rail's add-dropdown; consumed by .workflow-add-dropdown,
   .create-menu__dropdown, .notifications-dropdown, .profile-menu.
   Positioning, width, padding, scroll and z-index stay per-menu
   (context-dependent — rail vs chrome stacking contexts differ). */
.menu-panel {
  position: absolute;
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-md);
}

.btn-primary {
  background: var(--accent-primary);
  color: var(--accent-text);
}

.btn-primary:hover:not(:disabled) {
  background: var(--slate-700);
}

.btn-secondary {
  background: var(--bg-hover);
  color: var(--text-primary);
}

.btn-secondary:hover:not(:disabled) {
  background: var(--bg-active);
}

.btn-outline {
  background: transparent;
  border-color: var(--border);
  color: var(--text-primary);
}

.btn-outline:hover:not(:disabled) {
  background: var(--bg-hover);
}

.btn-ghost {
  background: transparent;
  color: var(--text-primary);
}

.btn-ghost:hover:not(:disabled) {
  background: var(--bg-hover);
}

.btn-danger {
  background: var(--accent-red);
  color: #ffffff;
}

.btn-danger:hover:not(:disabled) {
  background: var(--red-600);
}

/* Task 304 — warning variant for confirmDialog primitive (driven by slice.variant). */
.btn-warning {
  background: var(--accent-amber);
  color: #ffffff;
}

.btn-warning:hover:not(:disabled) {
  background: var(--accent-amber);
  filter: brightness(0.9);
}

/* ADR-047 — author display:flex (0,1,0) defeats native [hidden] (0,0,0). */
.btn-warning[hidden] {
  display: none;
}

.btn-leading {
  margin-right: auto;
}

.btn[hidden] {
  display: none;
}

/* ── Save Bar ─────────────────────────────────────────────────── */

.save-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--space-2) var(--space-5);
  background: var(--bg-card);
  border-top: 1px solid var(--border);
  gap: var(--space-4);
  transition: transform var(--duration-base) var(--ease-emphasized);
}

.save-bar[hidden] {
  display: none;
}

.participant-modal__network-error {
  display: block;
  color: var(--accent-red);
  font-size: var(--font-size-sm);
  margin-top: var(--space-2);
}

.participant-modal__network-error:empty {
  display: none;
}

.save-bar__message {
  font-size: var(--font-size-sm);
  color: var(--text-secondary);
}

.save-bar__actions {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
}

/* ── Email chip (TD-T286-001 — primitivised) ──────────────────── */

.email-chip {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  padding: var(--space-1) var(--space-2);
  background: var(--bg-hover);
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
  font-size: var(--font-size-xs);
  color: var(--text-primary);
}

/* ── Pane State (Task 314) ───────────────────────────────────────
   Waiting / empty / error states inside content panes (transcript,
   action output, proposal). Pairs with views/primitives/paneState.js.
   See design-system.md §2.7 for the recipe.
   .empty-state in style.css is intentionally retained for 5+ legacy
   consumers and is out of scope. */
.pane-state {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: var(--space-5) var(--space-4);
  gap: var(--space-2);
}
/* Centring lever for non-flex parents (Sites 2, 3 inside
   .transcript-tab-content). Scoped intentionally — applying min-height: 100%
   on every .pane-state would conflict with the header siblings at Sites 5
   and 7 inside .action-tab-content-wrapper (flex column with height: 100%):
   header (auto) + child min 100% would overflow the wrapper. The base
   flex: 1 above already fills correctly in flex-column parents. */
.transcript-tab-content > .pane-state {
  min-height: 100%;
}
.pane-state__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.pane-state__icon svg {
  width: 24px;
  height: 24px;
}
.pane-state__title {
  margin: 0;
  font-size: var(--font-size-lg);
  font-weight: var(--font-weight-medium);
  color: var(--text-primary);
}
.pane-state__subtitle {
  margin: 0;
  font-size: var(--font-size-sm);
  color: var(--text-tertiary);
}
.pane-state--error .pane-state__title {
  color: var(--accent-red);
}
.pane-state--error .pane-state__icon {
  color: var(--accent-red);
}

/* ── Pane Alert (Task 473) ──────────────────────────────────────
   Inline in-flow notice rendered ABOVE surviving pane content —
   contrast with .pane-state, which REPLACES the pane body.
   CSS-only primitive: callers emit the markup and escape text
   themselves (no JS helper at one consumer — promotion trigger:
   2nd consuming view). Recipe + decision table: design-system.md §2.9.
   Markup contract:
     <div class="pane-alert pane-alert--warning|--error" role="alert">
       <div class="pane-alert__body">
         <p class="pane-alert__title">…</p>
         <p class="pane-alert__text">…</p>
       </div>
       <div class="pane-alert__actions">…buttons…</div>  <!-- optional -->
     </div> */
.pane-alert {
  /* TD-473-004: single home for the icon square (column + ::before box). */
  --pane-alert-icon-size: 36px;
  display: grid;
  grid-template-columns: var(--pane-alert-icon-size) 1fr auto;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  margin-bottom: var(--space-5);
}
/* Alt-text form: glyph is silent for screen readers; role="alert" on
   the container carries the semantics (CSS-borne icon is the accepted
   consequence of no JS helper at one consumer — design-system §2.9).
   TD-473-006: browsers without alt-text `content` support drop that
   whole declaration — the plain form FIRST is the fallback; the alt
   form after it wins where supported. */
.pane-alert::before {
  content: "⚠";
  content: "⚠" / "";
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--pane-alert-icon-size);
  height: var(--pane-alert-icon-size);
  border-radius: var(--radius-sm);
}
.pane-alert--warning {
  background: var(--accent-amber-bg);
  border-color: var(--accent-amber);
}
.pane-alert--warning::before {
  color: var(--accent-amber);
}
.pane-alert--error {
  background: var(--accent-red-bg);
  border-color: var(--accent-red);
}
.pane-alert--error::before {
  color: var(--accent-red);
}
.pane-alert__body {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  min-width: 0;
}
.pane-alert__title {
  margin: 0;
  font-size: var(--font-size-sm);
  font-weight: var(--font-weight-semibold);
  color: var(--text-primary);
}
.pane-alert__text {
  margin: 0;
  font-size: var(--font-size-sm);
  color: var(--text-secondary);
  overflow-wrap: break-word;
}
.pane-alert__actions {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
}
/* Mandatory [hidden] companion — author display (0,1,0) beats native
   [hidden] (BUG-093 / design-system §7 step 2 / MP-303-01). */
.pane-alert[hidden] {
  display: none;
}

/* ── Output pane / card / body (Task 475) ───────────────────────
   The shared reviewable-output composition surface (design-system §4.7):
   promoted from the Task-473 remail pane with the email thread pane as
   the second consumer day one.
     .output-pane — full-width column shell (geometry only)
     .output-card — surface chrome ONLY (exactly 3 declarations); the
                    consuming view owns its own layout + padding
     .output-body — reading rhythm the global reset strips (p/ul/ol
                    margins, edge clips, img containment)
   .output-pane deliberately has NO [hidden] companion: it is not a
   togglable surface — the parent tab container owns hiding (inverts the
   BUG-093 companion rule; this rationale line is the OPC-475-05 guard). */
.output-pane {
  display: flex;
  flex-direction: column;
  width: 100%;
  margin-inline: auto;
  padding: var(--space-5) var(--space-4);
}
.output-card {
  background: var(--bg-card);
  border: 1px solid var(--border);
  box-shadow: var(--elevation-1);
}
/* Rhythm the global `* { margin:0; padding:0 }` reset strips (mirrors
   .action-output-markdown, tokenised). The list padding restore is
   load-bearing: without it, outside list markers hang into the left
   margin of the body column. */
.output-body p {
  margin: var(--space-3) 0;
}
.output-body ul,
.output-body ol {
  margin: var(--space-3) 0;
  padding-left: var(--space-6);
}
/* Edge clips stay AFTER the rhythm rules — equal (0,1,1) specificity,
   source order decides; earlier placement reopens the trailing gap. */
.output-body > :first-child { margin-top: 0; }
.output-body > :last-child { margin-bottom: 0; }
.output-body img { max-width: 100%; }

/* ── Form error baseline (TD-T286-002) ────────────────────────── */

.form-error {
  font-size: var(--font-size-xs);
  color: var(--accent-red);
  line-height: var(--line-height-normal);
}

/* ── Accessibility utility ────────────────────────────────────── */

.visually-hidden {
  position: absolute !important;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* ═══════════════════════════════════════════════════════════════
   ANIMATIONS
   ═══════════════════════════════════════════════════════════════ */

@keyframes modal-shell-fade-in {
  from { opacity: 0; transform: translateY(8px) scale(0.98); }
  to   { opacity: 1; transform: translateY(0) scale(1); }
}

/* ═══════════════════════════════════════════════════════════════
   CONNECTIONS TAB — Phase 2 (release 001)
   Visual treatment for the Settings → Connections page rendered
   by views/settingsView.js::renderConnectionsPage. Class names that
   tests rely on (.connection-row, [data-feature], .connection-row__connect,
   .connection-row__reconsent, .connection-row__reconsent-btn,
   .connections-cta, .connections-loading) are preserved as structural
   contracts — see tests/settings-connections-page.test.js + reconsent.
   ═══════════════════════════════════════════════════════════════ */

.connections-tab {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  padding: var(--space-2) 0;
}

/* Provider chip: "Signed in with [Microsoft]" header */
.connections-provider {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--font-size-sm);
  color: var(--text-secondary);
}

.connections-provider__chip {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  padding: var(--space-1) var(--space-2);
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  background: var(--bg-card);
  color: var(--text-primary);
  font-size: var(--font-size-xs);
  font-weight: var(--font-weight-medium);
  line-height: 1;
}

.connections-provider__chip::before {
  content: '';
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--accent-green);
}

.connections-provider__logo {
  display: inline-flex;
  align-items: center;
  line-height: 1;
}

.connections-provider__logo svg {
  width: 14px;
  height: 14px;
}

/* Connection row card */
.connection-row {
  display: grid;
  grid-template-columns: 36px 1fr auto;
  align-items: center;
  gap: var(--space-4);
  padding: var(--space-4);
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  transition: border-color var(--duration-fast) var(--ease-standard),
              background var(--duration-fast) var(--ease-standard);
}

.connection-row:hover {
  border-color: var(--slate-300);
}

.connection-row__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  border-radius: var(--radius-sm);
  background: var(--bg-hover);
  font-size: 18px;
  line-height: 1;
}

.connection-row__main {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  min-width: 0;
}

.connection-row__title {
  font-size: var(--font-size-base);
  font-weight: var(--font-weight-semibold);
  color: var(--text-primary);
  line-height: var(--line-height-tight);
}

.connection-row__subtitle {
  font-size: var(--font-size-sm);
  color: var(--text-secondary);
  line-height: var(--line-height-normal);
}

/* Right-hand status / action slot */
.connection-row__status {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
}

.connection-status {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  padding: var(--space-1) var(--space-2);
  border-radius: var(--radius-sm);
  font-size: var(--font-size-xs);
  font-weight: var(--font-weight-medium);
  line-height: 1;
}

.connection-status--connected {
  background: var(--accent-green-bg);
  color: var(--green-900);
}

@media (prefers-color-scheme: dark) {
  .connection-status--connected {
    color: var(--accent-green);
  }
}

.connection-status--locked {
  background: var(--bg-hover);
  color: var(--text-secondary);
  border: 1px solid var(--border-subtle);
}

/* Bundle-stale re-consent banner (Task 353 / P1-4) */
.connection-row__reconsent {
  display: grid;
  grid-template-columns: 36px 1fr auto;
  align-items: center;
  gap: var(--space-4);
  padding: var(--space-4);
  background: var(--accent-amber-bg);
  border: 1px solid var(--accent-amber);
  border-radius: var(--radius-md);
}

.connection-row__reconsent::before {
  content: '⚠';
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  font-size: 18px;
  color: var(--accent-amber);
  background: var(--bg-card);
  border-radius: var(--radius-sm);
}

.connection-row__reconsent-body {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  min-width: 0;
}

.connection-row__reconsent-title {
  margin: 0;
  font-size: var(--font-size-base);
  font-weight: var(--font-weight-semibold);
  color: var(--text-primary);
  line-height: var(--line-height-tight);
}

.connection-row__reconsent-text {
  margin: 0;
  font-size: var(--font-size-sm);
  color: var(--text-secondary);
  line-height: var(--line-height-normal);
}

/* Compact modifier — one-row inline action notice for narrow host contexts
   (sidebar, narrow tab panes). Drops the text body; the button label alone
   communicates the action. Pale red fill (no border, no icon box) keeps the
   surface subdued while the icon left + button right still flag attention.
   HTML omits .connection-row__reconsent-body. Host classes own outer margin
   so the CTA aligns with sibling content in each tab. */
.connection-row__reconsent--compact {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-3);
  background: var(--accent-red-bg);
  border: 0;
}

.connection-row__reconsent--compact::before {
  width: auto;
  height: auto;
  font-size: 18px;
  background: transparent;
  border-radius: 0;
  color: var(--accent-red);
  flex-shrink: 0;
}

.connection-row__reconsent--compact .connection-row__reconsent-btn {
  margin-left: auto;
}

/* Host-specific spacing for the compact CTAs.
   Calendar: .sidebar-section parent already provides 12px L/R padding, so
   only top breathing room is needed between the events list and the CTA.
   Docs:    siblings .upload-zone + .documents-list-box use margin: 8px 12px,
   so match them so the CTA inset-aligns with the rest of the tab. */
.calendar-reconsent-cta {
  margin-top: var(--space-2);
}

.documents-storage-cta {
  margin: var(--space-2) var(--space-3);
}

/* Task 361 — X dismiss button trailing the action button on the compact
   reconsent CTAs (calendar + docs only; Settings is non-dismissible). */
.connection-row__reconsent-dismiss {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  padding: 0;
  margin-left: var(--space-1);
  background: transparent;
  border: 0;
  border-radius: var(--radius-sm);
  color: var(--text-secondary);
  font-size: 18px;
  line-height: 1;
  cursor: pointer;
}

.connection-row__reconsent-dismiss:hover {
  color: var(--text-primary);
  background: var(--bg-hover);
}

.connection-row__reconsent-dismiss:focus-visible {
  outline: 2px solid var(--accent-focus);
  outline-offset: 2px;
}

/* btn_hidden_companion_rule (ADR-047): inline-flex defeats native [hidden]. */
.connection-row__reconsent-dismiss[hidden] { display: none; }

/* Empty state: password-only user (login_provider === null) */
.connections-cta {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: var(--space-3);
  padding: var(--space-8) var(--space-5);
  background: var(--bg-card);
  border: 1px dashed var(--border);
  border-radius: var(--radius-md);
}

.connections-cta__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 48px;
  height: 48px;
  border-radius: 50%;
  background: var(--bg-hover);
  font-size: 22px;
  line-height: 1;
}

.connections-cta__title {
  margin: 0;
  font-size: var(--font-size-md);
  font-weight: var(--font-weight-semibold);
  color: var(--text-primary);
}

.connections-cta p {
  margin: 0;
  max-width: 420px;
  font-size: var(--font-size-sm);
  color: var(--text-secondary);
  line-height: var(--line-height-normal);
}

/* Loading state — between provider known and consent status fetched */
.connections-loading {
  padding: var(--space-6);
  font-size: var(--font-size-sm);
  color: var(--text-secondary);
  text-align: center;
}

/* Compact layout for narrow modals */
@media (max-width: 560px) {
  .connection-row,
  .connection-row__reconsent {
    grid-template-columns: 32px 1fr;
    grid-template-areas:
      'icon  main'
      '.     action';
  }
  .connection-row__icon,
  .connection-row__reconsent::before { grid-area: icon; }
  .connection-row__main,
  .connection-row__reconsent-body { grid-area: main; }
  .connection-row__status,
  .connection-row__reconsent-btn { grid-area: action; justify-self: start; }
}

/* ═══════════════════════════════════════════════════════════════
   PILL — inline status pill (Task 466)
   Shape promoted from the bespoke .sched-renewal-chip; tokens only.
   Base tone is soft (bg-hover/secondary); tone modifiers opt in.
   --negative ships for future consumers — the portfolio renders
   "Renewal passed" with the plain base pill (honesty floor).
   ═══════════════════════════════════════════════════════════════ */

.pill {
  display: inline-block;
  padding: 0 var(--space-2);
  border-radius: var(--radius-pill);
  background: var(--bg-hover);
  color: var(--text-secondary);
  font-size: var(--font-size-xs);
  line-height: var(--line-height-loose);
  white-space: nowrap;
}
.pill--positive { color: var(--accent-green); background: var(--accent-green-bg); }
.pill--negative { color: var(--accent-red); background: var(--accent-red-bg); }
.pill--muted { color: var(--text-tertiary); background: transparent; }

/* ═══════════════════════════════════════════════════════════════
   CLIENT SUMMARY CARD — shared section chrome (Task 466, TD-T330-003)
   The card chrome previously duplicated across the dashboard/metrics
   section comma-list in style.css. Opt-in: section roots include the
   class in their markup. Radius/padding stay literal to avoid visual
   drift (no exact token equivalents).
   ═══════════════════════════════════════════════════════════════ */

.client-summary-card {
  background: var(--bg-primary);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 0.6rem 0.75rem;
}

/* ═══════════════════════════════════════════════════════════════
   HIGHLIGHT CARD — the "start here" treatment (design-system §2.12)
   Blue-tinted surface + muted 1px blue→violet gradient hairline via
   the padding-box/border-box composite. At most ONE highlighted
   element per view — scarcity is the cue. The consumer owns size,
   radius, layout and typography; re-owning background/border silently
   kills the hairline (consumer tests negative-pin this).
   Consumers: start-panel broker-journey primaries, workflow-rail
   Add step.
   ═══════════════════════════════════════════════════════════════ */

.card-highlight {
  border: 1px solid transparent;
  background:
      linear-gradient(var(--bg-card-accent), var(--bg-card-accent)) padding-box,
      linear-gradient(135deg,
          color-mix(in srgb, var(--accent-blue) 28%, transparent),
          color-mix(in srgb, var(--accent-violet) 28%, transparent)) border-box;
}

.card-highlight:hover:not([disabled]) {
  background:
      linear-gradient(var(--bg-hover), var(--bg-hover)) padding-box,
      linear-gradient(135deg,
          color-mix(in srgb, var(--accent-blue) 28%, transparent),
          color-mix(in srgb, var(--accent-violet) 28%, transparent)) border-box;
}

/* ═══════════════════════════════════════════════════════════════
   BEZEL — top-lit hairline for raised tiles (design-system §2.11)
   Soft 3D lift: 1px ring, light at top, dark at bottom, drawn with
   the padding-box/border-box composite (border-image can't round
   corners). Theme intensity comes from --bezel-highlight/--bezel-shadow
   in tokens.css (lighting constants, like elevation). Opt-in on small
   raised interactive tiles (icon tiles, avatars, stat tiles) — not on
   flat informational chips. The consumer owns size, radius and layout,
   and may repoint the surface via --bezel-surface.
   First consumer: start-panel icon tiles.
   ═══════════════════════════════════════════════════════════════ */

.bezel {
  --bezel-surface: var(--bg-active);
  border: 1px solid transparent;
  background:
      linear-gradient(var(--bezel-surface), var(--bezel-surface)) padding-box,
      linear-gradient(to bottom, var(--bezel-highlight), var(--bezel-shadow)) border-box;
}

/* ═══════════════════════════════════════════════════════════════
   REDUCED MOTION
   Honours OS-level user preference (architecture decisions row 18).
   ═══════════════════════════════════════════════════════════════ */

@media (prefers-reduced-motion: reduce) {
  .modal-shell,
  .modal-shell.visible,
  .save-bar,
  .toggle__thumb,
  .toggle__track {
    animation: none !important;
    transition: none !important;
  }
}
