/* These styles are generated from project.scss. */

/* CKEditor's floating balloons (the Link popup, image contextual toolbar,
   etc.) default to z-index ~1000 (--ck-z-panel = --ck-z-default + 999, and
   the vendored bundle sets --ck-z-default: 1) — below Bootstrap's own
   offcanvas (1045, see .feedback-offcanvas below). Every balloon mounts to
   document.body, not inside the editor's own container, so a selector
   scoped to .feedback-offcanvas can never reach it — this has to be a
   global override. Inside the feedback panel this made clicking "Link"
   open the balloon invisibly behind the panel, reading as "the button
   does nothing" (#819). Raised well above every fixed/sticky z-index this
   platform uses (max 1030 elsewhere) so it's not a near thing.

   !important is load-bearing, not defensive: base.html's own {% block
   css %} (project.css) always renders before {% block javascript %} /
   extra_js (ckeditor5.css) — confirmed by reading base.html, not assumed
   — on every page that loads CKEditor synchronously (8D, tickets, fmea,
   issues, pcp), and the feedback panel lazy-loads ckeditor5.css later
   still. Same :root selector, same specificity — whichever stylesheet
   is last in the DOM wins the cascade, and that is always CKEditor's own.
   Without !important this override would be silently undone on every
   single page, not just the one it was reported on.

   Broader than "just the balloons," worth knowing before touching this
   again: --ck-z-default feeds ten z-index rules in the vendored bundle,
   not only --ck-z-panel (balloons) — nine stay inside the editable
   (dropdown arrows, table column resizer, etc., where 1 vs 1100 is
   inert either way); the tenth, .ck-block-toolbar-button, would escape
   the editor and sit above this platform's sticky headers/Bootstrap
   modal/popover — currently moot, since BlockToolbar isn't in
   getRichTextPlugins() (project.js).

   Does not break CKEditor's own fullscreen mode, but only incidentally:
   fullscreen's own rule is html.ck-fullscreen, body.ck-fullscreen {
   --ck-z-default: calc(var(--ck-z-fullscreen) + 1) }, i.e. 10001 — an
   !important on :root wins on the <html> element, but CKEditor adds the
   ck-fullscreen class to *both* html and body, and body's own
   non-important value then wins there (closer in the cascade), which is
   where the fullscreen UI actually renders. Also moot today: Fullscreen
   isn't loaded either. */
:root {
  --ck-z-default: 1100 !important;
}

.alert-debug {
  color: black;
  background-color: white;
  border-color: #d6e9c6;
}

.alert-error {
  color: #b94a48;
  background-color: #f2dede;
  border-color: #eed3d7;
}

.mermaid-preview {
  min-height: 200px;
  overflow: auto;
}

.md-preview {
  min-height: 120px;
}

.rendered-markdown p:last-child {
  margin-bottom: 0;
}

/* Release notes sit inside a card whose header already names the release
   and its date, so a heading in the note itself is subordinate to that --
   at default markdown sizes an <h2> rendered larger than the release title
   above it, in every single card. */
.release-notes h1,
.release-notes h2,
.release-notes h3,
.release-notes h4 {
  font-size: 1rem;
  font-weight: 600;
  margin-top: 0.75rem;
  margin-bottom: 0.25rem;
}

.release-notes > :first-child {
  margin-top: 0;
}

/* CodeMirror wrapper for [data-markdown-editor] textareas (#397) — matches
   Bootstrap's .form-control appearance since it visually replaces one. */
.markdown-editor.CodeMirror {
  height: auto;
  min-height: 6rem;
  border: 1px solid #ced4da;
  border-radius: 0.375rem;
  font-size: 1rem;
  padding: 0.375rem 0.25rem;
}

.clickable-row {
  cursor: pointer;
}

.min-width-0 {
  min-width: 0;
}

.card-narrow {
  max-width: 600px;
}

.badge-xs {
  font-size: 0.65em;
}

/* Reusable "i" info-icon button (#546) — a small circular button that
   opens a Bootstrap popover explaining a field/label. See
   {% info_icon %} in edp/workflows/templatetags/ui_tags.py. */
.info-icon-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.1rem;
  height: 1.1rem;
  padding: 0;
  border: 1px solid #6c757d;
  border-radius: 50%;
  background: transparent;
  color: #6c757d;
  font-size: 0.7rem;
  font-style: italic;
  font-weight: 700;
  line-height: 1;
  cursor: pointer;
}

.info-icon-btn:hover,
.info-icon-btn:focus {
  color: #495057;
  border-color: #495057;
}

/* #894 — Bootstrap's own popover default (276px) was fine for the
   original two-short-paragraph content (the Track field's own info
   icon) but crams the 3-column severity scoring table (_severity_scale.html)
   into cramped, heavily-wrapped cells. Widened for every info-icon
   popover platform-wide rather than adding a per-usage override — the
   Track field's own content only gets more breathing room, never less,
   from a wider box. */
.popover {
  --bs-popover-max-width: 420px;
}

/* Canvas editor */
.canvas-workspace {
  position: relative;
  height: calc(100vh - 185px);
  min-height: 400px;
}

.canvas-stencil-panel {
  position: absolute;
  left: 8px;
  top: 8px;
  z-index: 10;
  background: #fff;
  border: 1px solid #dee2e6;
  border-radius: 6px;
  padding: 6px;
  display: flex;
  flex-direction: column;
  gap: 2px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
  width: 68px;
}

.stencil-item {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  padding: 4px 2px;
  border-radius: 4px;
  cursor: grab;
  font-size: 0.65rem;
  color: #555;
  user-select: none;
}

.stencil-item:hover {
  background: #f0f4ff;
}

.stencil-item:active {
  cursor: grabbing;
}

/* Prevent SVG children from intercepting drag events on the parent div */
.stencil-item svg {
  pointer-events: none;
}

.stencil-edge-btn {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  padding: 4px 2px;
  border-radius: 4px;
  cursor: pointer;
  font-size: 0.65rem;
  color: #555;
  user-select: none;
  background: none;
  border: none;
  width: 100%;
}

.stencil-edge-btn:hover {
  background: #f0f4ff;
}

.stencil-divider {
  border: none;
  border-top: 1px solid #dee2e6;
  margin: 2px 0;
}

.canvas-area {
  flex: 1;
  min-width: 0;
  background: #f8f9fa;
  overflow: hidden;
}

.canvas-props-panel {
  width: 380px;
  flex-shrink: 0;
  overflow-y: auto;
  background: #fff;
}

