/* Questionnaire Builder — uses CCMAR design tokens (variables.css) for theme parity. */

/* ---------- Library ---------- */
.row-actions {
    display: flex;
    gap: var(--space-1);
}

.btn-mini {
    padding: var(--space-1) var(--space-2);
    font-size: var(--text-xs);
    font-family: inherit;
    background: var(--bg-surface);
    color: var(--text-primary);
    border: 1px solid var(--border-input);
    border-radius: var(--radius-sm);
    cursor: pointer;
    transition: background var(--duration-fast) var(--ease-default),
                border-color var(--duration-fast) var(--ease-default);
}
.btn-mini:hover {
    background: var(--bg-surface-hover);
    border-color: var(--border-hover);
}
.btn-mini-active,
.btn-mini-active:hover {
    background: var(--accent-muted);
    border-color: var(--accent);
    color: var(--accent-text);
    font-family: var(--font-mono);
}

.modal-actions {
    display: flex;
    justify-content: flex-end;
    gap: var(--space-2);
}

/* ---------- Importer ---------- */
.drop-zone {
    border: 2px dashed var(--border-input);
    border-radius: var(--radius-lg);
    padding: var(--space-8);
    text-align: center;
    cursor: pointer;
    background: var(--bg-surface);
    color: var(--text-secondary);
    transition: background var(--duration-fast) var(--ease-default),
                border-color var(--duration-fast) var(--ease-default);
}
.drop-zone:hover,
.drop-zone.drag-over {
    border-color: var(--accent);
    background: var(--accent-muted);
    color: var(--text-primary);
}

.import-summary {
    padding: var(--space-2) 0;
    font-size: var(--text-sm);
    color: var(--text-secondary);
}
.import-summary strong { color: var(--text-primary); }
.warn-text { color: var(--warning-text); }
.ok-text   { color: var(--success-text); }

.import-warnings ul {
    margin: var(--space-2) 0;
    padding-left: var(--space-5);
    font-family: var(--font-mono);
    font-size: var(--text-xs);
}
.import-warnings li {
    color: var(--warning-text);
    margin-bottom: var(--space-1);
}

.q-preview-list {
    font-family: var(--font-mono);
    font-size: var(--text-xs);
    max-height: 360px;
    overflow-y: auto;
    padding-left: var(--space-6);
    color: var(--text-secondary);
}
.q-preview-list li { margin-bottom: var(--space-1); }
.q-preview-list code {
    background: var(--bg-surface);
    color: var(--accent-text);
    padding: 1px var(--space-1);
    border-radius: var(--radius-xs);
}
.q-preview-section { color: var(--text-tertiary); }

/* ---------- Builder shell (two columns, independent scrolls) ----------
   - Width breaks out of .main-content-inner's max-width so the editor uses the
     full available body width.
   - The shell fills the available vertical space inside .main-content-inner.
   - Each column has its own internal overflow — neither scrolls the page. */
.main-content-inner:has(.qb-shell) {
    max-width: none;
    height: 100%;
    display: flex;
    flex-direction: column;
    min-height: 0;
}

.qb-shell {
    flex: 1;
    min-height: 0;
    display: grid;
    grid-template-columns: 280px 1fr;
    gap: var(--space-4);
    align-items: stretch;
}
@media (max-width: 900px) {
    .qb-shell { grid-template-columns: 1fr; }
}

.qb-outline,
.qb-editor {
    background: var(--bg-surface);
    border: 1px solid var(--border-primary);
    border-radius: var(--radius-md);
    padding: var(--space-4);
    overflow-y: auto;
    min-height: 0;
}

.qb-outline h3,
.qb-editor h3,
.qb-skiplogic h4 {
    margin: 0 0 var(--space-3);
    font-size: var(--text-xs);
    color: var(--text-secondary);
    text-transform: uppercase;
    letter-spacing: var(--tracking-wide);
    font-weight: var(--weight-semibold);
}

/* Editor header bar — title left, icon-buttons right (preview, trash). */
.qb-editor-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: var(--space-3);
}
.qb-editor-header h3 { margin: 0; }
.qb-header-actions { display: flex; gap: var(--space-1); }
.qb-header-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: var(--space-1) var(--space-2);
    line-height: 1;
}
.qb-header-icon-danger {
    color: var(--danger-text);
    border-color: var(--danger-muted);
}
.qb-header-icon-danger:hover {
    background: var(--danger-muted);
    border-color: var(--danger);
    color: var(--danger);
}

/* Skip-logic block — sits inside the Skip Logic card-body. The card itself
   provides the visual boundary; no extra margin/padding/border-top here. */
.qb-skiplogic {
    margin-top: 0;
    padding-top: 0;
    border-top: 0;
}

/* Outline */
.qb-section { margin-bottom: var(--space-4); }
.qb-section-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    cursor: pointer;   /* click the header to collapse/expand the section */
    padding: var(--space-1) var(--space-2);
    background: var(--bg-secondary);
    border-radius: var(--radius-sm);
    margin-bottom: var(--space-2);
    /* Pin to the top of the scrolling outline panel as the user scrolls
       through long sections — keeps the section name + add buttons in
       reach without scrolling back up. Each .qb-section is its own
       sticky containing block, so the active section's header naturally
       replaces the previous one as scroll moves between sections. */
    position: sticky;
    top: 0;
    z-index: 5;
}
.qb-section-name {
    font-weight: var(--weight-semibold);
    color: var(--text-primary);
    font-size: var(--text-sm);
}
/* Caret + name grouped on the left of the (space-between) section header. */
.qb-section-title {
    display: flex;
    align-items: center;
    gap: var(--space-1);
    min-width: 0;
}
.qb-section-caret {
    color: var(--text-tertiary);
    font-size: var(--text-xs);
    user-select: none;
    line-height: 1;
}
/* Collapsed section: hide ONLY its own top-level list (not nested block-children,
   which manage their own data-collapsed). The header stays visible. */
.qb-section[data-collapsed="1"] > .qb-q-list { display: none; }

.qb-q-list {
    list-style: none;
    margin: 0;
    padding: 0;
}
.qb-q-item {
    padding: var(--space-2) var(--space-2);
    cursor: pointer;
    border-radius: var(--radius-sm);
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: var(--space-2);
    font-size: var(--text-sm);
    transition: background var(--duration-fast) var(--ease-default);
    color: var(--text-primary);
    /* No accidental text selection while dragging or click-selecting rows. */
    user-select: none;
}
/* Question drag handle in the outline. Same affordance as the option-row
   handle: ⋮⋮ glyph with a grab cursor on hover. Hidden in read-only mode.
   The padding/negative-margin pair extends the click target into the
   surrounding row gap (~20 × 24 px hit area) without nudging the row's
   outer dimensions. */
.qb-q-drag {
    cursor: grab;
    color: var(--text-tertiary);
    user-select: none;
    font-size: 14px;
    line-height: 1;
    letter-spacing: -2px;
    flex-shrink: 0;
    padding: 4px 6px;
    margin: -4px -6px;
}
.qb-q-drag:hover  { color: var(--text-primary); }
.qb-q-drag:active { cursor: grabbing; }
.qb-q-item:hover { background: var(--bg-surface-hover); }
.qb-q-item.selected {
    background: var(--accent-muted);
    color: var(--accent-text);
}
.qb-q-varname {
    font-family: var(--font-mono);
    color: var(--accent-text);
    white-space: nowrap;
    /* Varname always shows in full — the type label takes the hit if the
       row gets squeezed. */
    flex: 0 0 auto;
    text-align: left;
}
.qb-q-type {
    color: var(--text-tertiary);
    font-size: var(--text-xs);
    font-style: italic;
    /* Take whatever space is left and shrink first when the row narrows.
       text-align:right + ellipsis truncates from the START (so we keep the
       most distinctive part of the type — the suffix — visible). */
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    text-align: right;
}
.qb-add-section {
    margin-top: var(--space-3);
    width: 100%;
}