/* #675 — a soft blue tint replaces the previous flat grey so section
   headers stand out from the plain white card bodies around them;
   platform-wide (every canvas-section-header consumer: eightd's D0-D8,
   the workflows canvas editor panel, requirements' own accordion), since
   none of those besides eightd's own Theory/Report-level-Tests cards
   below actually nest one header inside another today — this is
   "level 1" by default, and .canvas-section-header-nested (below)
   lightens it one step for the cases that do nest. */
.canvas-section-header {
  background: #a9cbe8;
  border-bottom: 1px solid #7ba7d1;
  padding: 0.375rem 0.75rem;
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: #2c4a66;
  display: flex;
  justify-content: space-between;
  align-items: center;
  user-select: none;
  width: 100%;
  border-left: none;
  border-right: none;
  border-top: none;
  text-align: left;
}

button.canvas-section-header:hover {
  background: #94bce0;
  color: #1c344a;
}

/* #675 — "level 2": lighter tint for a header nested inside another
   section's own card body (eightd's D4 Theory cards, Report-level Tests
   sub-card) so the hierarchy reads at a glance — combined with
   .canvas-section-header, not a replacement for it. */
.canvas-section-header.canvas-section-header-nested {
  background: #cfe1f2;
  border-bottom-color: #a8c8e4;
  color: #3d5a75;
}

button.canvas-section-header.canvas-section-header-nested:hover {
  background: #bcd4ec;
}

.canvas-meta-chevron {
  transition: transform 0.2s;
}

[aria-expanded="false"] .canvas-meta-chevron {
  transform: rotate(-90deg);
}

.canvas-zoom-display {
  min-width: 52px;
  cursor: default;
  text-align: center;
}

.canvas-rankdir-select {
  width: auto;
  min-width: 72px;
}

.canvas-panel-resize-handle {
  width: 6px;
  flex-shrink: 0;
  cursor: col-resize;
  background: transparent;
  transition: background 0.15s;
  z-index: 10;
}

.canvas-panel-resize-handle:hover,
.canvas-panel-resize-handle.dragging {
  background: #adb5bd;
}

/* Read-only workflow viewer embedded on procedure pages. */
.workflow-viewer {
  height: calc(100vh - 240px);
  min-height: 400px;
  background: #f8f9fa;
  overflow: hidden;
  border-radius: 0.375rem;
}

.viewer-sticky {
  position: sticky;
  top: 4rem;
}

.fmea-entry-panel-scroll {
  max-height: calc(100vh - 5rem);
  overflow-y: auto;
}

/* Nested links inside a .stretched-link ticket row (tickets:list) — without
   this, the row's own .stretched-link ::after overlay sits above and
   intercepts clicks meant for the linked-8D links. Also lands in #573. */
.ticket-row-links a {
  position: relative;
  z-index: 1;
}

/* #761 — per-row "Duplicate" action on the ticket list. Carries Bootstrap's
   own .btn .btn-sm .btn-outline-secondary alongside this class so it reads
   as a real button rather than a bare link (Thom's ask), matching the
   Duplicate button on the ticket detail page; this class only adds the
   reveal behaviour and the stacking fix.

   Hidden until the row is hovered so it adds no permanent visual weight to
   an already-wide table (also Thom's ask), but deliberately NOT hover-only:

   - :focus-within keeps it reachable by keyboard, where there is no hover
     at all and the control would otherwise be permanently invisible.
   - The (hover: none) block below pins it visible on touch devices, which
     never fire hover — field staff on a tablet would otherwise have no way
     to reach it.

   position/z-index for the same reason .ticket-row-links above needs them:
   the row's own .stretched-link ::after overlay covers the whole row, and
   without lifting this above it the click is swallowed and silently
   navigates to the detail page instead of duplicating. */
.ticket-row-action {
  position: relative;
  z-index: 1;
  opacity: 0;
  transition: opacity 0.12s ease-in-out;
}

tr:hover > td > .ticket-row-action,
tr:focus-within > td > .ticket-row-action {
  opacity: 1;
}

@media (hover: none) {
  .ticket-row-action {
    opacity: 1;
  }
}

/* 8D report read-only detail view (eightdreport_detail.html) */
.eightd-detail-kv-label {
  width: 20%;
}

.eightd-detail-whystep-num {
  width: 5%;
}

.fmea-filter-sticky {
  position: sticky;
  top: 4rem;
  background: #fff;
  z-index: 10;
  padding-top: 0.375rem;
  padding-bottom: 0.5rem;
  border-bottom: 1px solid #dee2e6;
  margin-bottom: 0.75rem;
}

/* 8D report/branch header — title + back-link + View/PDF/Edit buttons
   (#653) — stays visible while the long D0-D8 page scrolls, so the
   actions stay reachable without scrolling back to the top. Same
   sticky-under-navbar shape as .fmea-filter-sticky, but top: 3.5rem
   (not 4rem) — measured live against the rendered navbar's own
   border-box bottom edge (56px = 3.5rem); 4rem left an 8px gap showing
   scrolled-past page content peeking through between the two sticky
   elements. margin-top: -0.25rem pulls the header up into the navbar
   wrapper's own trailing `mb-1` margin (blank space, not part of the
   navbar's painted area) so the header's natural resting position
   exactly matches its sticky offset — without this, the header visibly
   drifts up those 4px the instant you start scrolling (its natural
   position sat 4px below the sticky threshold, so scrolling "used up"
   that gap before it locked in place) instead of being pinned from the
   first pixel of scroll. */
.eightd-page-header-sticky {
  position: sticky;
  top: 3.5rem;
  margin-top: -0.25rem;
  background: #fff;
  z-index: 10;
  padding-top: 0.5rem;
  padding-bottom: 0.5rem;
  border-bottom: 1px solid #dee2e6;
}

.fmea-sort-link {
  color: inherit;
}

.fmea-sort-link:hover {
  color: #0d6efd;
}

.viewer-graph-header {
  cursor: default;
}

.viewer-fit-btn {
  font-size: 0.7rem;
}

/* PCP deliverable status — mirrors the source Excel's color legend */
.pcp-status-not_started {
  background-color: #f8f9fa;
  color: #212529;
}

.pcp-status-missing {
  background-color: #dc3545;
  color: #fff;
}

.pcp-status-to_be_reviewed {
  background-color: #d63384;
  color: #fff;
}

.pcp-status-checked {
  background-color: #ffc107;
  color: #212529;
}

.pcp-status-validated {
  background-color: #198754;
  color: #fff;
}

.pcp-grid-cell {
  min-width: 150px;
  font-size: 0.7rem;
}

.pcp-grid-category-cell {
  max-width: 140px;
}

.pcp-grid-chip {
  display: block;
  padding: 0.1rem 0.3rem;
  margin-bottom: 2px;
  border-radius: 0.2rem;
  text-decoration: none;
  line-height: 1.3;
  word-break: break-word;
}