/* Section heading inside the options card — used by matrix to label its
   Rows / Columns sub-tables. */
.qb-options-subtitle {
    margin: var(--space-3) 0 var(--space-2);
    font-size: var(--text-sm);
    font-weight: var(--weight-semibold);
    color: var(--text-secondary);
}
.qb-options-subtitle:first-child { margin-top: 0; }

/* Block grouping in the outline.
   - .qb-q-item-block         block header row (caret + varname + count)
   - .qb-q-block-children     nested <ul> with vertical bar on the left
   - .qb-q-block-empty        empty drop placeholder shown when block has no children
   - .qb-q-item-child         child rows (just slightly tinted for hierarchy)
   - .qb-q-drop-indicator     thin colored insertion line shown during drag
   - .qb-q-droptarget         highlight the target list while dragging over it
   - .qb-q-dragging           the row currently being dragged */
.qb-q-item-block {
    background: var(--bg-tertiary);
    font-weight: var(--weight-semibold);
}
.qb-q-item-block:hover { background: var(--bg-surface-hover); }
.qb-q-block-caret {
    cursor: pointer;
    color: var(--text-secondary);
    user-select: none;
    flex-shrink: 0;
    font-size: 11px;
    width: 14px;
    text-align: center;
}
.qb-q-block-caret:hover { color: var(--text-primary); }

.qb-q-block-children {
    border-left: 3px solid var(--accent-primary);
    margin-left: 10px;
    padding-left: 10px;
    margin-bottom: var(--space-1);
}
.qb-q-block-children[data-collapsed="1"] { display: none; }

.qb-q-item-child {
    /* Slight visual sub-step so children read as nested. */
    padding-left: var(--space-3);
}

.qb-q-block-empty {
    padding: var(--space-2) var(--space-3);
    color: var(--text-tertiary);
    font-style: italic;
    font-size: var(--text-xs);
    border: 1px dashed var(--border-secondary);
    border-radius: var(--radius-sm);
    text-align: center;
    list-style: none;
}

.qb-q-droptarget {
    background: var(--bg-surface-hover);
}

/* Other-specify children: smaller indent, muted left-bar tint to distinguish
   from block children. These rows are auto-managed (created when an option's
   is_other flag flips on) and aren't draggable. */
.qb-q-other-children {
    border-left: 2px dashed var(--text-tertiary);
    margin-left: 14px;
    padding-left: 10px;
    margin-bottom: var(--space-1);
}
.qb-q-item-other {
    font-size: var(--text-xs);
    opacity: 0.85;
}
.qb-q-item-other .qb-q-type {
    color: var(--accent-text);
    font-style: normal;
}
/* Floating drop indicator — single shared element managed by
   wireSectionDragDrop. position:fixed so it doesn't shift layout; a
   bright accent line at the row's top/bottom edge shows exactly where
   the drop will land. */
.qb-drag-indicator {
    position: fixed;
    height: 3px;
    background: var(--accent-primary);
    pointer-events: none;
    z-index: 9999;
    display: none;
    border-radius: 2px;
    box-shadow: 0 0 6px var(--accent-primary);
}
.qb-q-dragging {
    opacity: 0.4;
}
/* Section +V / +B add-buttons double as drag handles: click appends at the end,
   drag drops the new item at a specific spot (reuses .qb-drag-indicator). */
.qb-add-drag {
    cursor: grab;
}
.qb-add-drag:active {
    cursor: grabbing;
}

/* Per-type-config: read-only block child summary. */
.qb-block-child-summary {
    list-style: none;
    margin: 0;
    padding: 0;
}
.qb-block-child-summary li {
    display: flex;
    justify-content: space-between;
    gap: var(--space-2);
    padding: var(--space-1) var(--space-2);
    background: var(--bg-secondary);
    border-radius: var(--radius-sm);
    margin-bottom: var(--space-1);
    font-size: var(--text-sm);
}
.qb-block-child-vn {
    font-family: var(--font-mono);
    color: var(--accent-text);
}
.qb-block-child-ft {
    color: var(--text-tertiary);
    font-size: var(--text-xs);
    font-style: italic;
}

/* Editor */
.qb-empty {
    color: var(--text-tertiary);
    text-align: center;
    padding: var(--space-8) var(--space-4);
    font-style: italic;
}
.qb-loading {
    padding: var(--space-10);
    text-align: center;
    color: var(--text-tertiary);
}

.form-group { margin-bottom: var(--space-3); }
.form-group label {
    display: block;
    font-size: var(--text-xs);
    color: var(--text-secondary);
    margin-bottom: var(--space-1);
}
.form-input {
    width: 100%;
    padding: var(--space-2) var(--space-3);
    background: var(--bg-input);
    color: var(--text-primary);
    border: 1px solid var(--border-input);
    border-radius: var(--radius-sm);
    font: inherit;
    font-size: var(--text-sm);
    transition: border-color var(--duration-fast) var(--ease-default);
}
.form-input-sm { padding: var(--space-1) var(--space-2); font-size: var(--text-xs); }
.form-input:focus {
    outline: none;
    border-color: var(--border-focus);
    box-shadow: 0 0 0 3px var(--accent-glow);
}
/* QB used to override .form-row globally to force flex / equal-width children
   for its own modals (function editor, rule condition rows). That leaked
   site-wide and broke bid / job forms which rely on the grid form-row from
   components.css. The few QB call sites that need flex now opt in via the
   `.qb-flex-row` class below; everything else inherits the standard grid. */
.qb-flex-row {
    display: flex;
    gap: var(--space-2);
    align-items: center;
}
.qb-flex-row > * { flex: 1; }
.inline-checkbox {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    font-size: var(--text-sm);
    cursor: pointer;
    color: var(--text-primary);
}

.qb-options-table {
    width: 100%;
    border-collapse: collapse;
    margin-top: var(--space-2);
    font-size: var(--text-sm);
    table-layout: auto;
}
.qb-options-table th,
.qb-options-table td {
    padding: var(--space-1) var(--space-2);
    border-bottom: 1px solid var(--border-secondary);
    text-align: center;       /* default: center everything */
    vertical-align: middle;
}
.qb-options-table th {
    background: var(--table-header-bg);
    color: var(--text-secondary);
    font-weight: var(--weight-medium);
    font-size: var(--text-xs);
}
/* Zebra-stripe the option rows so authors can scan long option lists by
   row pair. Even rows pick up the table-row-stripe token, odd rows stay
   on the surrounding card background. Using tbody > tr targets only the
   data rows (skips the thead). The :hover rule below still wins for the
   row currently under the cursor. */
.qb-options-table tbody > tr:nth-child(even) > td {
    background: var(--table-row-stripe, rgba(255, 255, 255, 0.025));
}
.qb-options-table tr:hover td { background: var(--table-row-hover); }
/* Drag handle column: narrow, just enough for the ⋮⋮ glyph + a click target.
   Code: fixed; Vis / × columns: narrow.
   Label: fluid but capped via 40% so the Flags cell has room to breathe.
   Flags: holds the dropdown + any active badges, wraps onto a second line on
   narrow screens. */
.qb-options-table .col-drag  { width: 24px; padding-left: 0; padding-right: 0; }
.qb-options-table .col-code  { width: 110px; }
.qb-options-table .col-code .form-input { text-align: center; }
.qb-options-table .col-label { width: 40%; }
.qb-options-table .col-flags { min-width: 280px; }
.qb-options-table .col-flag  { width: 70px; white-space: nowrap; }