.pcp-grid-chip:hover {
  opacity: 0.85;
}

.pcp-grid-chip-number {
  font-weight: 700;
  margin-right: 0.25rem;
}

/* PCP stage header row — groups tollgate columns into named stages
   (Product definition, Product development, ...), cycling through a fixed
   palette since the number/names of stages are template-defined. The first
   three colors are lifted directly from the source Excel's own stage header
   fills (Product Definition/Development/Industrialization), computed from
   its theme + tint values so the platform visually matches the sheet Thom
   is used to reading. */
.pcp-stage-header {
  text-transform: uppercase;
  letter-spacing: 0.02em;
  font-weight: 600;
}

/* Bootstrap 5's table cells set background-color via
   `.table > :not(caption) > * > *`, a higher-specificity selector than a
   plain class — the `.table` prefix here (two classes) is needed to win
   the cascade instead of silently losing to Bootstrap's default. */
.table .pcp-stage-0 {
  background-color: #ffcc66;
}

.table .pcp-stage-1 {
  background-color: #b4c7e7;
}

.table .pcp-stage-2 {
  background-color: #a9d18e;
}

.table .pcp-stage-3 {
  background-color: #e2d9f3;
}

/* PCP grid — boxed scrollable panel with a sticky header, so the
   stage/tollgate/phase column headers stay legible on a tall grid.
   `position: sticky` does NOT work on a plain Bootstrap `.table-responsive`
   wrapper: it sets `overflow-x: auto` only, but per the CSS overflow spec a
   non-`visible` x-axis forces the y-axis to compute to `auto` too — turning
   `.table-responsive` into its own scroll container. Since that div has no
   fixed height, it just grows to fit the table and never actually scrolls,
   so a sticky descendant has nothing to stick against. Giving it a bounded
   `max-height` + explicit `overflow: auto` here makes it a real scrollport
   (both axes, like a spreadsheet pane) so the sticky header actually has
   something to pin against. */
.pcp-grid-scroll {
  max-height: calc(100vh - 220px);
  overflow: auto;
}

/* Three stacked header rows each need their own cumulative top offset (a
   plain `top: 0` on all three would make row 2 and row 3 jump up and
   overlap row 1 at the same sticky point, instead of stacking below it).
   Hardcoded rem guesses here caused a visible jump the instant a row
   became stuck (offset didn't exactly match the row's real rendered
   height) and a hairline border gap at that boundary — the offsets are
   measured from actual rendered row heights instead, via CSS custom
   properties set by initPcpGridStickyHeader() in project.js. Row 2/3 get
   an explicit white background so scrolled body rows don't show through
   underneath; row 1's stage-color cells already have an opaque background
   via .pcp-stage-N above, and its one plain corner cell gets
   .pcp-grid-sticky-corner instead so it doesn't fight that cascade.
   box-shadow (not border) reinforces the boundary below each row —
   Bootstrap's own collapsed border between cells doesn't repaint reliably
   while one side is position: sticky, so it visibly flickers/goes
   transparent under scroll; a box-shadow is painted inside each cell's own
   box regardless of stickiness, masking that flicker with a stable line.
   `will-change: transform` forces the browser to composite the sticky
   cell on its own GPU layer — without it, some browsers rasterize
   position: sticky elements at a slightly different sub-pixel offset than
   the content scrolling beneath them each frame, showing a hairline seam
   of that content through the boundary; compositing separately keeps the
   cell's own paint (background + box-shadow) pixel-stable regardless. */
.pcp-grid-sticky-thead th {
  position: sticky;
  z-index: 2;
  box-shadow: inset 0 -1px 0 #dee2e6;
  will-change: transform;
}

.pcp-grid-sticky-thead tr:nth-child(1) th {
  top: 0;
}

.pcp-grid-sticky-thead tr:nth-child(2) th {
  top: var(--pcp-grid-row1-height, 1.75rem);
  background-color: #fff;
}

.pcp-grid-sticky-thead tr:nth-child(3) th {
  top: var(--pcp-grid-row12-height, 4.75rem);
  background-color: #fff;
  text-align: left;
  vertical-align: top;
}

/* Bootstrap 5's table cells set background-color via
   `.table > :not(caption) > * > *`, a higher-specificity selector than a
   plain class — the `.table` prefix here (two classes) is needed to win
   the cascade instead of silently losing to Bootstrap's default (same
   gotcha as .pcp-stage-N above; the sticky rows' own `th` selectors above
   already carry enough specificity to win without this, since they chain
   through `tr:nth-child(N)`, but this single-class selector doesn't).
   `!important` because this cell reportedly stayed transparent even after
   the `.table` specificity bump — belt-and-braces against whatever else
   is still winning the cascade on it. */
.table .pcp-grid-sticky-corner {
  background-color: #fff !important;
}

/* First column frozen on horizontal scroll too, spreadsheet-style — the
   category name is otherwise meaningless once scrolled out of view to the
   left. Header row's first cell (category label / empty corner) needs
   `left` in addition to the `top` it already gets above, so it stays
   pinned at both edges at once; a higher z-index than the plain sticky-top
   header cells (2) and the sticky-left body column (1) below ensures it
   renders above both wherever they visually meet. */
.pcp-grid-sticky-thead tr th:first-child {
  left: 0;
  z-index: 3;
  background-color: #fff !important;
  box-shadow:
    inset -1px 0 0 #dee2e6,
    inset 0 -1px 0 #dee2e6;
  will-change: transform;
}

.pcp-grid-table tbody tr > :first-child {
  position: sticky;
  left: 0;
  z-index: 1;
  box-shadow: inset -1px 0 0 #dee2e6;
  will-change: transform;
}

.table .pcp-grid-category-cell {
  background-color: #fff;
}

.pcp-stage-chip {
  min-width: 220px;
}

/* Restyle ClearableFileInput's plain checkbox into a small outline button —
   scoped to the deliverable document card only, not every ClearableFileInput
   platform-wide. */
.pcp-document-card input[type="checkbox"][id$="-clear_id"] {
  display: none;
}

.pcp-document-card label[for$="-clear_id"] {
  display: inline-block;
  padding: 0.1rem 0.5rem;
  margin-left: 0.5rem;
  font-size: 0.7rem;
  border: 1px solid #dc3545;
  color: #dc3545;
  border-radius: 0.2rem;
  cursor: pointer;
}

.pcp-document-card label[for$="-clear_id"]:hover {
  background-color: #dc3545;
  color: #fff;
}

/* FMEA Action Priority badges */
.ap-high {
  background-color: #dc3545;
  color: #fff;
}

.ap-medium {
  background-color: #fd7e14;
  color: #fff;
}

.ap-low {
  background-color: #198754;
  color: #fff;
}