/* Shared Quill snow toolbar for option-label cells. Sits above the
   options table; one toolbar applies to whichever option cell currently
   has focus. Same button set as the question-label editor so authors
   get a consistent formatting UX across all rich-text fields. */
.qb-opt-shared-toolbar {
    margin-bottom: var(--space-2);
    border-radius: var(--radius-md);
    /* Quill's quill.snow.css already styles .ql-toolbar; just tighten
       the visual nesting in the options-table card. */
}

/* Option-label cell hosting a Quill snow editor. Cell looks like a
   compact input until clicked. Single-line, scrolls horizontally for
   long labels. Quill's default min-height (~150px) is overridden so
   the table row stays at the original input-row height. */
.qb-opt-label-rt {
    padding: 0 !important;
    min-height: 28px;
    height: 28px;
    text-align: left;
    cursor: text;
    overflow: visible;
    box-sizing: border-box;
}
.qb-opt-label-rt .ql-container {
    border: none !important;
    height: 100% !important;
    min-height: 0 !important;
    font-family: inherit !important;
    font-size: inherit !important;
    overflow: visible;
}
.qb-opt-label-rt .ql-editor {
    min-height: 0 !important;
    padding: 4px 8px !important;
    line-height: 1.4;
    font-family: inherit;
    font-size: inherit;
    height: 100%;
    overflow-x: auto;
    overflow-y: hidden;
    white-space: nowrap;
}
.qb-opt-label-rt .ql-editor.ql-blank::before {
    left: 8px;
    font-style: italic;
    line-height: 1.4;
    color: var(--text-muted, #9ca3af);
}
/* Quill's link-edit popup floats above the editor when the user clicks
   the link button — make sure it sits on top of adjacent table rows. */
.qb-opt-label-rt .ql-tooltip {
    z-index: 100;
}

/* Read-only option cells — plain text so the user can drag-select across
   rows/columns and copy-paste the table elsewhere (browsers extract a
   tab-separated representation by default). Visually they sit at roughly
   the same height as the disabled inputs in edit mode so toggling modes
   doesn't shift the row. */
.qb-opt-readonly-cell {
    display: block;
    padding: 4px 6px;
    color: var(--text-primary);
    font-size: var(--text-sm);
    line-height: 1.4;
    min-height: 22px;
    user-select: text;
    cursor: text;
    white-space: pre-wrap;
    word-break: break-word;
}
.qb-opt-readonly-code  { text-align: center; font-family: var(--font-mono); }
.qb-opt-readonly-label { text-align: left; }

/* Read-only flags cell — single-line plain text so it doesn't break the
   copy output into multiple lines per row. */
.qb-opt-flags-readonly {
    display: block;
    padding: 4px 6px;
    color: var(--text-primary);
    font-size: var(--text-sm);
    line-height: 1.4;
    user-select: text;
    white-space: pre-wrap;
    word-break: break-word;
}

/* Drag handle — vertical-dot affordance. Cursor flips to "move" on hover so
   the user knows it's draggable; the rest of the row stays text-selectable
   because draggable=true is only set on the handle. */
.qb-opt-drag-handle {
    cursor: grab;
    color: var(--text-tertiary);
    user-select: none;
    font-size: 16px;
    line-height: 1;
    letter-spacing: -2px;     /* tighten the two dots so they read as one glyph */
}
.qb-opt-drag-handle:hover {
    color: var(--text-primary);
}
.qb-opt-drag-handle:active {
    cursor: grabbing;
}
/* Inputs in cells stay left-aligned for natural typing, except the code (centered above). */
.qb-options-table td input[type="text"] { text-align: left; }
.qb-options-table .col-code input[type="text"] { text-align: center; }

/* Flags cell — dropdown sits inline with the badges, wrapping when the row
   gets crowded. Badges are pill-shaped with a clickable × that visually
   separates from the label so the affordance is obvious. */
.qb-opt-flags-cell {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-1);
    align-items: center;
    justify-content: flex-start;
}
.qb-opt-flag-badge {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 2px 6px 2px 8px;
    background: var(--bg-elevated);
    border: 1px solid var(--border-primary);
    border-radius: 999px;
    font-size: var(--text-xs);
    color: var(--text-primary);
    white-space: nowrap;
}
.qb-opt-flag-x {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 14px;
    height: 14px;
    border-radius: 50%;
    cursor: pointer;
    color: var(--text-secondary);
    line-height: 1;
}
.qb-opt-flag-x:hover {
    background: var(--accent-subtle, rgba(255,255,255,0.08));
    color: var(--text-primary);
}
.qb-opt-flag-select {
    width: auto;
    min-width: 130px;
    max-width: 180px;
}

.btn-danger {
    background: var(--danger);
    color: var(--text-on-accent);
    border: none;
    padding: var(--space-2) var(--space-3);
    border-radius: var(--radius-sm);
    cursor: pointer;
    font: inherit;
}
.btn-danger:hover { background: var(--danger); filter: brightness(1.1); }

/* Rule editor: condition row inside a group card. Grid layout so every row
   lines up under the same columns — the first condition leaves the AND/OR
   and × slots empty so subsequent rows' LHS / op / RHS still sit directly
   below the first row's. align-items:end keeps the op dropdown bottom level
   with the LHS/RHS input baselines (LHS/RHS are taller because of the
   mode-toggle row above their input). */
.rule-cond-row {
    display: grid;
    grid-template-columns: 70px minmax(0, 1fr) 110px minmax(0, 1fr) 32px;
    gap: var(--space-2);
    align-items: end;
}
.rule-cond-slot-empty { /* layout placeholder, no visible content */ }
.rule-cond-x { justify-self: center; }

/* Multiple-group editor — each group is a subtle card with its own conditions. */
.rule-groups {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    margin-bottom: var(--space-3);
}
.rule-group-card {
    border: 1px solid var(--border-secondary);
    border-radius: var(--radius-md);
    padding: var(--space-3);
    background: var(--bg-input);
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}
.rule-group-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: var(--space-1);
}
.rule-group-label {
    font-size: var(--text-xs);
    color: var(--text-secondary);
    text-transform: uppercase;
    letter-spacing: var(--tracking-wide);
    font-weight: var(--weight-semibold);
}
/* Inter-group AND/OR connector — sits ON ITS OWN ROW between two cards. */
.rule-group-connector-row {
    display: flex;
    justify-content: flex-start;
    margin: 0;
}
.rule-group-connector {
    flex: 0 0 90px;
    text-transform: uppercase;
    letter-spacing: var(--tracking-wide);
    font-weight: var(--weight-semibold);
    color: var(--accent-text);
}
.rule-conn-sel {
    flex: 0 0 70px;
    text-transform: uppercase;
    letter-spacing: var(--tracking-wide);
    font-weight: var(--weight-semibold);
}
.rule-add-group {
    align-self: flex-start;
    margin-top: var(--space-1);
}
/* "Then" row sits below the groups — same shape as the After row. */
.rule-then-row {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    margin-top: var(--space-2);
}
.rule-then-row .rule-then-label { padding-bottom: 0; }
.rule-then-label {
    font-size: var(--text-xs);
    color: var(--text-secondary);
    text-transform: uppercase;
    letter-spacing: var(--tracking-wide);
    font-weight: var(--weight-semibold);
    flex: 0 0 auto;
    padding-bottom: var(--space-2);
}
.rule-action-sel { flex: 0 0 140px; }

/* After-action row, sits at the bottom of the rule form on its own line. */
.rule-after-row {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    margin-top: var(--space-2);
}
.rule-after-row .rule-then-label { padding-bottom: 0; }
.rule-after-row .rule-action-sel { flex: 0 0 240px; }

/* Rail (skip logic) */
.qb-rail-help {
    font-size: var(--text-xs);
    color: var(--text-tertiary);
    margin-bottom: var(--space-3);
}
.qb-rail-help code,
.qb-pipe-help code {
    background: var(--bg-secondary);
    color: var(--accent-text);
    padding: 1px var(--space-1);
    border-radius: var(--radius-xs);
    font-family: var(--font-mono);
}

/* Collapsed "Piping variables" reference at the bottom of the question editor. */
.qb-pipe-help {
    margin-top: var(--space-3);
    font-size: var(--text-xs);
    color: var(--text-tertiary);
}
.qb-pipe-help summary {
    cursor: pointer;
    color: var(--text-secondary);
    user-select: none;
}
.qb-pipe-help-body { margin-top: var(--space-2); }
.qb-pipe-help-body p { margin: var(--space-2) 0; }

.qb-rules {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    margin-bottom: var(--space-3);
}
.qb-rule-card {
    border: 1px solid var(--border-primary);
    border-radius: var(--radius-md);
    padding: var(--space-3);
    background: var(--bg-secondary);
}
.qb-rule-head {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: var(--space-2);
    margin-bottom: 0;
    min-height: 0;
}
.qb-rule-form { display: flex; flex-direction: column; gap: var(--space-2); }
.qb-rule-fields { display: flex; flex-direction: column; gap: var(--space-2); }

/* "Saved" indicator that flashes after each auto-save. */
.qb-rule-saved {
    flex: 1;
    font-size: var(--text-xs);
    color: var(--success-text);
    opacity: 0;
    transition: opacity var(--duration-normal) var(--ease-default);
}
.qb-rule-saved.show { opacity: 1; }
.qb-rule-saved.is-error { color: var(--danger-text); }

.help {
    color: var(--text-secondary);
    font-size: var(--text-sm);
    margin-bottom: var(--space-3);
}

/* ---------- Questionnaire issues modal (header "⚠ N issues") ---------- */
.qb-issues-group { margin-bottom: var(--space-4); }
.qb-issues-group-title {
    font-size: var(--text-sm);
    font-weight: 600;
    color: var(--text-secondary);
    margin-bottom: var(--space-2);
}
.qb-issue-row {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-2) 0;
    border-top: 1px solid var(--border-secondary);
}
.qb-issue-row .qb-flag-badge { flex: 0 0 auto; }
.qb-issue-msg { flex: 1; font-size: var(--text-sm); color: var(--text-primary); }

/* ---------- Function editor modal ---------- */
.fn-editor label {
    display: block;
    font-size: var(--text-xs);
    color: var(--text-secondary);
    margin-bottom: var(--space-1);
}
.fn-params-table {
    margin-top: var(--space-1);
}
.fn-params-table .form-input-sm {
    min-width: 80px;
}
.fn-list .qb-options-table {
    margin-top: var(--space-2);
}

/* Monaco code-editor host (auto-grows to content height; min ~4 lines). */
.monaco-host {
    border: 1px solid var(--border-input);
    border-radius: var(--radius-sm);
    overflow: hidden;     /* the editor manages its own internal scrolling, if any */
    background: var(--bg-input);
    min-height: calc(var(--text-sm) * 6);
}
.monaco-host:focus-within {
    border-color: var(--border-focus);
    box-shadow: 0 0 0 3px var(--accent-glow);
}
.monaco-mount { width: 100%; }

/* Code-style textarea that auto-grows to fit its content. */
.code-textarea {
    resize: vertical;          /* author can still drag to override */
    overflow: hidden;          /* hides scrollbar while autoSize is in charge */
    min-height: calc(var(--text-sm) * 2.5);
    line-height: 1.5;
    white-space: pre;          /* preserve indentation in JS bodies */
    overflow-x: auto;          /* horizontal scroll for very long single lines */
}

/* Inline technical-name shown next to the friendly display name. */
.fn-code-name {
    font-family: var(--font-mono);
    font-size: var(--text-xs);
    color: var(--text-tertiary);
    background: var(--bg-secondary);
    padding: 1px var(--space-1);
    border-radius: var(--radius-xs);
}

/* ---------- Function-call widget (used in Rule editor) ---------- */
.fnc-wrap {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    padding: var(--space-2);
    background: var(--bg-secondary);
    border: 1px solid var(--border-secondary);
    border-radius: var(--radius-sm);
}
.fnc-picker { flex: 0 0 auto; }
.fnc-args {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    border-left: 2px solid var(--border-secondary);
    padding-left: var(--space-3);
}
.fnc-arg {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
}
.fnc-arg-label {
    font-family: var(--font-mono);
    font-size: var(--text-xs);
    color: var(--text-primary);
}
.fnc-arg-req { color: var(--danger-text); margin-left: 2px; }
.fnc-arg-type { color: var(--text-tertiary); }
.fnc-arg-desc {
    font-size: var(--text-xs);
    color: var(--text-tertiary);
    font-style: italic;
}
.fnc-arg-input {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
}
.fnc-mode-toggle {
    display: flex;
    gap: 2px;
}
.fnc-mode-toggle .btn-mini {
    padding: 2px var(--space-2);
    font-size: var(--text-xs);
}
.fnc-inline { width: 100%; }
.fnc-nested {
    border-left: 2px solid var(--accent-muted);
    margin-left: var(--space-1);
    padding-left: var(--space-2);
}

/* Inline kind dropdown + active-mode editor on a single row. Replaces the
   previous "three buttons stacked above the input" layout. */
.fnc-arg-row {
    display: flex !important;
    align-items: baseline;
    gap: 6px;
    flex-direction: row !important;
}
.fnc-arg-row .fnc-mode-select {
    flex: 0 0 auto;
    width: 130px;
}
.fnc-arg-row .fnc-arg-control {
    flex: 1;
    min-width: 0;
}
/* Nested function call inside an arg slot — keep the left-border accent but
   let it stretch instead of looking like an indent block. */
.fnc-arg-row > .fnc-nested.fnc-arg-control {
    margin-left: 0;
    padding-left: var(--space-1);
}

/* ---------- Rule RHS host ---------- */
.rule-rhs {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    flex: 1;
}

/* ============================================================
   READ-ONLY MODE
   Applied via .qb-readonly on .qb-shell when the page-header pencil
   is OFF. renderEditor sets `disabled` on every input/textarea/select
   so save handlers can never fire; this block just tones down the
   browser's default disabled styling and hides edit-only buttons.
   ============================================================ */
.qb-readonly input:disabled,
.qb-readonly textarea:disabled,
.qb-readonly select:disabled {
    /* Lifted tone vs the editor surface — in dark mode this is a touch
       lighter than the page (so the box stands out against the dark);
       in light mode it's a touch darker than the page (so the box has
       contrast against the white). Both ways the field is visible. */
    background-color: var(--bg-surface-active);
    border-color: var(--border-primary);
    color: var(--text-primary);
    opacity: 1;
    cursor: default;
}

.qb-readonly .qb-readonly-hide {
    display: none !important;
}

/* ============================================================
   DEFINITIONS MODAL (Variables / Functions / Callbacks tabs)
   ============================================================ */
.qb-defs-modal { display: flex; flex-direction: column; gap: var(--space-2); }
.qb-defs-tabbar {
    display: flex;
    gap: 4px;
    border-bottom: 1px solid var(--border-secondary);
    margin-bottom: var(--space-2);
}
.qb-defs-tab {
    padding: 8px 14px;
    border: 0;
    background: transparent;
    cursor: pointer;
    font-size: 14px;
    border-bottom: 2px solid transparent;
    margin-bottom: -1px;
    color: var(--text-secondary);
}
.qb-defs-tab:hover { background: var(--bg-surface-hover); color: var(--text-primary); }
.qb-defs-tab.active {
    color: var(--accent-text);
    border-bottom-color: var(--accent);
    font-weight: 600;
}
.qb-defs-content { padding: var(--space-1) 0; min-height: 200px; }
.qb-defs-add { margin-top: var(--space-2); display: flex; gap: 8px; align-items: center; }