/* FMEA entry list */
.fmea-search-input {
  max-width: 220px;
}

.btn-xs {
  padding: 0.1rem 0.4rem;
  font-size: 0.75rem;
}

.fmea-revalidation-toggle {
  cursor: pointer;
}

.fmea-scoring-guide-link {
  font-size: 0.8rem;
}

.fmea-scoring-guide {
  background-color: #f8f9fa;
  border: 1px solid #dee2e6;
}

.fmea-guide-table {
  font-size: 0.78rem;
}

.fmea-guide-table td:first-child {
  font-weight: 600;
  text-align: center;
  width: 2rem;
}

.fmea-col-nr {
  width: 2.5rem;
}

.fmea-col-score {
  width: 2.5rem;
}

.fmea-col-ap {
  width: 3rem;
}

.fmea-scores-table {
  table-layout: fixed;
  width: 100%;
}

.fmea-scores-col-label {
  width: 4rem;
}

.fmea-scores-col-val {
  width: 3rem;
}

.fmea-scores-col-rpn {
  width: 3.5rem;
}

.fmea-scores-col-ap {
  width: 3rem;
}

.fmea-review-select {
  width: auto;
  display: inline-block;
}

.fmea-scores-table .form-control {
  padding: 0.15rem 0.2rem;
  text-align: center;
  font-size: 0.8125rem;
}

.fmea-node-mini-form {
  background: #f8f9fa;
  border: 1px solid #dee2e6;
}

.fmea-filter-select {
  max-width: 220px;
}

.fmea-advanced-filter-row {
  background: #f8f9fa;
  border: 1px solid #dee2e6;
  border-radius: 0.375rem;
  padding: 0.5rem 0.75rem;
}

.fmea-phase-add-row {
  max-width: 320px;
}

.fmea-phase-remove-btn {
  background: none;
  border: none;
  padding: 0 0 0 4px;
  color: inherit;
  line-height: 1;
  cursor: pointer;
  opacity: 0.7;
}

.fmea-phase-remove-btn:hover {
  opacity: 1;
}

.fmea-guide-tab {
  font-size: 0.8rem;
  padding: 0.25rem 0.75rem;
}

.fmea-field-error {
  font-size: 0.7rem;
  color: #dc3545;
}

.field-error {
  font-size: 0.7rem;
  color: #dc3545;
}

.fmea-autoresize {
  resize: none;
  overflow-y: hidden;
}

.fmea-timestamp {
  font-size: 0.72rem;
  color: #6c757d;
}

.fmea-action-card {
  padding: 0.4rem 0.5rem;
  border-radius: 0.25rem;
  background-color: #f8f9fa;
}

.fmea-action-update {
  padding: 0.3rem 0.5rem;
  border-radius: 0.25rem;
  background-color: #f8f9fa;
}

.autosave-label {
  position: absolute;
  top: -1.5rem;
  right: 0;
  color: #6c757d;
}

/* Remove native number-input spinners so cost-line amounts align with the
   plain Total figure below them (the spinner arrows otherwise eat into the
   input's width and throw off the right-aligned digits). */
.cost-line-amount {
  -moz-appearance: textfield;
}

.cost-line-amount::-webkit-outer-spin-button,
.cost-line-amount::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}

/* Module list table — fixed layout prevents column-width shifts on row expand */
#module-list-table { table-layout: fixed; width: 100%; }
.module-col-name    { width: 24%; }
.module-col-node    { width: 32%; }
.module-col-person  { width: 28%; }
.module-col-actions { width: 16%; }

/* Clickable module rows */
.module-row { cursor: pointer; }
.module-row-actions a { position: relative; z-index: 1; }

/* System tree table — fixed layout prevents column-width shifts on row expand */
#system-tree-table { table-layout: fixed; width: 100%; }
/* Editor layout (4 cols) */
.sys-col-name    { width: 30%; }
.sys-col-module  { width: 20%; }
.sys-col-owner   { width: 20%; }
.sys-col-actions { width: 30%; }
/* Viewer layout (3 cols) */
.sys-col-name-viewer   { width: 50%; }
.sys-col-module-viewer { width: 25%; }
.sys-col-owner-viewer  { width: 25%; }

/* Clickable system node rows */
.system-node-row-actions a { position: relative; z-index: 1; }

/* Nested links inside a .stretched-link ticket row (tickets:list) — without
   this, the row's own .stretched-link ::after overlay sits above and
   intercepts clicks meant for the linked-8D links. */
.ticket-row-links a { position: relative; z-index: 1; }

/* Tree indentation for SystemNode / OrgChartNode list views.
   !important needed to beat Bootstrap's .table-sm compound selector. */
.tree-depth-0 { padding-left: 0.5rem !important; }
.tree-depth-1 { padding-left: 2rem !important; }
.tree-depth-2 { padding-left: 3.5rem !important; }
.tree-depth-3 { padding-left: 5rem !important; }
.tree-depth-4 { padding-left: 6.5rem !important; }
.tree-depth-5 { padding-left: 8rem !important; }

/* Actions dashboard "Sources" filter dropdown (#376) */
.actions-source-menu { min-width: 16rem; max-height: 20rem; overflow-y: auto; }

/* Requirements */
.req-indent-0 { padding-left: 0; }
.req-indent-1 { padding-left: 1.5rem; display: block; }
.req-indent-2 { padding-left: 3rem; display: block; }
.req-indent-3 { padding-left: 4.5rem; display: block; }

.req-md-help {
  background: #f8f9fa;
  font-size: 0.8rem;
}

/* Issue Tracker 2D review diagram (chance x impact) */
.issue-diagram-svg-wrapper {
  overflow-x: auto;
}

.issue-diagram-svg {
  max-width: 100%;
  height: auto;
}

.issue-diagram-cell {
  width: 100%;
  height: 100%;
  padding: 0.25rem;
  display: flex;
  flex-wrap: wrap;
  align-content: flex-start;
  gap: 0.25rem;
  overflow-y: auto;
  font-family:
    -apple-system,
    BlinkMacSystemFont,
    "Segoe UI",
    Roboto,
    Helvetica,
    Arial,
    sans-serif;
}

.issue-diagram-card {
  width: 7.5rem;
  padding: 0.25rem 0.4rem;
  background: #fff;
  border: 1px solid #adb5bd;
  border-radius: 0.2rem;
  font-size: 0.7rem;
  line-height: 1.2;
  text-decoration: none;
  color: inherit;
  display: block;
}

.issue-diagram-card:hover {
  border-color: #495057;
  background: #f8f9fa;
}

.issue-diagram-card.ap-high {
  border-color: #dc3545;
}

.issue-diagram-card.ap-medium {
  border-color: #fd7e14;
}

.issue-diagram-card.ap-low {
  border-color: #198754;
}

.issue-diagram-grid-line {
  stroke: #dee2e6;
  stroke-width: 1;
}

.issue-diagram-axis-line {
  stroke: #495057;
  stroke-width: 1.5;
}

.issue-diagram-axis-label {
  font-size: 0.85rem;
  fill: #495057;
  text-anchor: middle;
}

.issue-diagram-tick-label {
  font-size: 0.75rem;
  fill: #6c757d;
}

.issue-diagram-tick-label-x {
  text-anchor: middle;
}

.issue-diagram-tick-label-y {
  text-anchor: end;
}

.percent-readout {
  display: inline-block;
  min-width: 3em;
  text-align: right;
  font-variant-numeric: tabular-nums;
}

/* A whole-card/row is clickable via hx-get (matching system_tree/orgchart's
   click-to-expand convention) — action buttons inside it need their own
   stacking context above the row's own click target. */
.issue-action-card-actions {
  position: relative;
  z-index: 2;
}

/* 8D report editor's section sidebar (decision #9, .claude/plans/8D-app-plan.md)
   — stays in view while the (long, D0-D8) form scrolls past it. top
   (#653 follow-up) must clear *both* the sticky navbar and the sticky
   page header above it (title + View/PDF/Edit buttons, also #653) — the
   header's own height varies with title length/viewport width (long
   report titles wrap), so it's measured live in JS
   (initEightdStickyOffsets() in project.js) rather than guessed as a
   fixed rem value, same reasoning as PCP's own
   initPcpGridStickyHeader(). The 9.25rem fallback covers the common
   single-line-title case for the brief window before JS runs. */
.eightd-section-nav {
  position: sticky;
  top: var(--eightd-sidebar-sticky-top, 9.25rem);
}

/* D0/D3/D5/D6/D7 "Not applicable" section-header lock (#710, replaces
   #666's older field-dimming mechanism entirely) — checking the box
   (initEightdSectionNotApplicable() in _eightd_edit_scripts.html) forces
   the section closed and strips the header's own data-bs-toggle
   attribute so clicking it does nothing; this class is the visual half
   of that lock, applied/removed alongside it. Unlike #666's
   pointer-events: none (deliberately NOT reused here — that trick was
   about not excluding a still-submitted field from FormData, which
   doesn't apply to a header button that isn't a form field at all),
   this only needs to look non-interactive, not behave like one — the
   removed data-bs-toggle attribute is what actually disables the click. */
.eightd-header-locked {
  opacity: 0.6;
  cursor: default;
}

/* #710 — the toggle button no longer alone in its own header once a
   Not-applicable checkbox sits beside it (same reason
   .eightd-hypothesis-header-toggle, folded into this now-shared class,
   existed for the Theory card's own Delete button, #576) — it can't
   claim the header's full width the way a lone .canvas-section-header
   assumes. */
.eightd-section-header-shared {
  width: auto;
  flex: 1 1 auto;
}

/* Rich text editors (#447) — a page with several fields showed a full
   CKEditor toolbar on every one of them at once, too crowded; collapsed by
   default and only shown while that specific field has focus (see
   initRichTextEditors() in project.js), plus a bit more editing room than
   CKEditor's own default editable height. !important is warranted here:
   CKEditor injects its own stylesheet into <head> at runtime, after
   project.css has already loaded, so its .ck-toolbar { display: flex }
   wins any same-specificity tie regardless of source order otherwise. */
.ck-toolbar.eightd-toolbar-collapsed {
  display: none !important;
}

.eightd-richtext-editable {
  min-height: 8rem;
}

/* Rendered rich text (#500 follow-up) — a CKEditor-embedded <img> carries
   no width constraint of its own, so it can overflow its container at
   natural pixel size. #500 fixed this inside eightdreport_pdf.html's own
   <style> block (a separate standalone WeasyPrint document), but the
   equivalent rule was never added here for the live site — surfaced again
   on the read-only Detail view (#572), which renders every rich-text
   field via `|safe` with no wrapping constraint. Global, not scoped to one
   template, since any page rendering rich text HTML has the same gap. */
img {
  max-width: 100%;
  height: auto;
}

/* #936 — the rule above is silently ignored for an image pasted inside a
   table the *user* inserted via CKEditor's own table-widget toolbar
   button, inside any rich-text field: CKEditor's own vendored CSS
   deliberately drops the constraint back to none for that specific case
   (`.ck.ck-editor__editable td .image-inline img { max-width: none }`,
   in ckeditor5.css), aimed at its own editing UI. A full-resolution
   oscilloscope screenshot pasted into such a cell rendered at its native
   ~1200px width, which the D4 Theory 5-Whys table (an ordinary HTML
   <table>, not a CKEditor one) then grew to match via its own
   shrink-to-fit column sizing — dragging the *entire page* into
   horizontal scroll, reported as "layout overflow". Same specificity as
   the vendored rule (3 classes, 2 tags) so source order alone would
   settle it (project.css loads after the vendor bundle) — !important
   makes that not have to be relied on. */
.ck.ck-editor__editable :is(td, th) .image-inline img {
  max-width: 100% !important;
}

/* D4 Theory cards' inline 5-Whys table (#449 amendment) — narrow numeric
   "#" column so the Why textarea gets the rest of the row's width.
   table-layout: fixed (#936) stops the column sizing itself off an
   embedded image's natural pixel width in the first place — belt and
   braces alongside the rule above, since that only fixes CKEditor's own
   nested-table case, not e.g. a very long unbroken word/URL. */
.eightd-whystep-table {
  table-layout: fixed;
}

.eightd-whystep-order-col {
  width: 4rem;
}

.eightd-whystep-table .text-end.text-nowrap {
  width: 8rem;
}

/* #944/#945 — the Actions/Tests/Updates/Attachments panels inside a
   D3-D7 section or Theory card (eightd/_action_panel.html,
   actions/_test_panel.html, eightd/_hypothesis_updates_panel.html,
   eightd/_report_updates_panel.html, eightd/_attachment_widget.html)
   share one shape: a list of existing items, then an add-form collapsed
   behind a "+ Add ..." toggle. Several of these stack directly on top of
   each other (Corrective actions, then Attachments, in one D5 section);
   a plain .card would read as "just another card" next to the
   Theory/Action cards already inside it, so it's toned down — lighter
   border, no background tint — to read as a section wrapper instead. */
.eightd-panel-card {
  border-color: #e9ecef;
}

.eightd-panel-card > .card-body {
  padding: 0.75rem 1rem;
}

/* Once expanded, a visible rule separates the add-form from the list
   above it — without this the boundary between "existing items" and
   "the form to add a new one" is exactly the ambiguity #937 reported. */