/* Callback portion cards */
.qb-portion-card {
    margin-bottom: var(--space-2);
    padding: var(--space-2);
    border: 1px solid var(--border-primary);
    border-radius: 6px;
    background: var(--bg-elevated);
    color: var(--text-primary);
}
.qb-portion-header {
    display: flex;
    gap: 8px;
    align-items: center;
    margin-bottom: var(--space-2);
}
.qb-portion-pos {
    font-size: 12px;
    color: var(--text-secondary);
    font-weight: 600;
    text-transform: uppercase;
    white-space: nowrap;
}
.qb-portion-conditions { margin-top: var(--space-2); }
.qb-portion-condition-list {
    display: flex;
    flex-direction: column;
    gap: 4px;
    margin: 4px 0;
}
.qb-portion-condition-row {
    display: flex;
    gap: 6px;
    align-items: center;
    padding: 6px;
    background: var(--bg-surface);
    border: 1px solid var(--border-secondary);
    border-radius: 3px;
}
.qb-portion-condition-row .form-input { max-width: 220px; }
.qb-portion-email {
    margin-top: var(--space-2);
    padding: var(--space-2);
    border: 1px solid var(--border-secondary);
    border-radius: 4px;
    background: var(--bg-surface);
}
.qb-portion-email legend {
    font-weight: 600;
    padding: 0 6px;
    color: var(--text-primary);
    background: var(--bg-elevated);
}

/* Modal-wide help toggle — sits at the right end of the tab bar. Click flips
   .qb-help-visible on the modal body, which reveals all .qb-help-text divs. */
.qb-defs-tabbar-spacer { flex: 1; }
.qb-help-toggle {
    background: transparent;
    border: 1px solid var(--border-secondary);
    color: var(--text-secondary);
    padding: 4px 10px;
    margin-bottom: -1px;
    border-radius: 4px;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    gap: 4px;
    font-size: 13px;
    line-height: 1;
}
.qb-help-toggle:hover {
    background: var(--bg-surface-hover);
    color: var(--text-primary);
}
.qb-help-toggle.on {
    background: var(--accent-muted);
    color: var(--accent-text);
    border-color: var(--accent);
}
.qb-help-toggle svg { display: block; }
.qb-help-toggle-label { font-size: 13px; }

/* Hidden help blocks — only visible when an ancestor is .qb-help-visible.
   Used everywhere inside the Settings modal so one toggle reveals all. */
.qb-help-text {
    display: none;
    color: var(--text-secondary);
    font-size: 13px;
    margin: 4px 0;
    line-height: 1.4;
}
.qb-help-visible .qb-help-text { display: block; }
.qb-help-visible span.qb-help-text { display: inline; }