.eightd-panel-add-form.show {
  margin-top: 0.75rem;
  padding-top: 0.75rem;
  border-top: 1px solid #e9ecef;
}

/* #930/#949 — segmented D0-D8 stage bar, replacing the list page's
   separate "Current stage" text + "Progress" bar (which read as two
   unrelated numbers — percent_complete counts stages *finished* while
   the stage label shows the furthest one merely *started*, and they
   deliberately diverge once work happens out of order, #860). One
   segment per stage says plainly what's done, in progress, skipped, or
   untouched, in one glance. */
.eightd-stage-bar {
  display: flex;
  gap: 2px;
  min-width: 11rem;
}

.eightd-stage-seg {
  flex: 1 1 0;
  text-align: center;
  font-size: 0.65rem;
  line-height: 1.4;
  padding: 0.1rem 0;
  border-radius: 2px;
  cursor: default;
  box-sizing: border-box;
}

/* Thom's own four-state scheme (2026-09-06), replacing the first pass's
   gray/hatched-green: outlined black-on-white for untouched reads as
   "empty" rather than "muted," which a flat gray risked being confused
   with the *skipped* state below — the two need to look nothing alike,
   since one is a real gap and the other is a deliberate decision. */
.eightd-stage-seg-pending {
  background-color: #fff;
  color: #212529;
  border: 1px solid #212529;
}

.eightd-stage-seg-started {
  background-color: #fd7e14;
  color: #fff;
}

.eightd-stage-seg-done {
  background-color: #198754;
  color: #fff;
}

/* "Disabled"/greyed-out, not hatched (the first pass's treatment) — a
   flat, muted fill reads as "switched off" the way a disabled form
   control already does everywhere else on this platform, and is still
   visually distinct from every other state (white outline / orange /
   green) at a glance, which is the actual requirement #942 raised. */
.eightd-stage-seg-skipped {
  background-color: #adb5bd;
  color: #495057;
}

/* Why-step order number (#674, replaced by #826) — the input itself is
   now a HiddenInput (the ↑↓ arrows' JS still writes the real order to it,
   #630); this is the plain <span> label a person actually reads, so no
   form-control-defeating overrides are needed the way the old <input>
   version required. */
.eightd-whystep-order-label {
  display: block;
  color: #6c757d;
  text-align: center;
}

/* Closed action cards (originally eightd's D4 Theory Actions panel, #471,
   generalized in #516 when _action_card.html moved to the shared
   edp/actions app) stay visible inline (rather than collapsed out of
   sight) so their outcome remains in context; dimmed to distinguish them
   from open ones at a glance. */
.action-card-closed {
  opacity: 0.7;
}

/* #798 — persistent per-field hints on the D2 questions. Tighter and
   quieter than Bootstrap's default .form-text, since five of these stack
   in one section and should guide without competing with the answers. */
.eightd-d2-help {
  margin-top: 0.15rem;
  font-size: 0.75rem;
  line-height: 1.35;
  color: #6c757d;
}

/* #810 — the tests heading sat in the same `text-muted small fw-semibold`
   style as every field label in a Theory card (Final root cause,
   Conclusion...), so it did not read as introducing a list of entries.
   Darker, slightly larger, with a rule to mark the section start. */
.eightd-subsection-heading {
  margin: 1rem 0 0.4rem;
  padding-bottom: 0.2rem;
  border-bottom: 1px solid #dee2e6;
  font-size: 0.9rem;
  font-weight: 600;
  color: #343a40;
}

/* #810 — a card's identity line. Action has no title field, so this is the
   description's opening words; the body below repeats them in full, which
   is fine — the point is to make a stack of cards scannable. */
.eightd-entry-title {
  margin: 0;
  font-weight: 600;
  font-size: 0.875rem;
  line-height: 1.35;
  color: #212529;
}

.eightd-entry-title-empty {
  font-weight: 400;
  color: #adb5bd;
}

/* #879 — permalink icon on each detail-page entry card (D3/D5/D6/D7 and
   both Test lists), same hover-reveal shape as .ticket-row-action (#761):
   hidden by default so it adds no permanent visual weight to a page that
   can hold many entries, but not hover-only — :focus-within keeps it
   keyboard-reachable, and (hover: none) pins it visible on touch devices,
   which never fire hover at all. */
.eightd-permalink {
  opacity: 0;
  transition: opacity 0.12s ease-in-out;
  text-decoration: none;
  margin-right: 0.25rem;
}

.eightd-entry:hover .eightd-permalink,
.eightd-entry:focus-within .eightd-permalink {
  opacity: 1;
}

@media (hover: none) {
  .eightd-permalink {
    opacity: 1;
  }
}

/* Detail-view entry cards (#799/#801) — replaces the old action table.
   A test write-up can run to several paragraphs with images; as table
   rows they ran together, and were hard to separate from the 8D's own
   narrative around them. Each entry is now a bordered card with a
   metadata header, so the boundary between entries is unambiguous. */
.eightd-entry-list {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.eightd-entry {
  border: 1px solid #dee2e6;
  border-radius: 0.375rem;
  background-color: #fff;
  overflow: hidden;
}

.eightd-entry-head {
  padding: 0.45rem 0.65rem;
  background-color: #f8f9fa;
  border-bottom: 1px solid #dee2e6;
  font-size: 0.8rem;
}

.eightd-entry-meta-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
  margin-top: 0.2rem;
}

/* Thom, reviewing #810: the metadata read as "pass open thom" - three
   bare words in a row with nothing distinguishing them. Interpuncts
   between items, and the status gets a pill so it does not read as more
   free text next to a person's name. */
.eightd-entry-meta-row > * + * {
  padding-left: 0.5rem;
  border-left: 1px solid #dee2e6;
}

.eightd-entry-meta {
  color: #6c757d;
}

.eightd-entry-status {
  padding: 0.05rem 0.4rem;
  border: 1px solid #ced4da;
  border-radius: 0.25rem;
  background-color: #fff;
  font-weight: 600;
  color: #495057;
}

/* Result leads the header — it is what a reader scans for, and before
   #797 it was not shown at all. Uses the same red/amber/green language as
   the FMEA action-priority badges elsewhere on the platform. */
.eightd-result {
  font-weight: 600;
  padding: 0.05rem 0.4rem;
  border-radius: 0.25rem;
  color: #fff;
}

.eightd-result-pass {
  background-color: #198754;
}

.eightd-result-fail {
  background-color: #dc3545;
}

.eightd-result-inconclusive {
  background-color: #fd7e14;
}

.eightd-entry-body {
  padding: 0.55rem 0.65rem;
}

.eightd-entry-body > :last-child {
  margin-bottom: 0;
}