/* Generic icon-only button (trash, plus). Smaller than .btn-mini, square. */
.btn-icon {
    background: transparent;
    border: 1px solid transparent;
    padding: 4px;
    color: var(--text-secondary);
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 3px;
    line-height: 1;
}
.btn-icon:hover {
    background: var(--bg-surface-hover);
    color: var(--text-primary);
    border-color: var(--border-secondary);
}
.btn-icon svg { display: block; }
.btn-danger-icon:hover { color: #b91c1c; border-color: #b91c1c; }

/* Empty state for condition lists — single + button next to a hint */
.qb-portion-condition-empty {
    display: flex;
    align-items: center;
    padding: 4px 6px;
}

/* Condition row action group — keeps + / trash together at the right edge */
.qb-portion-condition-actions {
    display: inline-flex;
    gap: 4px;
    margin-left: auto;
}
.qb-portion-condition-row {
    /* override the previous gap/justify so .actions can push to the right */
    justify-content: flex-start;
}

/* Auto-growing email body — minimum 4 rows, soft cap so very long bodies scroll */
.qb-email-body {
    min-height: 96px;
    max-height: 60vh;
    overflow-y: auto;
    resize: none;
    box-sizing: border-box;
}

/* "Label: Field" rendering used by the question editor's top row + per-type
   config knobs. qb-inline-row puts the label and the input on the same line;
   qb-inline-stack keeps the label above (used for textareas where inline
   would crowd the input). qb-inline-label is the bold/colon label style. */
.qb-inline-label {
    font-weight: 700;
    margin: 0;
    white-space: nowrap;
    color: var(--text-primary);
}
/* Make every <label> in the question editor + per-type config bold so they
   read uniformly. Includes the Required / Randomize inline checkboxes and
   any free-floating <label> elements callers might add. */
.qb-shell label,
.qb-defs-modal label {
    font-weight: 700;
}
.qb-shell .inline-checkbox,
.qb-shell .inline-checkbox label,
.qb-defs-modal .inline-checkbox {
    font-weight: 700;
}
.qb-inline-row {
    display: flex !important;
    /* Align text baselines so the bold "Variable:" label sits on the same
       baseline as the input's typed text, not floating above it. */
    align-items: baseline;
    gap: 8px;
    margin-bottom: 0 !important;
}

/* Vertical breathing room between every block in the question editor —
   the cards (question / per-type / options / skip), and any other
   top-level child. Skips the very first child since the + selector needs
   a preceding sibling. */
.qb-editor > * + * {
    margin-top: var(--space-4);
}

/* Click-to-edit pattern across the editor matches bids/jobs. Each card
   has card-header (title + actions) + card-body (form). */
.qb-card-question .card-header,
.qb-card-pertype  .card-header,
.qb-card-options  .card-header,
.qb-card-skip     .card-header {
    background: var(--bg-secondary);
}
.qb-card-question .card-title,
.qb-card-pertype  .card-title,
.qb-card-options  .card-title,
.qb-card-skip     .card-title {
    text-transform: uppercase;
    letter-spacing: 0.04em;
}

/* Preview the Question + Instruction rich-text editors at the live survey's
   default content width (new2survey --max-w default) so line wrapping matches
   what respondents see. toolbar + editor share .richtext-wrapper, so capping it
   keeps them aligned. Reflects the DEFAULT only — per-client "Content max width"
   overrides apply at runtime, not in the builder. Keep in sync with that
   default. Option labels use .qb-opt-label-rt (a separate card) and aren't
   capped. max-width, so narrower panes just use available width. */
.qb-card-question .richtext-wrapper { max-width: 1024px; }

/* Question editor field rows — three explicit rows so the page-level
   .form-row flex override can't squish everything onto a single line. */
.qb-edit-fields {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
}
.qb-edit-row {
    display: flex;
    gap: var(--space-3);
    align-items: stretch;
    flex-wrap: wrap;
}
.qb-edit-row > .form-group {
    flex: 1 1 180px;
    margin-bottom: 0;
    min-width: 0;
}
.qb-edit-fields > .form-group { margin-bottom: 0; }

/* Skip-logic rule cards: "Run when" dropdown sits inline to the left of
   the When checkbox, on the same row. */
.qb-rule-when-row {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    flex-wrap: wrap;
    margin-bottom: var(--space-2);
}
.qb-rule-runwhen-label {
    font-weight: 700;
    color: var(--text-primary);
    white-space: nowrap;
}
.qb-rule-runwhen { width: 110px; flex: 0 0 110px; }

/* Required / Randomize badges shown in read-only mode in place of
   disabled checkboxes. */
.qb-flag-row { display: flex; gap: 16px; flex-wrap: wrap; align-items: center; }
.qb-randomize-row { display: flex; align-items: center; gap: 6px; }
.qb-randomize-row .qb-inline-label { font-size: var(--text-sm); }
.qb-randomize-mode { width: 200px; flex: 0 0 200px; }
.qb-flag-badge {
    display: inline-flex;
    align-items: center;
    padding: 2px 10px;
    border-radius: var(--radius-md);
    font-size: var(--text-xs);
    font-weight: 600;
    background: var(--accent-muted);
    color: var(--accent-text);
    border: 1px solid var(--accent);
}
.qb-flag-badge.qb-flag-badge-muted {
    background: transparent;
    color: var(--text-secondary);
    border-color: var(--border-secondary);
    font-weight: 500;
}
.qb-flag-badge.qb-flag-badge-danger {
    background: transparent;
    color: var(--danger-text);
    border-color: var(--danger-text);
}

/* Auto-growing textarea — content drives the height. Caps at 60vh so a
   pathologically long question doesn't push the rest of the editor off
   the screen; overflow scrolls inside the field instead. */
textarea.qb-autogrow {
    min-height: 4em;
    max-height: 60vh;
    resize: none;
    overflow-y: auto;
    box-sizing: border-box;
}
.qb-inline-row > .form-input,
.qb-inline-row > input,
.qb-inline-row > select,
.qb-inline-row > textarea {
    flex: 1;
    min-width: 0;
}
.qb-inline-stack {
    display: flex !important;
    flex-direction: column;
    align-items: stretch;
    gap: 4px;
    margin-bottom: 0 !important;
}
.qb-inline-stack > .qb-inline-label { margin-bottom: 2px; }

/* Read-only visibility indicator on each option row. Mirrors btn-mini-active
   when a rule is attached so the eye scans for "has rule" the same way
   whether the form is in edit or read-only mode. */
.qb-vis-indicator {
    display: inline-block;
    padding: 2px 8px;
    border-radius: 3px;
    font-size: 11px;
    line-height: 1.4;
    color: var(--text-secondary);
    background: transparent;
    border: 1px solid transparent;
    font-family: monospace;
}
.qb-vis-indicator-active {
    color: var(--accent-text);
    background: var(--accent-muted);
    border-color: var(--accent);
    font-weight: 600;
}
/* Full readable rule text in the options-table visibility cell ("if f17a
   contains 1 — armini"). Wraps inside the cell instead of stretching the
   table; applies to both the edit-mode button and the read-only badge. */
.qb-vis-rule-full {
    white-space: normal;
    text-align: left;
    line-height: 1.35;
    font-size: var(--text-xs);
    max-width: 420px;
}
/* When a row actually carries rules, the cell overrides .col-flag's compact
   70px/nowrap sizing so typical one-condition rules fit on one or two lines.
   One ruled row widens the whole column; rule-less tables stay compact. */
.qb-options-table .col-flag.qb-vis-rule-cell {
    width: auto;
    min-width: 260px;
    white-space: normal;
}

/* text-list editor rows in the per-question config */
.qb-text-list-rows { display: flex; flex-direction: column; gap: 4px; margin: 6px 0; }
.qb-text-list-row { display: flex; gap: 6px; align-items: center; flex-wrap: nowrap; }
.qb-text-list-row input[type="text"] { flex: 1; min-width: 0; }
.qb-text-list-row input[type="number"] { flex: 0 0 100px; }
.qb-text-list-index {
    font-family: monospace;
    font-size: 12px;
    color: var(--text-secondary);
    min-width: 36px;
}

/* Force the per-question config form-row to flex consistently regardless of
   the global .form-row grid rule in components.css. */
.qb-pertype-config .form-row {
    display: flex !important;
    gap: var(--space-2);
    align-items: flex-end;
    flex-wrap: nowrap;
}
.qb-pertype-config .form-row > .form-group {
    flex: 1;
    min-width: 0;
    margin-bottom: 0;
}

/* Survey System Settings page */
.sss-page { max-width: 900px; }
.sss-table .form-input { max-width: 220px; }
.sss-desc { color: var(--text-secondary); font-size: 13px; }

/* ============================================================================
   QUESTIONNAIRE BUILDER — PANEL POLISH
   ============================================================================
   The question + per-type cards are the main editing surface. We pulled the
   "EDIT QUESTION" card title (the action buttons stay tucked top-right). The
   styles below add structure to the per-type panel (labeled subsections),
   replace bare checkboxes with switches, fade controls that are gated by an
   off toggle, and turn the top flag row into discrete labeled cells so it
   reads as a form. */

/* ---- Card header without title — just the actions tucked right --------- */
.qb-card-header-actions-only {
    display: flex;
    justify-content: flex-end;
    align-items: center;
    padding: var(--space-2) var(--space-3);
    background: transparent;
    min-height: 32px;
}

/* ---- Per-type subsection (Behavior / Layout / Validation / etc.) ------- */
.qb-pertype-section {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    padding: var(--space-3) 0;
    border-top: 1px solid var(--border-secondary);
}
.qb-pertype-section:first-child { border-top: none; padding-top: 0; }
.qb-pertype-section:last-child  { padding-bottom: 0; }
.qb-pertype-section-title {
    font-size: 0.72rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--text-secondary);
    margin: 0 0 4px 0;
}

/* ---- Toggle switch (drop-in for checkbox in qb-* contexts) ------------- */
/* Markup expected:
     <label class="qb-toggle">
       <input type="checkbox">
       <span class="qb-toggle-track"><span class="qb-toggle-thumb"></span></span>
       <span class="qb-toggle-label">Label text</span>
     </label>
   The native checkbox is visually hidden but stays focusable + clickable.
*/
.qb-toggle {
    display: inline-flex;
    align-items: center;
    /* gap covers the spacing between the input (visually hidden absolute)
       and the track. The track→label spacing is set explicitly on
       .qb-toggle-label to guarantee breathing room even if a parent rule
       collapses the flex gap. */
    gap: 4px;
    cursor: pointer;
    user-select: none;
    font-weight: 700;
    color: var(--text-primary);
}
.qb-toggle input[type="checkbox"] {
    position: absolute;
    opacity: 0;
    width: 0;
    height: 0;
    pointer-events: none;
}
.qb-toggle-track {
    position: relative;
    display: inline-block;
    width: 38px;
    height: 22px;
    background: var(--border-primary);
    border-radius: 999px;
    transition: background var(--duration-fast, 150ms) var(--ease-default, ease);
    flex: 0 0 38px;
}
.qb-toggle-thumb {
    position: absolute;
    top: 2px;
    left: 2px;
    width: 18px;
    height: 18px;
    border-radius: 999px;
    background: var(--bg-elevated, #fff);
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
    transition: transform var(--duration-fast, 150ms) var(--ease-default, ease);
}
.qb-toggle input:checked + .qb-toggle-track { background: var(--accent); }
.qb-toggle input:checked + .qb-toggle-track .qb-toggle-thumb {
    transform: translateX(16px);
}
.qb-toggle input:focus-visible + .qb-toggle-track {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}
.qb-toggle-label {
    font-size: 0.875rem;
    font-weight: 600;
    color: var(--text-primary);
    line-height: 1.4;
    /* Explicit margin instead of relying on the parent flex gap — the
       absolute-positioned input can absorb the gap quota in some
       browsers, leaving the track and label nearly touching. */
    margin-left: 10px;
}

/* ---- Coupled-control fade (e.g. Min/Max while Multi-select off) -------- */
.qb-disabled-coupled {
    opacity: 0.5;
    transition: opacity var(--duration-fast, 150ms) var(--ease-default, ease);
    position: relative;
}
.qb-disabled-coupled::after {
    content: attr(data-disabled-hint);
    display: block;
    font-size: 0.72rem;
    font-style: italic;
    color: var(--text-muted);
    margin-top: 2px;
}

/* ---- Top flag row: each control in its own labeled cell ---------------- */
/* Wraps Required / Randomize / Group # so they read as three form fields
   side by side instead of loose inline controls. Each child keeps its own
   internal layout (row for inline-checkbox, row for randomize-row); we
   just add framing chrome around each cell. */
.qb-flag-row {
    display: flex !important;
    gap: var(--space-3) !important;
    flex-wrap: wrap;
    align-items: stretch !important;
}
.qb-flag-row > * {
    padding: 8px 12px;
    background: var(--bg-surface);
    border: 1px solid var(--border-secondary);
    border-radius: var(--radius-md);
    display: flex;
    align-items: center;
    min-height: 44px;
}
.qb-flag-row > label.inline-checkbox {
    gap: 6px;
}
.qb-flag-row > .qb-randomize-row {
    /* Keep the inherited row layout from .qb-randomize-row. */
    gap: 8px;
}
.qb-flag-row > .qb-randomize-row .qb-inline-label {
    font-size: 0.72rem;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--text-secondary);
    font-weight: 700;
}

/* Force builder Quill editors to a fixed light palette regardless of the
   page's data-theme / prefers-color-scheme. Authors style content against
   the same backdrop the survey runtime renders, so saved colors look the
   same in both places.
   Applied via the .qb-richtext-light marker class set on every Quill host
   in the builder (the per-type-config richtext editors via the lightTheme
   opt on buildFormField/createInlineField in js/ui.js, plus the option-
   label cells and their shared toolbar in js/pages/questionnaire-builder.js).
   Tickets and other Quill consumers keep the page's theme. */
.qb-richtext-light,
.qb-richtext-light .ql-toolbar,
.qb-richtext-light .ql-container,
.qb-richtext-light .ql-editor,
.qb-richtext-light .ql-tooltip,
.qb-richtext-light .ql-picker-options {
    --bg-primary:    #ffffff;
    --bg-input:      #ffffff;
    --bg-surface:    #ffffff;
    --bg-secondary:  #f8f9fa;
    --text-primary:  #1a1a1a;
    --text-secondary:#4a4a4a;
    --text-muted:    #6c757d;
    --border-primary:#d0d4d8;
    color-scheme: light;
}
.qb-richtext-light .ql-editor {
    color: #1a1a1a;
    background: #ffffff;
}
.qb-richtext-light .ql-toolbar {
    background: #f8f9fa;
    color: #1a1a1a;
    border-color: #d0d4d8;
}
.qb-richtext-light .ql-toolbar button,
.qb-richtext-light .ql-toolbar .ql-picker-label,
.qb-richtext-light .ql-toolbar .ql-picker-item {
    color: #1a1a1a;
}
.qb-richtext-light .ql-toolbar button:hover,
.qb-richtext-light .ql-toolbar button.ql-active,
.qb-richtext-light .ql-toolbar .ql-picker-label:hover {
    color: #2563eb;
}
.qb-richtext-light .ql-toolbar .ql-stroke { stroke: #1a1a1a; }
.qb-richtext-light .ql-toolbar button:hover .ql-stroke,
.qb-richtext-light .ql-toolbar button.ql-active .ql-stroke { stroke: #2563eb; }
.qb-richtext-light .ql-toolbar .ql-fill   { fill: #1a1a1a; }
.qb-richtext-light .ql-toolbar button:hover .ql-fill,
.qb-richtext-light .ql-toolbar button.ql-active .ql-fill   { fill: #2563eb; }
.qb-richtext-light .ql-tooltip,
.qb-richtext-light .ql-picker-options {
    background: #ffffff;
    color: #1a1a1a;
    border-color: #d0d4d8;
}
.qb-richtext-light .ql-tooltip input[type=text] {
    background: #ffffff;
    color: #1a1a1a;
    border-color: #d0d4d8;
}

/* =========================================================================
   Asset library (Settings → Assets tab) + asset picker + in-editor blot
   ========================================================================= */

/* ----- Settings → Assets tab ----- */
.qa-dropzone {
    border: 2px dashed var(--border-primary, #d0d4d8);
    border-radius: var(--radius-md, 8px);
    padding: 24px;
    margin: 12px 0 16px;
    text-align: center;
    background: var(--bg-surface, #f8f9fa);
    transition: background .15s, border-color .15s;
}
.qa-dropzone-active {
    border-color: #2563eb;
    background: #eef4ff;
}
.qa-status {
    padding: 12px 4px;
    color: var(--text-muted, #6c757d);
    font-size: 0.9rem;
}
.qa-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
    gap: 12px;
    margin-top: 8px;
}
.qa-card {
    border: 1px solid var(--border-primary, #d0d4d8);
    border-radius: var(--radius-md, 8px);
    padding: 8px;
    background: #fff;
    display: flex;
    flex-direction: column;
    gap: 6px;
    min-width: 0;
}
.qa-card-thumb {
    display: block;
    width: 100%;
    height: 120px;
    object-fit: contain;
    border-radius: 4px;
    background: #f0f2f4;
}
.qa-card-thumb-icon {
    font-size: 2.4rem;
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--text-muted, #6c757d);
}
.qa-card-title {
    font-weight: 500;
    font-size: 0.9rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    cursor: text;
    /* The card is always white, so an explicit dark color is needed — without
       it the title inherits the dark theme's near-white --text-primary and is
       nearly invisible until clicked (the rename input has its own color). */
    color: #1f2329;
}
.qa-card-meta {
    font-size: 0.78rem;
    color: var(--text-muted, #6c757d);
}
.qa-card-actions {
    display: flex;
    gap: 4px;
    margin-top: auto;
    flex-wrap: wrap;
}
.qa-card-actions .btn-mini {
    font-size: 0.75rem;
    padding: 2px 8px;
}

/* ----- Picker modal ----- */
.qa-picker { display: flex; flex-direction: column; gap: 12px; }
.qa-picker-status { padding: 16px; color: var(--text-muted, #6c757d); }
.qa-picker-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
    gap: 10px;
    max-height: 60vh;
    overflow-y: auto;
}
.qa-picker-card {
    border: 1px solid var(--border-primary, #d0d4d8);
    border-radius: var(--radius-md, 8px);
    padding: 6px;
    background: #fff;
    cursor: pointer;
    text-align: left;
    display: flex;
    flex-direction: column;
    gap: 4px;
    font: inherit;
    transition: border-color .12s, box-shadow .12s;
}
.qa-picker-card:hover {
    border-color: #2563eb;
    box-shadow: 0 0 0 2px rgba(37, 99, 235, 0.18);
}
.qa-picker-thumb {
    width: 100%;
    height: 96px;
    object-fit: contain;
    border-radius: 4px;
    background: #f0f2f4;
}
.qa-picker-thumb-video,
.qa-picker-thumb-audio {
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 1.8rem;
    color: var(--text-muted, #6c757d);
}
.qa-picker-label {
    font-weight: 500;
    font-size: 0.85rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    /* White card → explicit dark color (same reason as .qa-card-title). */
    color: #1f2329;
}
.qa-picker-sub {
    font-size: 0.72rem;
    color: var(--text-muted, #6c757d);
}

/* ----- In-editor attribute popover ----- */
.qa-popover {
    background: #fff;
    border: 1px solid var(--border-primary, #d0d4d8);
    border-radius: var(--radius-md, 8px);
    box-shadow: 0 4px 18px rgba(0,0,0,0.14);
    padding: 10px;
    width: 260px;
    font-size: 0.85rem;
    color: #1a1a1a;
}
.qa-popover-title {
    font-weight: 600;
    padding-bottom: 6px;
    border-bottom: 1px solid var(--border-primary, #d0d4d8);
    margin-bottom: 8px;
}
.qa-popover-row {
    display: flex;
    align-items: center;
    gap: 6px;
    margin: 4px 0;
}
.qa-popover-row label { font-size: 0.85rem; }
.qa-popover-custom { width: 90px; }

/* Custom size dropdown — used instead of <select> to dodge OS-native
   dropdown focus quirks when multiple embeds live in the same editor. */
.qa-popover-row-size { flex-wrap: wrap; row-gap: 4px; position: relative; }
.qa-size-trigger {
    appearance: none;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 4px 8px;
    font: inherit;
    font-size: 0.85rem;
    background: #fff;
    color: #1a1a1a;
    border: 1px solid var(--border-primary, #d0d4d8);
    border-radius: var(--radius-sm, 4px);
    cursor: pointer;
    min-width: 80px;
}
.qa-size-trigger:hover { border-color: #2563eb; }
.qa-size-trigger-open { border-color: #2563eb; }
.qa-size-trigger-caret {
    font-size: 0.7rem;
    line-height: 1;
    color: var(--text-muted, #6c757d);
}
.qa-size-list {
    position: absolute;
    top: 100%;
    left: 48px;          /* aligns under the trigger; label is to the left */
    margin-top: 2px;
    background: #fff;
    border: 1px solid var(--border-primary, #d0d4d8);
    border-radius: var(--radius-sm, 4px);
    box-shadow: 0 4px 14px rgba(0,0,0,0.12);
    max-height: 220px;
    overflow-y: auto;
    z-index: 10000;
    min-width: 100px;
    padding: 4px 0;
}
.qa-size-list[hidden] { display: none; }
.qa-size-item {
    display: block;
    width: 100%;
    text-align: left;
    padding: 4px 12px;
    font: inherit;
    font-size: 0.85rem;
    background: transparent;
    color: #1a1a1a;
    border: 0;
    cursor: pointer;
}
.qa-size-item:hover { background: #eaf3ff; }
.qa-size-item-current { font-weight: 600; color: #2563eb; }
.qa-size-item-custom { border-top: 1px solid var(--border-primary, #d0d4d8); margin-top: 2px; padding-top: 6px; }

/* ----- In-editor embed (the `.q-asset-embed` img Quill renders) ----- */
.ql-editor .q-asset-embed {
    max-width: 100%;
    /* inline-block so two embeds in the same Quill paragraph sit side-
       by-side. We deliberately omit vertical-align here so the default
       baseline applies — adjacent text reads against the image's bottom
       edge, matching the runtime .q-asset-img rule. */
    display: inline-block;
    margin: 4px 4px 4px 0;
    border: 1px dashed transparent;
}
.ql-editor .q-asset-embed:hover {
    border-color: #2563eb;
    cursor: pointer;
}
.ql-editor .q-asset-embed[data-kind="video"],
.ql-editor .q-asset-embed[data-kind="audio"] {
    /* In the editor, video/audio embeds render as `<img>` with no src (or
       the asset's thumbnail). Show a placeholder via CSS pseudo. */
    background: #f0f2f4;
    min-width: 120px;
    min-height: 60px;
    padding: 16px;
    object-fit: contain;
}
.ql-editor .q-asset-embed[data-kind="video"]:not([src])::before {
    content: "▶ video";
}
.ql-editor .q-asset-embed[data-kind="audio"]:not([src])::before {
    content: "♪ audio";
}

/* Custom toolbar icon — injected via Quill's icons registry at blot setup.
   Fallback to emoji when the SVG didn't render (browsers without :has()
   show both, which is fine — Quill icon dominates visually). */
.ql-toolbar button.ql-asset:not(:has(svg))::after {
    content: "📎";
    font-size: 14px;
}

/* Per-option image picker (when card_options is enabled on the question) */
.qb-opt-image-cell {
    display: flex;
    align-items: center;
    gap: 6px;
    min-width: 60px;
}
.qb-opt-image-thumb {
    width: 36px;
    height: 36px;
    object-fit: contain;
    border: 1px solid var(--border-primary, #d0d4d8);
    border-radius: 4px;
    background: #f0f2f4;
}
.qb-opt-image-placeholder {
    font-size: 0.72rem;
    color: var(--text-muted, #6c757d);
    display: inline-block;
    min-width: 36px;
    text-align: center;
}

/* Quill toolbar valign picker — paragraph-level V-align control.
   When a value is picked, the current paragraph gets a `qb-valign-top`
   or `qb-valign-middle` class (handled by the block-scoped Parchment
   ClassAttributor registered in assets.js). The accompanying CSS rules
   below apply `vertical-align` to every inline child of that paragraph
   — that's what shifts the line baseline and positions text relative to
   tall inline images. */
.ql-toolbar .ql-picker.ql-valign { width: 76px; }
.ql-toolbar .ql-picker.ql-valign .ql-picker-label::before                        { content: 'V-align'; }
.ql-toolbar .ql-picker.ql-valign .ql-picker-label[data-value="top"]::before      { content: 'Top';      }
.ql-toolbar .ql-picker.ql-valign .ql-picker-label[data-value="middle"]::before   { content: 'Middle';   }
.ql-toolbar .ql-picker.ql-valign .ql-picker-label[data-value="baseline"]::before { content: 'Baseline'; }
.ql-toolbar .ql-picker.ql-valign .ql-picker-label[data-value="bottom"]::before   { content: 'Bottom';   }
.ql-toolbar .ql-picker.ql-valign .ql-picker-item[data-value=""]::before          { content: 'Default';  }
.ql-toolbar .ql-picker.ql-valign .ql-picker-item[data-value="top"]::before       { content: 'Top';      }
.ql-toolbar .ql-picker.ql-valign .ql-picker-item[data-value="middle"]::before    { content: 'Middle';   }
.ql-toolbar .ql-picker.ql-valign .ql-picker-item[data-value="baseline"]::before  { content: 'Baseline'; }
.ql-toolbar .ql-picker.ql-valign .ql-picker-item[data-value="bottom"]::before    { content: 'Bottom';   }

/* Flexbox-based paragraph alignment.
   Author picks V-align in the toolbar → paragraph gets `qb-valign-<v>`
   class → paragraph becomes a flex container. The tallest child drives
   the line height, and align-items positions every other child (images
   AND text runs) accordingly.
   Why flex instead of `vertical-align` on children: text nodes aren't
   elements, so CSS rules don't directly position them. With flex, each
   contiguous text run becomes an anonymous flex item that participates
   in align-items. `flex-wrap: wrap` lets long content reflow to new
   flex lines if it overflows; each flex line aligns independently. */
.qb-valign-top      { display: flex; flex-wrap: wrap; align-items: flex-start; }
.qb-valign-middle   { display: flex; flex-wrap: wrap; align-items: center;     }
.qb-valign-baseline { display: flex; flex-wrap: wrap; align-items: baseline;   }
.qb-valign-bottom   { display: flex; flex-wrap: wrap; align-items: flex-end;   }

/* Box (bordered block) format — the toolbar 'box' button toggles a
   `qb-box` class on a paragraph (BoxBlot in assets.js). A run of consecutive
   boxed paragraphs renders as ONE connected box: left/right border on every
   boxed line, top on the first of a run, bottom on the last (detected with the
   adjacent-sibling and :has selectors). Paragraph margins are already 0 in the
   editor so the lines touch. Mirrored in the survey runtime (engine.css). */
.ql-editor p.qb-box-on {
    border-left: 1px solid #333; border-right: 1px solid #333;
    padding-left: 12px; padding-right: 12px;
}
.ql-editor :not(.qb-box-on) + p.qb-box-on,
.ql-editor p.qb-box-on:first-child {
    border-top: 1px solid #333; padding-top: 8px;
}
.ql-editor p.qb-box-on:has(+ :not(.qb-box-on)),
.ql-editor p.qb-box-on:last-child {
    border-bottom: 1px solid #333; padding-bottom: 8px;
}