/* Thom, reviewing #810: this had a grey ground and a small bold label,
   which made it read as a second header rather than as the outcome of the
   entry above it. Now plain body ground, set off by an accent rule on the
   left and an inline label. */
.eightd-entry-notes {
  margin: 0 0.65rem 0.55rem;
  padding: 0.35rem 0 0.35rem 0.6rem;
  border-left: 3px solid #dee2e6;
  background-color: transparent;
}

.eightd-entry-notes-label {
  display: inline;
  margin-right: 0.35rem;
  font-weight: 600;
  color: #6c757d;
}

.eightd-entry-notes-label::after {
  content: ":";
}

.eightd-entry-notes > :last-child {
  margin-bottom: 0;
}

/* D2 — Problem Description (#478): fixed-width label, field takes the
   rest. A percentage split squeezed the label down to an unreadable
   sliver as the window narrowed, since it shrank right along with the
   field instead of staying legible. */
.eightd-d2-label {
  flex: 0 0 auto;
  width: 8rem;
}

/* flex-basis: 0% (not auto), #498: with flex-basis: auto a flex item's
   *content* size is what decides whether flex-wrap: wrap moves it to a
   new line — min-width: 0 and flex-shrink only apply to sizing after
   that line-assignment decision has already been made, so long CKEditor
   content (which easily fits once given the row's actual width) was
   still wrapping the field below the label purely because its unwrapped
   content size looked too wide at decision time. flex-basis: 0 makes the
   item start from zero and grow to fill the remaining space instead,
   sidestepping content size entirely for the wrap decision. */
.eightd-d2-field {
  flex: 1 1 0%;
  width: auto;
  min-width: 0;
}

/* #491 — Bootstrap's w-auto sizes a <select> to fit its widest option's
   content, which for a "Link an existing test…" picker (candidate
   description + source label) can exceed the theory card's own width and
   overflow past the page's right edge. Flex items also default to
   min-width: auto (not 0), so plain flex-shrink alone doesn't fix it —
   same root cause as .eightd-d2-field above, just on a <select> instead
   of a rich-text field. */
.test-link-select {
  flex: 1 1 auto;
  min-width: 0;
}

/* #645 — the 8D list view's per-branch sub-rows, shown indented under
   their parent report row once it has genuinely split into >1 branch. */
.eightd-branch-row {
  background-color: var(--bs-tertiary-bg);
}

.eightd-branch-row td:first-child {
  padding-left: 2rem;
}

/* #645 follow-up — the read-only D0-D3 recap on a specific branch's own
   edit page (eightd_branch_form.html) needs to visually read as "not
   editable here" at a glance, distinct from the editable D4-D8 body
   below it on the same page — muted background + reduced opacity keeps
   the content fully readable while making the non-interactive state
   obvious without relying on the reader noticing there's no <input>. */
.eightd-readonly-context {
  background-color: var(--bs-tertiary-bg);
  opacity: 0.85;
  border-radius: 0.375rem;
  padding: 0.5rem;
  margin-bottom: 1rem;
}

/* #423 — platform feedback floating button, fixed bottom-right on every
   authenticated page (base.html). z-index above the sticky navbar (which
   defaults to Bootstrap's own 1020) so it stays clickable over any page's
   own sticky headers/sidebars, but below Bootstrap's own offcanvas panel
   (1045) so it's naturally covered once the feedback panel opens. */
.feedback-widget-btn {
  position: fixed;
  right: 1.5rem;
  bottom: 1.5rem;
  z-index: 1030;
  border-radius: 2rem;
  box-shadow: 0 0.25rem 0.75rem rgba(0, 0, 0, 0.25);
}

/* #423 follow-up — a pasted screenshot renders small at Bootstrap's own
   offcanvas default width (400px, images are already capped to their
   container's width platform-wide, #612), but a wider default risks
   covering the very bug the panel is meant to help report. Rather than
   guess at one right answer, the width is user-draggable (see
   .feedback-resize-handle + initFeedbackResizeHandle() in project.js,
   which sets this same custom property live and remembers the choice in
   localStorage) — this value is only the first-ever-visit default.
   offcanvas already carries its own max-width: 100%, so this still
   degrades gracefully on narrow viewports regardless of the stored
   preference. */
.feedback-offcanvas {
  --bs-offcanvas-width: 28rem;
}

/* Drag handle on the panel's left edge (the panel is right-anchored, so
   this is the only edge that can meaningfully resize it) — deliberately a
   custom drag implementation rather than the CSS `resize` property: a
   `resize`d box grows from its bottom-right corner, which fights a
   right-anchored fixed-position element (the box would grow off the right
   edge of the viewport, not the left, undoing the anchor). */
.feedback-resize-handle {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  width: 6px;
  cursor: ew-resize;
  z-index: 1;
}

.feedback-resize-handle:hover,
.feedback-resize-handle.is-dragging {
  background-color: var(--bs-primary);
  opacity: 0.35;
}

/* Same root cause as .eightd-richtext-editable's own min-height (#447) —
   CKEditor's default editable height reads as "very low" — but this field
   is the panel's only content, with the whole offcanvas height to use, so
   it gets noticeably more room than a field embedded among several others
   on a normal page. Applied by createFeedbackEditor() in project.js, not
   the shared initRichTextEditors() — see that function's own comment for
   why the feedback panel can't reuse the shared init path. */
.feedback-richtext-editable {
  min-height: 20rem;
}

/* The placeholder is one long sentence, rendered as a ::before
   pseudo-element (content: attr(data-placeholder)) on the empty
   paragraph — CKEditor's own injected stylesheet sets white-space on it
   directly, so the fix has to target that ::before specifically, not rely
   on inheriting a value set on the outer editable div above. !important is
   warranted for the same reason .ck-toolbar.eightd-toolbar-collapsed
   needs it just above: CKEditor injects its stylesheet into <head> at
   runtime, after project.css has already loaded, so it wins any
   same-specificity tie regardless of source order otherwise. */
.feedback-richtext-editable .ck-placeholder::before {
  white-space: normal !important;
  overflow-wrap: break-word !important;
  word-break: break-word !important;
}

/* #816 — the Tests dashboard reads as an indented tree inside one table:
   8D → theory → the tests themselves. Hierarchy is carried by indentation
   plus a font that gets progressively lighter and smaller as it nests,
   rather than by the blue .canvas-section-header bars the 8D pages use —
   on a list of many 8Ds those read as heavy repeated banners, and the
   font ran big-bold → small-bold-underlined → normal-bigger, which
   inverted the hierarchy it was meant to show. */
.tests-doc-row td {
  background-color: var(--bs-tertiary-bg);
  border-top: 2px solid var(--bs-border-color);
  font-size: 1rem;
  font-weight: 700;
}

.tests-theory-row td {
  padding-left: 1.5rem;
  font-size: 0.9rem;
  font-weight: 600;
}

/* Underlined-by-default made the theory line noisier than the 8D above
   it; the link affordance moves to hover instead. */
.tests-tree-link {
  color: inherit;
  text-decoration: none;
}

.tests-tree-link:hover {
  text-decoration: underline;
}

/* Report-level Tests belong to the 8D itself, so they sit level with a
   theory heading; a theory's own tests indent one step further again.

   Qualified with `td` deliberately: Bootstrap's own cell padding rule is
   `.table > :not(caption) > * > *`, specificity (0,1,1). A bare
   `.tests-indent-3` is (0,1,0) and loses to it, so the test rows kept
   Bootstrap's default padding and sat *left* of the theory heading above
   them - the reverse of the nesting. `.tests-theory-row td` already
   matched at (0,1,1) and won on load order, which is why only the theory
   level appeared to work. */
td.tests-indent-2 {
  padding-left: 1.5rem;
}

td.tests-indent-3 {
  padding-left: 3rem;
}

/* #816 — anchor targets on an 8D detail/branch page. A #action-<pk> or
   #hypothesis-card-<pk> link from the Tests dashboard scrolls its target
   flush to the top of the viewport, which is exactly where
   .eightd-page-header-sticky sits — so the entry's own title strip ended
   up behind the header and the description appeared to start mid-way.
   --eightd-sticky-offset is measured in initEightdStickyOffsets() (the
   header's height varies with title length and viewport width, so it
   cannot be a fixed value here); the fallback matches the sidebar's own
   and only applies for the browser's initial jump, before the measurement
   lands. */
.eightd-entry,
.eightd-anchor-target {
  scroll-margin-top: calc(var(--eightd-sticky-offset, 9.25rem) + 0.75rem);
}

/* #822 — a search result reads as a tree: document → section → match.
   The first cut listed matches flat and repeated the section's full name
   on every one of them, so a report with six theories printed the same
   bold "Theory 6 — …" line four times over. The section name is printed
   once here and each match carries only its own leaf label. */
.search-section {
  margin-top: 0.5rem;
}

.search-section-head {
  display: block;
  font-size: 0.85rem;
  font-weight: 600;
  padding-left: 0.75rem;
  border-left: 2px solid var(--bs-border-color);
}

/* Whole line clickable, so the hit area is the text you are reading rather
   than the small label at its start. */
.search-match {
  display: block;
  font-size: 0.875rem;
  padding: 0.15rem 0.25rem 0.15rem 2rem;
  border-left: 2px solid var(--bs-border-color);
  border-radius: 0.2rem;
}

a.search-match:hover,
a.search-section-head:hover {
  background-color: var(--bs-tertiary-bg);
  text-decoration: none;
}

.search-match-label {
  font-weight: 600;
  color: var(--bs-secondary-color);
  margin-right: 0.4rem;
  white-space: nowrap;
}

.search-tree-link {
  color: inherit;
  text-decoration: none;
}

.search-tree-link:hover {
  text-decoration: underline;
}

.search-match-snippet mark {
  padding: 0 0.1rem;
}

/* #822 — navbar search. The results panel is absolutely positioned under
   the input rather than using a Bootstrap dropdown, because its content is
   swapped in by HTMX and a Bootstrap dropdown expects to own show/hide
   itself. z-index sits above the sticky page headers the 8D pages use
   (10) and above the navbar (1020), but below the feedback offcanvas. */
.search-navbar-form {
  max-width: 260px;
}

.search-navbar-input {
  min-width: 140px;
}

.search-navbar-results {
  position: absolute;
  top: 100%;
  right: 0;
  left: 0;
  z-index: 1030;
}

.search-dropdown-panel {
  margin-top: 0.25rem;
  background: var(--bs-body-bg);
  border: 1px solid var(--bs-border-color);
  border-radius: 0.375rem;
  box-shadow: 0 0.5rem 1rem rgb(0 0 0 / 15%);
  overflow: hidden;
  min-width: 320px;
}

.search-dropdown-item {
  display: block;
  padding: 0.4rem 0.6rem;
  color: inherit;
  text-decoration: none;
  border-bottom: 1px solid var(--bs-border-color);
}

.search-dropdown-item:hover {
  background: var(--bs-tertiary-bg);
}

.search-dropdown-doc {
  display: block;
  font-size: 0.8rem;
  font-weight: 600;
}

.search-dropdown-meta {
  font-size: 0.7rem;
  color: var(--bs-secondary-color);
}

.search-dropdown-snippet {
  display: block;
  font-size: 0.75rem;
  color: var(--bs-secondary-color);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.search-dropdown-empty,
.search-dropdown-all {
  display: block;
  padding: 0.4rem 0.6rem;
  font-size: 0.78rem;
}

.search-dropdown-all {
  color: inherit;
  text-decoration: none;
  font-weight: 600;
}

.search-dropdown-all:hover {
  background: var(--bs-tertiary-bg);
}

/* #878 — ticket edit page: the Attachments card must be a sibling <form>
   of #ticket-form (nested <form> tags are invalid HTML), but should render
   directly under the main card rather than below the whole row, which is
   as tall as the sidebar (ten fields, including two 8-row multi-selects —
   much taller than the three-field main card). A plain Bootstrap row/col
   stretches both columns to that height, so anything appended afterward
   starts below the sidebar, not the shorter card.
   ticket-edit-form gets display:contents so #ticket-form's own box is
   removed from layout entirely and its children (ticket-edit-main,
   ticket-edit-sidebar) become direct items of this grid, sized/placed
   exactly like ticket-edit-attachments (a true sibling of the form) —
   the form still wraps the same fields as before; only their visual
   position changes. */
.ticket-edit-layout {
  display: grid;
  grid-template-columns: 2fr 1fr;
  grid-template-areas: "main sidebar" "attach sidebar";
  gap: 1rem;
}

.ticket-edit-form {
  display: contents;
}

.ticket-edit-main {
  grid-area: main;
}

.ticket-edit-sidebar {
  grid-area: sidebar;
}

.ticket-edit-attachments {
  grid-area: attach;
  align-self: start;
}

/* The sidebar partial is shared with the create page's own plain
   Bootstrap row, where its col-lg-4 width is load-bearing — cancelled
   here since this grid's own column track does that job instead. */
.ticket-edit-sidebar > .col-lg-4 {
  width: 100%;
  max-width: 100%;
  flex: 1 1 auto;
}

@media (max-width: 991.98px) {
  .ticket-edit-layout {
    grid-template-columns: 1fr;
    grid-template-areas: "main" "attach" "sidebar";
  }
}
