/* Focus ring for the app's chrome. The item engine's sheet, loaded just before
   this one, rings every focused element in a fixed blue that is under 3:1 on
   a dark page. This rule has the same weight (:where adds none) and comes
   later, so it replaces that ring wherever <html> carries a theme; a rule
   that sets its own focus style still wins. Inside authored content the ring
   token is the light one, and inside an item's shadow root the engine's own
   ring still applies. */
:where(html[data-app-theme]) *:focus-visible {
    outline: var(--focus-outline);
    outline-offset: var(--focus-offset);
    box-shadow: none;
}

/* Two more engine rules that reach the app's chrome, replaced the same way
   (equal weight, later sheet, only where <html> carries a theme).

   Equations. The engine paints every <math> in its own foreground, the dark
   ink of the item paper, so an equation on a dark panel was invisible. An
   equation takes the colour of the text it sits in: light on a dark panel,
   and the paper's ink inside authored content. */
:where(html[data-app-theme]) math {
    color: inherit;
}

/* Popups. The engine gives every <dialog> the item text size (14pt). An
   app popup uses the app's text size; test content shown inside one is a
   paper host and keeps its own. */
:where(html[data-app-theme]) dialog {
    font-size: var(--text-body);
}

/* Invalid fields. The engine gives any field marked aria-invalid a pale pink
   fill and leaves its text alone, which in the dark theme is light text on
   pale pink. The fill and the text are set together here. */
:where(html[data-app-theme]) input[aria-invalid="true"],
:where(html[data-app-theme]) textarea[aria-invalid="true"],
:where(html[data-app-theme]) select[aria-invalid="true"] {
    border-color: var(--status-danger);
    background-color: var(--status-danger-tint);
    color: var(--text-primary);
}

.DISView_window {
}

.tq_interaction_dialog > h1 {
    text-align: center;
}

.tq-dialog-header-actions {
    display: flex;
    align-items: center;
    gap: 4px;
}

.tq-header {
    background-color: var(--fill);
    color: var(--text-primary);
}

.tq-quantity-stimulus-editor {
   margin-bottom: 15px;
}

.tq-flex-column {
    display: flex;
    flex-direction: column;
}
.tq-flex-row {
    display: flex;
    flex-direction: row;
}
.tq-flex-row-reverse {
    display: flex;
    flex-direction: row-reverse;
}

.tq-full-width {
    flex: 1;
    min-width: 0;
    overflow-y: auto;
}

.tq-center-span {
    display:flex;
    justify-content: center;
    flex-direction: row;
}

div.DISView_window > div.DISView_body {
    display: flex;
    flex-direction: row;
    margin-left: -15px;
    margin-right: -15px;
}
div.tq-panel-close {
    width: 54px;
    min-width: 54px;
    flex-shrink: 0;
    align-self: stretch;
    overflow: hidden;
    transition: width 220ms cubic-bezier(0.4, 0, 0.2, 1);
}

div.tq-panel-open {
    width: 320px;
    flex-shrink: 0;
    align-self: stretch;
    overflow-y: auto;
    overflow-x: hidden;
    transition: width 220ms cubic-bezier(0.4, 0, 0.2, 1);
}

div.tq-panel-close > :not(.tq-panel-header) {
    visibility: hidden;
    opacity: 0;
    pointer-events: none;
    transition: visibility 0s 150ms, opacity 120ms ease;
}

div.tq-panel-open > :not(.tq-panel-header) {
    visibility: visible;
    opacity: 1;
    pointer-events: auto;
    transition: opacity 150ms ease 200ms;
}

.tq-panel-header {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    border-bottom: 1px solid var(--divider);
    width: calc(100% + 24px);
    margin-left: -12px;
    height: 54px;
    min-height: 54px;
    flex-shrink: 0;
    padding: 5px;
    box-sizing: border-box;
    cursor: pointer;
    user-select: none;
}

div.tq-panel-close .tq-panel-title {
    display: none;
}

div.tq-sheild {
    position: absolute;
    z-index: 5;
    width: 100%;
    height: 100%;
    background-color: rgba(255,255,255,0.2);
    top: 0px;
    left: 0px;
}

div.tq-side-panel div.Tree_window {
    width: max-content;
}

.tq-pattern-display {
    display: grid;
    grid-template-columns: 1fr ffr 1fr;
}

.tq-reorderable-list {
    width: fit-content;
}

    .tq-reorderable-list ul {
        list-style: none;
        background-color: var(--surface);
        box-shadow: var(--shadow-3); /* shadow-2xl */
        border-radius: 0.75rem; /* rounded-xl */
        padding: 1.5rem; /* p-6 */
    }

.tq-reorderable-list-item {
    display: flex; /* flex */
    align-items: center; /* items-center */
    justify-content: space-between; /* justify-between */
    padding: 0.75rem; /* p-3 (Tailwind's spacing scale) */
    background-color: var(--surface); /* bg-white */
    border-width: 1px; /* border */
    border-color: var(--divider); /* border-gray-200 */
    border-radius: 0.5rem; /* rounded-lg */
    box-shadow: var(--shadow-1); /* shadow-sm */
    transition-property: box-shadow; /* transition */
    transition-duration: 150ms; /* duration-150 */
    transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); /* ease-in-out */
}

.tq-picked-up {
}

.tq-dragging {
    opacity: 0.4;
    border: 2px dashed var(--color-border);
    background-color: var(--bg-secondary);
}

.tq-simulation-row1 {
    display: grid;
    grid-template-columns: 1fr 1fr 1fr;
}

.tq-simulation-template-dialog {
    min-width: 80%;
}

    .tq-simulation-template-dialog .tq-reorderable-list {
        width: 100%;
        padding-right: 2em;
    }

/* BankWorkflowView Workflow Activities: scoped to .bw-activity-list so the
   list fills its fixed-width column and long activity labels wrap instead of
   forcing the list wider. Does not affect other ReorderableList instances. */
.bw-activity-list .tq-reorderable-list {
    width: 100%;
}

    .bw-activity-list .tq-reorderable-list ul {
        padding: 0.75rem;
    }

.bw-activity-list .tq-reorderable-list-item {
    gap: 4px;
}

.tq-draggable-list-item {
    display: flex;
    align-items: center;
    flex: 1 1 auto;
    min-width: 0;
}

.tq-list-item-actions {
    display: flex;
    align-items: center;
    flex-shrink: 0;
    gap: 4px;
}

    .bw-activity-list .tq-draggable-list-item > span {
        white-space: normal;
        overflow-wrap: anywhere;
    }

div.tq-gr-canvas {
    position: absolute;
    z-index: 10;
    width: 100%;
    height: 100% ;
    background-color: rgba(255,255,255,0.2);
    top: 0px;
    left: 0px;
    border: 2px dashed red;
}

div.tq-gr-canvas>div {
    background-color: white;
    width: 100%;
    text-align:center;
}

div.tq-dialog-controls {
    display: grid;
    grid-template-columns: auto auto;
}
dialog.tq-condition,
div.tq-condition {
    width: 100%;
    border: 1px solid var(--control-border);
    border-radius: .5em;
}

    div.tq-condition div.tq-body {
        width: stretch;
        display: grid;
        grid-template-columns: 1fr;
        margin-left: .5em;
        margin-right: 2px;
        margin-bottom: 2px;
    }

    div.tq-condition div.tq-body.tq-logic {
        grid-template-columns: 5em 1fr;
    }
    div.tq-condition select {
        width: 100%;
        height: fit-content;
    }
div.DISView_window > div.DISView_body div.tq-assertion-panel div.tq-condition div.tq-header {
        width: stretch;
        display: flex;
        flex-direction: row;
        justify-content: left;
        margin-left: .5em;
        margin-right: .5em;
        border: none;
    }

div.DISView_window > div.DISView_body div.tq-numeric-buttons > span.tq-control-span select.Select_window,
div .tq-condition div.tq-header select.Select_window {
    width: auto;
    border: none;
    padding: 2px;
    /* Room for the chevron, which sits closer to the edge in these tight
       inline drop-downs. */
    padding-right: 26px;
    background-position: right 6px center;
}

div.DISView_window > div.DISView_body div.tq-control-span select.Select_window,
div .tq-condition div.tq-header select.Select_window {
    width: auto;
    border: none;
    padding: 2px;
    padding-right: 26px;
    background-position: right 6px center;
}

div .tq-condition div.tq-header mrow[inert] {
    margin-left: .5em;
    margin-right: 1em;
}

button:disabled {
    color: var(--text-tertiary);
}
div .tq-side-panel div.tq-sample-panel button.tq-expandable-button.tq-selected,
button.tq-selected {
    color: var(--color-primary-dark);
    background-color: var(--color-primary-tint);
}

.tq-widget-spec-generator div.tq-scroll-box {
    height: 16em;
    width: auto;
    border: 1px solid var(--control-border);
    margin-bottom: 1.5em;
}

.tq-widget-spec-generator div.tq-scroll-box .tq-reorderable-list {
    width: 100%;
}
button.tq-test-score-btn {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    background: transparent;
    border: none;
    color: inherit;
    padding: 4px 2px;
}

button.tq-test-score-btn:hover,
button.tq-test-score-btn:focus {
    background: transparent;
}

button.tq-test-score-btn::after {
    content: '';
    flex-shrink: 0;
    display: inline-block;
    width: 44px;
    height: 26px;
    border-radius: 13px;
    /* Off track: #767676 puts the white knob at 4.5:1 against it (WCAG 1.4.11
       needs 3:1); the old #b8b8b8 gave 1.9:1. On track is --color-primary. */
    background-color: #767676;
    background-image: radial-gradient(circle, white 48%, transparent 50%);
    background-size: 22px 22px;
    background-position: 2px center;
    background-repeat: no-repeat;
    transition: background-color 250ms ease, background-position 250ms ease;
    box-shadow: inset 0 0 0 1px rgba(0,0,0,0.1);
}

button.tq-test-score-btn.tq-test-score-mode,
button.tq-test-score-btn.tq-test-score-mode:hover,
button.tq-test-score-btn.tq-test-score-mode:focus {
    background: transparent;
    color: inherit;
    border: none;
    transform: none;
    box-shadow: none;
}

button.tq-test-score-btn.tq-test-score-mode::after {
    background-color: var(--accent-fill);
    background-position: 20px center;
}

/* Score-report dialogs (success score-result + failure scoring-issues).
   Mirrors the assertion-dialog chrome so both adopt the new app-dialog look:
   a centred flex-column box with a sticky header and a scrolling body. The
   table styling further down is scoped to this dialog only so the global
   .Table2D_* rules (used app-wide) stay untouched. */
dialog.tq-score-dialog {
    position: fixed;
    inset: 0;
    box-sizing: border-box;
    width: min(900px, 90%);
    max-width: 900px; /* override .app-dialog's 480px cap */
    max-height: 92vh;
    margin: auto;
}

dialog.tq-score-dialog[open] {
    display: flex;
    flex-direction: column;
    overflow: hidden;
}

/* Slight dim only — the item behind stays readable. */
dialog.tq-score-dialog::backdrop {
    background: rgba(0, 0, 0, 0.18);
}

/* The header holds only the close (×) button — the table caption carries the
   title now — so push the × to the right. */
dialog.tq-score-dialog .app-dialog-header {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    flex-shrink: 0;
}

dialog.tq-score-dialog .app-dialog-body {
    flex: 1 1 auto;
    overflow: auto;
    padding: 1rem;
    margin-bottom: 0;
}

dialog.tq-score-dialog .app-dialog-close {
    /* Keep the shared 44x44 hit target (WCAG 2.5.5 AAA) — do NOT shrink it the
       way the assertion dialog does. Base .app-dialog-close already sets
       min-width/height:44px + flex centering; here we only enlarge the glyph
       and darken it for AAA contrast. */
    font-size: 1.4rem;
    line-height: 1;
    /* Comfortable AAA: 12.2:1 on white. The shared default (#475569) is only
       7.6:1 — a marginal pass — so the score dialog uses the brand dark. */
    color: var(--color-primary-dark);
}

dialog.tq-score-dialog .app-dialog-close:hover {
    /* 10.8:1 on the tint hover background (the shared purple hover is 7.4:1). */
    color: var(--color-primary-dark);
}

/* Strong, visible focus indicators (AAA). */
dialog.tq-score-dialog button:focus-visible {
    outline: var(--focus-outline);
    outline-offset: var(--focus-offset);
}

/* Assertions / issues table — styled after the redesigned WorkQueue table
   (.wq-table in styles.css): borderless, uppercase column headers with a 2px
   under-rule, light horizontal row dividers, no vertical grid lines, 44px-tall
   rows, and light-purple even-row striping (the global Table2D zebra fill,
   recoloured from grey — see styles.css). Scoped to this dialog so the
   structural .Table2D_* rules stay untouched; long assertion text may wrap. */
dialog.tq-score-dialog .Table2D_window {
    width: 100%;
    border: none;
}

dialog.tq-score-dialog .Table2D_header th {
    text-align: left;
}

dialog.tq-score-dialog .Table2D_body td {
    text-align: left;
}

dialog.tq-score-dialog .Table2D_body tr {
    height: 44px;
}

dialog.tq-score-dialog .Table2D_body tr:last-child {
    border-bottom: none;
}

/* Even rows use the global Table2D zebra fill, recoloured to light purple in
   styles.css (was WAF grey) — no per-dialog override needed. */

/* The dialog header is just the × now, so the table caption carries the visible
   title. The centered layout + right-aligned download + hidden summary all come
   from the global .Table2D_titlebar (WAFBaseCSS.css); here we only emphasise the
   title text as a near-black heading. */
dialog.tq-score-dialog .Table2D_titletext {
    font-weight: 600;
    color: var(--color-text-heading);
}

dialog.tq-score-dialog div.tq-score-result-header {
    margin: 0.5em 0 1em 0;
    padding: 0.75em 1em;
    border: 2px solid var(--color-primary);
    border-radius: var(--radius-md);
    background-color: var(--color-primary-tint);
}
dialog.tq-score-dialog div.tq-score-result-header div.tq-score-result-row {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    padding: 0.25em 0;
}
dialog.tq-score-dialog div.tq-score-result-header span.tq-score-result-label {
    font-weight: 600;
    margin-right: 1em;
    color: var(--color-text-heading);
}
dialog.tq-score-dialog div.tq-score-result-header span.tq-score-result-value {
    font-size: 1.5em;
    font-weight: 600;
    color: var(--color-primary-dark);
}
/* A notice about the item's scoring (e.g. an assertion that can never hold).
 * Amber with a leading warning glyph - not colour-only; #7c2d12 on #fef3c7
 * is AAA. */
dialog.tq-score-dialog div.tq-score-notice {
    margin: 0 0 1em 0;
}
dialog.tq-score-dialog div.tq-score-notice::before {
    content: "\26A0\00A0";   /* ⚠ warning sign */
    font-weight: 600;
}

/* Score-report standards info buttons + dialog. The ⓘ button rides each
 * assertion row (and the numeric score rows) in the DEFAULT report;
 * disabled (greyed, explanatory title) when the target has no aligned
 * standards. The framework name renders in small print after a standard's
 * text only when the bank spans multiple frameworks. Colors keep WCAG AAA
 * contrast on white (#444 = 9.7:1; #555 = 7.5:1). */
button.tq-info-btn {
    background: none;
    border: none;
    cursor: pointer;
    font-size: 1.1em;
    line-height: 1;
    padding: 2px 6px;
    color: var(--color-primary-dark);
}
button.tq-info-btn:disabled {
    color: var(--text-tertiary);
    cursor: not-allowed;
}
button.tq-info-btn:focus-visible {
    outline: 2px solid var(--color-primary-dark);
    outline-offset: 1px;
}

/* Incomplete-definition marker (EmptyDefinitionBadge): a VE with no
 * constraints that an assertion checks for (never holds) or that nothing
 * uses yet, or an assertion with no condition (always true) gets an amber background + ⓘ — no modal, saving stays allowed.
 * The class rides BOTH the container and the always-visible title row
 * (the accordion title paints its own background over the block's, so
 * the container alone was invisible). The warning tint, with the ⓘ glyph in
 * the warning colour on it. */
.tq-empty-def,
li.tq-assertion-item.tq-empty-def:hover,
li.tq-assertion-item.tq-empty-def:focus {
    background: var(--status-warning-tint);
}
button.tq-info-btn.tq-empty-info {
    color: var(--status-warning);
}
button.tq-info-btn.tq-empty-info:focus-visible {
    outline: 2px solid var(--focus-ring);
    outline-offset: 1px;
}
li.tq-assertion-item.tq-empty-def button.tq-empty-info {
    /* Assertion rows are flex — push the ⓘ to the row's far edge. */
    margin-left: auto;
}
td.tq-standards-cell {
    text-align: center;
    vertical-align: middle;
}
dialog.tq-standards-dialog {
    max-width: 44em;
}
dialog.tq-standards-dialog h3.tq-standards-title {
    margin: 0;
}
ul.tq-standards-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 10px;
}
li.tq-standard-item {
    line-height: 1.4;
}
li.tq-standard-item span.tq-standard-code {
    font-weight: 600;
    margin-right: 8px;
}
li.tq-standard-item span.tq-standard-framework {
    font-size: 0.8em;
    color: var(--text-primary);
    margin-left: 8px;
    white-space: nowrap;
}

/* Visually-hidden utility (screen-reader-only text), used for the standards
 * column's table header. */
.tq-sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

div.DISView_window > div.DISView_body div.tq-scoring-display {
    position: relative;
    width: 100%;
    height: 80vh;
    overflow: auto;
    /* Its scrollbar is a classic one (styles.css, the slim-scrollbar rule),
       kept in place so the shield can always find it. */
    scrollbar-gutter: stable;
    padding: 2em;
    box-sizing: border-box;
}
    div.DISView_window > div.DISView_body div.tq-scoring-display.tq-assertions-live {
        height: 50vh;
    }

/* Passage-set internal pane height for SHADOW-rendered items: the pane
   rules below cannot reach inside item roots, so the height ships in the
   DISView scoring extra sheet reading --tq-scoring-pane-max, which is set
   HERE (custom properties inherit through the shadow host) so the
   .tq-assertions-live shrink still tracks live panel state. */
div.DISView_window > div.DISView_body div.tq-scoring-display {
    --tq-scoring-pane-max: calc(80vh - 4em);
}
div.DISView_window > div.DISView_body div.tq-scoring-display.tq-assertions-live {
    --tq-scoring-pane-max: calc(50vh - 4em);
}

/* Single-scrollbar enforcement for the scoring view's right panel.
 *
 * Paldroe's .p-qti-item-container (and .p-qti-stimulus when a
 * stimulus is rendered) carry their own height + overflow:auto
 * (PaldroeStyles.css ~line 526/531) so they scroll independently
 * when used inside the runtime player. Stacked inside
 * .tq-scoring-display — which has its own height + overflow:auto —
 * those inner containers produce nested scroll regions. The
 * ItemShield positions itself over .tq-scoring-display with
 * height = parentDiv.scrollHeight (ItemShield.js _highlightEntity),
 * so it never extends into the nested scrollers; content past the
 * inner viewport sits behind the shield and the user can't scroll
 * to reach it.
 *
 * Strip the inner height + overflow inside .tq-scoring-display so
 * the sole scrollable container is .tq-scoring-display itself.
 * The shield then covers the full scroll-height uniformly and
 * every interaction stays reachable.
 */
div.DISView_window > div.DISView_body div.tq-scoring-display div.p-qti-item-container,
div.DISView_window > div.DISView_body div.tq-scoring-display div.p-qti-stimulus {
    height: auto;
    max-height: none;
    overflow: visible;
}

/* EXCEPTION to the single-scroller rule above, for the passage-set container's
 * INTERNAL split pane (it reuses .p-qti-stimulus / .p-qti-item-container under its
 * own .p-qti-stim-split). The rule above strips those panes' height + overflow so
 * .tq-scoring-display is the sole scroller — correct for single-item scoring + the
 * ItemShield, but it also flattens the passage-set's two panes into one outer
 * scroll. Scoped to .p-qti-stim-split (more specific, so it wins) and to the panes
 * UNDER it, so single-item scoring is untouched: re-instate each pane's own scroll,
 * bounded to the .tq-scoring-display box (80vh, less its 2em padding) so the passage
 * scrolls independently of the parts instead of growing the outer scroller.
 * (.tq-assertions-live shrinks that box to 50vh.)
 * SHADOW NOTE (keep in sync): the container's internal split now sits
 * inside the item's shadow root — the live copy of this height rule is in
 * DefineItemScoringView's scoring extra sheet, driven by
 * --tq-scoring-pane-max (set above). These rules remain for any legacy
 * light-DOM render. */
div.DISView_window > div.DISView_body div.tq-scoring-display .p-qti-stim-split > div.p-qti-stimulus,
div.DISView_window > div.DISView_body div.tq-scoring-display .p-qti-stim-split > div.p-qti-item-container {
    height: calc(80vh - 4em);
    overflow: auto;
}

    div.DISView_window > div.DISView_body div.tq-scoring-display.tq-assertions-live .p-qti-stim-split > div.p-qti-stimulus,
    div.DISView_window > div.DISView_body div.tq-scoring-display.tq-assertions-live .p-qti-stim-split > div.p-qti-item-container {
        height: calc(50vh - 4em);
    }

div.DISView_window > div.DISView_body div.tq-assertion-panel {
    height: 30vh;
    display:block;
    width: 100%;
}

    div.DISView_window > div.DISView_body div.tq-assertion-panel div.tq-header {
        border: 1px solid var(--control-border);
        border-radius: .5em;
        width: 100%;
        background: var(--surface);
        color: var(--text-primary);
        height: fit-content;
        display: flex;
        flex-direction: row;
        justify-content: space-between;
    }
        div.DISView_window > div.DISView_body div.tq-assertion-panel div.tq-header button {
            background-color: var(--surface);
            width: 1.5em;
            height: 1.5em;
            padding: 2px 2px 2px 2px;
        }
        div.DISView_window > div.DISView_body div.tq-assertion-panel div.tq-header textarea {
            width: 25em;
            height: 2em;
            resize: both;
            margin-left: .5em;
            margin-right: .5em;
        }

    div.DISView_window > div.DISView_body div.tq-assertion-panel div.tq-body {
    }

div.DISView_window > div.DISView_body div.tq-scoring-display div.tq-shield {
    height: 100%;
}

div.DISView_window div.tq-item-frame {
    position: relative;
    margin: 24px 16px 16px;
    border: 2px solid var(--divider);
    border-radius: var(--radius-md);
}

div.DISView_window div.tq-item-frame.tq-item-frame-unlocked {
    border-color: transparent;
}

/* The locked item's tab stop is the shield, which is as tall as the whole
   item: its own outline would scroll out of view. The frame, always in view,
   shows the focus instead (WCAG 2.4.7 / 2.4.13). */
div.DISView_window div.tq-item-frame div.tq-sheild:focus {
    outline: none;
}
div.DISView_window div.tq-item-frame:has(div.tq-sheild:focus-visible) {
    outline: var(--focus-outline);
    outline-offset: var(--focus-offset);
}

div.DISView_window div.tq-item-frame div.tq-lock-badge {
    position: absolute;
    top: 0;
    left: 12px;
    transform: translateY(-50%);
    display: flex;
    align-items: center;
    gap: 5px;
    padding: 3px 8px;
    background: var(--surface);
    border: 2px solid var(--divider);
    border-radius: var(--radius-md);
    z-index: 1;
}

div.DISView_window div.tq-item-frame div.tq-lock-badge.tq-lock-badge-hidden {
    display: none;
}

div.DISView_window div.tq-item-frame div.tq-lock-badge span.tq-lock-badge-icon {
    display: inline-block;
    width: 0.875rem;
    height: 0.875rem;
    flex-shrink: 0;
    background-color: var(--accent-fill);
    -webkit-mask-image: url('/images/lock.svg');
    mask-image: url('/images/lock.svg');
    -webkit-mask-size: contain;
    mask-size: contain;
    -webkit-mask-repeat: no-repeat;
    mask-repeat: no-repeat;
}

div.DISView_window > div.DISView_body div.tq-numeric-buttons{
    background-color: var(--fill);
    position: relative;
    width: 95%
}

    div.DISView_window > div.DISView_body div.tq-numeric-buttons > span.tq-control-span {
        z-index: 10;
        position: fixed;
        background-color: var(--accent-fill);
    }

    div.DISView_window > div.DISView_body div.tq-numeric-buttons > span.tq-control-span > button.Button_window {
        background-color: var(--accent-fill);
        color: var(--text-on-accent);
        height: 1.4em;
        padding: .1em 1em;
        height: 100%;
        margin-left: 1em;
        margin-top: .1em;
        margin-bottom: .1em;
    }
    div.DISView_window > div.DISView_body div.tq-numeric-buttons > button:disabled {
        background-color: var(--fill);
        opacity: 0.5;
    }

    div.DISView_window > div.DISView_body div.tq-numeric-buttons > span.tq-existing-score-span > span.tq-score-row > button.Button_window:not(.tq_delete) {
        background-color: transparent;
        border: 2px outset var(--control-border);
        margin: .1em .1em .1em .1em;
        padding: .1em;
        color: var(--text-primary);
    }

    /* Each existing score is a row: its main (edit) button + an integrated
       trashcan that deletes the score. */
    div.DISView_window > div.DISView_body div.tq-numeric-buttons > span.tq-existing-score-span > span.tq-score-row {
        display: inline-flex;
        align-items: center;
        gap: .15em;
        margin: .1em .25em .1em 0;
    }
    div.DISView_window > div.DISView_body div.tq-numeric-buttons > span.tq-existing-score-span > span.tq-score-row > button.tq_delete {
        min-width: 1.8em;
        min-height: 1.8em;
        background-size: 1.1em 1.1em;
    }
 
div .tq-side-panel div.tq-sample-panel {
    //overflow: auto;
    position: relative;
}
div .tq-side-panel div.tq-sample-panel button.tq-expandable-button:disabled {
    color: var(--color-text-muted);
    opacity: 0.6;
    cursor: not-allowed;
}

div .tq-side-panel div.tq-sample-panel button.tq-expandable-button:hover {
    background-color: var(--color-primary-tint);
    color: var(--color-primary-dark);
}

/* Full scoring's sample-response panel: Capture / Cancel are the app's buttons
 * in a row (SamplePanel.js; they were accordion headers, cert set 2026-10-01 #79). */
div.tq-sample-panel > div.tq-sample-panel-buttons {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin: 8px 0 12px 0;
}

/* ── Scoring side-panel accordion: overrides the global black AccBlock ── */
.DISView_window .tq-side-panel div.AccGroup_window {
    height: auto !important;
    overflow: visible;
}

.DISView_window .tq-side-panel div.AccGroup_window div.AccBlock_window {
    margin: 0 0 4px;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md, 10px);
    overflow: hidden;
}

.DISView_window .tq-side-panel div.AccGroup_window span.AccBlock_title .tq_delete {
    margin-left: auto;
    flex-shrink: 0;
    min-width: 44px;
    min-height: 44px;
    background-size: 1.1em 1.1em;
}

.DISView_window .tq-side-panel div.AccGroup_window .tq_delete:hover {
    background-color: var(--fill-hover);
}

/* BR-83: "assertions that use this virtual entity" — the link icon sits
 * immediately before the delete icon, so IT takes the auto margin that pushes
 * the pair to the right and the delete icon follows it directly. */
.tq_ve_uses {
    background-image: var(--icon-link);
    background-repeat: no-repeat;
    background-size: 1.1em 1.1em;
    background-position: center;
    min-width: 44px;
    min-height: 44px;
    border: none;
    background-color: transparent;
    cursor: pointer;
    border-radius: var(--radius-control);
    transition: background-color 120ms ease;
}
.tq_ve_uses:focus-visible {
    outline: var(--focus-outline);
    outline-offset: var(--focus-offset, 2px);
}
.DISView_window .tq-side-panel div.AccGroup_window span.AccBlock_title .tq_ve_uses {
    margin-left: auto;
    flex-shrink: 0;
}
.DISView_window .tq-side-panel div.AccGroup_window span.AccBlock_title .tq_ve_uses + .tq_delete {
    margin-left: 0;
}
.DISView_window .tq-side-panel div.AccGroup_window .tq_ve_uses:hover {
    background-color: var(--fill-hover);
}

/* The usage dialog: each assertion is a text button that opens it. */
/* Content is inserted straight into the WAF dialog's central div, which has no
 * padding of its own: inset it to line up with the dialog title. */
.tq-ve-usage-content {
    padding: 0 20px;
}
.tq-ve-usage-list {
    list-style: none;
    margin: 0.5em 0;
    padding: 0;
    max-height: 50vh;
    overflow-y: auto;
}
.tq-ve-usage-list > li {
    padding: 0.25em 0;
}
.tq-ve-usage-assertion {
    background: none;
    border: none;
    padding: 0.25em 0.25em;
    color: var(--color-primary-dark);
    text-decoration: underline;
    text-align: left;
    cursor: pointer;
    font: inherit;
}
.tq-ve-usage-assertion:hover {
    background-color: var(--color-primary-tint);
}
.tq-ve-usage-assertion:focus-visible {
    outline: var(--focus-outline);
    outline-offset: var(--focus-offset, 2px);
}
.tq-ve-usage-via {
    margin-left: 0.5em;
    font-style: italic;
    color: var(--color-text-muted);
}

/* Incomplete-definition marker on a VE title (EmptyDefinitionBadge): the
 * title rules above set background at 4-class specificity, so the generic
 * .tq-empty-def rule never won — match it here. Amber persists through
 * hover AND the open (active) state: the indicator must not vanish while
 * the author works the block. */
.DISView_window .tq-side-panel div.AccGroup_window span.AccBlock_title.tq-empty-def,
.DISView_window .tq-side-panel div.AccGroup_window span.AccBlock_title.tq-empty-def:hover,
.DISView_window .tq-side-panel div.AccGroup_window span.AccBlock_title.tq-empty-def.AccBlock_active {
    background: var(--status-warning-tint);
    color: var(--text-primary);
}

/* Implicit (identifier) VEs: no caret, no hover interaction */
.DISView_window .tq-side-panel div.AccGroup_window span.AccBlock_title.tq-ve-implicit-title::before {
    content: none;
}

.DISView_window .tq-side-panel div.AccGroup_window div.AccBlock_body {
    border: none;
    border-top: 1px solid var(--color-border);
    margin: 0;
    padding: 0;
    background: var(--surface);
}

.DISView_window .tq-side-panel div.AccGroup_window div.AccBlock_body > * {
    padding: 8px 12px 12px;
}

div .tq-side-panel div.tq-sample-panel.tq-sample-panel-overlay {
    z-index: 20;
    top: 0px;
    left: 0px;
    height: 100%;
    width: 100%;
    background-color: var(--accent-fill);
    position: absolute;
}

dialog.tq-dialog.tq-pattern-dialog div.tq-dialog-controls {
    display: block;
}

.tq-dialog.tq-pattern-dialog .tq-dialog-controls ul.CheckboxGroup_window {
    padding-left: 0px;
    display: flex;
}

.tq-scoring-section-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 6px 0;
}

.tq-scoring-section-header .tq-scoring-section-title {
    flex: 1;
}

.tq-scoring-section-header.tq-accordion-header {
    cursor: pointer;
    user-select: none;
}

.tq-accordion-caret {
    font-size: 1.1em;
    line-height: 1;
    margin-left: 6px;
    color: var(--color-text-muted);
    transition: transform 0.18s ease;
    display: inline-block;
}

.tq-scoring-section-header.tq-accordion-open .tq-accordion-caret {
    transform: rotate(90deg);
}

.tq-scoring-section-body {
    overflow: hidden;
}

.tq-new-assertion-btn {
    display: block;
    margin-left: auto;
    margin-top: 10px;
    margin-bottom: 8px;
    min-width: 44px;
    border: 1px solid transparent;
    white-space: nowrap;
}

.tq-assertion-list {
    list-style: none;
    margin: 0;
    padding: 0;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    overflow: hidden;
    margin-bottom: 4px;
}

.tq-assertion-item {
    display: flex;
    align-items: center;
    min-height: 44px;
    padding: 0 10px;
    font-size: 0.85em;
    border-bottom: 1px solid var(--color-border);
    cursor: pointer;
    user-select: none;
    color: var(--color-text-base);
}

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

.tq-assertion-item:hover,
.tq-assertion-item:focus {
    background: var(--color-primary-tint);
    color: var(--color-primary-dark);
    align-items: flex-start;
    padding-top: 12px;
    padding-bottom: 12px;
}

.tq-assertion-item:focus-visible {
    outline: 2px solid var(--color-primary-dark);
    outline-offset: -2px;
}

.tq-assertion-item-active {
    background: var(--selected-bg);
    color: var(--selected-text);
    box-shadow: var(--selected-mark);
}

.tq-assertion-item > span {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    min-width: 0;
}

.tq-assertion-item:hover > span,
.tq-assertion-item:focus > span {
    white-space: normal;
    overflow: visible;
    text-overflow: clip;
}

/* An assertion bound to another exemplar than the one the panel edits
   (bug report #25). Listed so it can be opened and deleted; the note says
   why it looks out of place. Colour stays the row's own (AAA on the tint). */
.tq-assertion-item.tq-assertion-item-foreign {
    flex-wrap: wrap;
    row-gap: 2px;
}
.tq-assertion-item.tq-assertion-item-foreign > span.tq-assertion-item-note {
    flex-basis: 100%;
    font-size: 0.82em;
    font-style: italic;
    white-space: normal;
    color: var(--color-text-muted);
}
.tq-assertion-item.tq-assertion-item-foreign:hover > span.tq-assertion-item-note,
.tq-assertion-item.tq-assertion-item-foreign:focus > span.tq-assertion-item-note,
.tq-assertion-item.tq-assertion-item-foreign.tq-assertion-item-active > span.tq-assertion-item-note {
    color: inherit;
}

div.tq-scoring-section {
    margin: 0 -12px;
    padding: 0 12px 8px;
    border-bottom: 1px solid var(--color-border);
}

.tq-deleted-items-accordion-container {
    margin: 0 -12px;
    padding: 0 12px 8px;
    border-bottom: 1px solid var(--color-border);
}

.tq-deleted-accordion-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 8px 0 4px;
    cursor: pointer;
    user-select: none;
}

.tq-deleted-accordion-caret {
    font-size: 1.1em;
    line-height: 1;
    transition: transform 0.18s ease;
}

.tq-deleted-accordion-header.tq-deleted-accordion-open .tq-deleted-accordion-caret {
    transform: rotate(90deg);
}

.tq-deleted-accordion-body {
    padding: 4px 0 2px;
}

.tq-deleted-section {
    overflow: hidden;
    margin-bottom: 6px;
}

.tq-deleted-section:last-child {
    margin-bottom: 0;
}

.tq-deleted-section-title {
    padding: 5px 10px;
    background: var(--bg-secondary);
}

.tq-deleted-items {
    list-style: none;
    margin: 0;
    padding: 0;
}

.tq-deleted-item {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 7px 10px;
    border-bottom: 1px solid var(--color-border);
    font-size: 0.82em;
}

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

.tq-deleted-item-label {
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    color: var(--color-text-base);
}

.tq-deleted-interaction-info {
    color: var(--color-text-muted);
}

.tq-cascade-container {
    display: flex;
    align-items: center;
    gap: 4px;
    font-size: 0.8em;
    color: var(--color-text-muted);
    white-space: nowrap;
}

.tq-restore-btn {
    flex-shrink: 0;
    min-width: 44px;
    border: 1px solid transparent;
    white-space: nowrap;
}

div.tq-scoring-section-title {
    padding: 8px 0 4px;
}

div.tq-property-widget-title {
    display: flex;
    align-items: center;
    justify-content: flex-start;
    background-color: var(--surface);
    padding: 6px 0 6px;
}

/* The exemplified checkbox + info icon, kept together at the left. */
.tq-property-toggle {
    display: inline-flex;
    align-items: center;
    flex: none;
}

.tq-property-toggle input[type="checkbox"] {
    margin: 0;
}

/* One em between the information icon and the start of the property label. */
div.tq-property-widget-title > label {
    margin-left: 0.5em;
}

/* Let property widgets fill the full width of their virtual-entity block. The
   global AccBlock_body has 1em side margins that inset the property area from
   the full-width VE titlebar; drop the side inset within the scoring panel
   only (other accordions keep their margins). */
.tq-sample-panel div.AccGroup_window div.AccBlock_body {
    margin-left: 0;
    margin-right: 0;
}

/* Info button next to the "exemplified" control: a circled "i" — white inside the
   circle, a heavier ring, and transparent outside the circle (so the dark title bar
   shows through the corners). */
/* The circled "i" that opens a feature's help modal (HelpIcon.js). It is the
   only affordance pointing at the help, so it is essential UI, not decoration:
   it uses --color-text-base (10.4:1, AAA) rather than the AA-only
   --color-text-muted it began with. */
button.tq-info-icon {
    background-color: var(--surface);
    color: var(--color-text-base);
    border: 1px solid var(--color-border);
    border-radius: 50%;            /* circle; corners outside it stay transparent */
    width: 1.2em;
    height: 1.2em;
    min-width: 1.2em;
    padding: 0;
    margin-left: 0.4em;
    font-size: 0.85em;
    font-style: italic;
    font-weight: 600;
    line-height: 1;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    flex: none;
}

button.tq-info-icon:hover {
    color: var(--color-primary-dark);
    border-color: var(--color-primary);
}

button.tq-info-icon:focus-visible {
    outline: 2px solid var(--color-primary-dark);
    outline-offset: 1px;
}

/* A WAF.Dialog title bar is a flex row with space-between, holding the title
   and the close button. HelpIcon.attachToDialog wraps the title text and the
   icon in this span so the bar keeps exactly TWO flex children — otherwise a
   third child is spread into the middle of the bar. */
span.tq-dialog-title-help {
    display: flex;
    align-items: center;
    gap: 6px;
    min-width: 0;
}

/* A setting's label and its help icon sit on one row, because the attribute
   widget around them is a flex COLUMN (label row above, input below). */
div.tq-attr-label-row {
    display: flex;
    align-items: center;
    gap: 2px;
}

/* Help modal body (WAF.notify's addClass hook). Help text is prose with
   bullet lists, not the one-line message AlertThen is normally given, so it
   is left-aligned and given room and leading to stay readable. */
.tq-help-body {
    text-align: left;
    max-width: 46em;
    line-height: 1.5;
}

.tq-help-body p {
    margin: 0 0 0.6em 0;
}

.tq-help-body ul {
    margin: 0 0 0.6em 0;
    padding-left: 1.3em;
    list-style: disc;
}

.tq-help-body li {
    margin-bottom: 0.3em;
}

.tq-help-body :last-child {
    margin-bottom: 0;
}

/* ── Demo video library (DemoVideoLibrary.js) ─────────────────────────────
   The Watch affordance inside the help modal, and the modal player itself.
   Contrast: --color-primary-dark (#3d2270) on white is ~12.9:1 — AAA (7:1)
   with margin in both the plain and the hover-inverted state. */
button.tq-video-watch {
    display: flex;
    align-items: center;
    gap: 0.5em;
    margin-top: 0.8em;
}

.tq-video-watch-glyph {
    font-size: 0.85em;
    line-height: 1;
}

/* The player video: always hosted inside a measured .ht-player-stage (the
   Help & Training tabs and the fullscreen overlay — the small modal player
   is retired, owner 2026-09-01). width/height are the pre-metadata
   fallback; DemoVideoLibrary.attachStageSizing sets px sizes so the
   contained frame plus the 60px control band always fits the stage, with
   the picture pinned to the top so the native control strip (anchored to
   the video's CONTENT box) lands on the band, never on the burned-in
   caption line. */
.tq-video-player {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: contain;
    object-position: 50% 0;
    background-color: #000;
}

/* The fullscreen overlay player (help modals' Watch): the whole viewport,
   the same bar + stage layout as the Help & Training tabs' players. */
dialog.tq-video-full-dialog[open] {
    width: 100vw;
    height: 100vh;
    max-width: none;
    max-height: none;
    margin: 0;
    border: none;
    padding: 0 1em;
    box-sizing: border-box;
    background-color: var(--surface);
}

.tq-video-summary {
    text-align: left;
    max-width: 46em;
    line-height: 1.5;
    margin: 0.6em 0 0 0;
}

/* ── Help & Training screen (HelpTrainingView.js) ─────────────────────────
   The video course + online user guide. Contrast: body text #26262b on
   white is ~15.6:1, the meta line #3f3f46 is ~10.4:1, and the primary-dark
   accents are ~12.9:1 — all past AAA (7:1). */
.ht-view {
    padding: 0 1.5em 2em 1.5em;
    max-width: 62em;
    text-align: left;
    color: var(--text-primary);
}

.ht-heading {
    display: flex;
    align-items: center;
    gap: 0.4em;
    color: var(--color-primary-dark);
}

/* Immersive chrome hides the heading via the hidden ATTRIBUTE — but the
   display:flex above would defeat the UA's [hidden] rule without this
   (live bug 2026-09-01: the heading stayed put while a guide section or
   full-size player was up, eating ~100px of the stage's viewport). */
.ht-heading[hidden] {
    display: none;
}

.ht-heading:focus-visible {
    outline: 2px solid var(--color-primary-dark);
    outline-offset: 2px;
}

.ht-chapter {
    margin: 1.2em 0;
}

.ht-chapter-title {
    color: var(--color-primary-dark);
    border-bottom: 1px solid var(--color-primary-dark);
    padding-bottom: 0.25em;
}

.ht-notice {
    max-width: 46em;
}

/* ── the course face ── */
.ht-video-list {
    list-style: none;
    margin: 0;
    padding: 0;
}

.ht-video-list > li {
    margin: 0.5em 0;
}

/* One course row: a real button, full-width, left-aligned. */
button.ht-video-row {
    display: flex;
    align-items: flex-start;
    gap: 0.7em;
    width: 100%;
    text-align: left;
    padding: 0.7em 0.9em;
    background-color: var(--surface);
    color: var(--text-primary);
    border: 1px solid var(--color-primary-dark);
    border-radius: var(--radius-md);
    font-size: 1em;
    cursor: pointer;
}

button.ht-video-row:hover {
    background-color: var(--fill-hover);
}

button.ht-video-row:focus-visible {
    outline: 2px solid var(--color-primary-dark);
    outline-offset: 2px;
}

.ht-video-glyph {
    color: var(--color-primary-dark);
    font-size: 0.9em;
    line-height: 1.6;
}

.ht-video-body {
    display: flex;
    flex-direction: column;
    gap: 0.15em;
}

.ht-video-meta {
    font-size: 0.9em;
    color: var(--text-primary);
}

.ht-video-summary {
    line-height: 1.45;
    max-width: 46em;
}

/* ── the guide face ── */
.ht-guide-toc ul {
    list-style: none;
    margin: 0.4em 0 1.4em 0;
    padding: 0;
}

button.ht-toc-link {
    background: none;
    border: none;
    padding: 0.25em 0.2em;
    font-size: 1em;
    color: var(--color-primary-dark);
    text-decoration: underline;
    cursor: pointer;
    text-align: left;
}

button.ht-toc-link:focus-visible {
    outline: 2px solid var(--color-primary-dark);
    outline-offset: 2px;
}

/* the printable edition's download, under the contents heading */
.ht-guide-download {
    display: block;
    margin: 0 0 1em 0;
}

.ht-guide-body {
    max-width: 46em;
    line-height: 1.55;
}

/* ── paged reading mode (Word-reading-mode style, owner 2026-09-01) ──
   The nav bar stays put; the page below is the one scrolling region. */
.ht-guide-nav,
.ht-player-bar {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.5em;
    padding: 0.5em 0;
    border-bottom: 1px solid var(--color-primary-dark);
    margin-bottom: 0.8em;
}

button.ht-nav-button {
    font-size: 1em;
    padding: 0.35em 0.9em;
    border: 1px solid var(--color-primary-dark);
    border-radius: var(--radius-md);
    background-color: var(--surface);
    color: var(--color-primary-dark);
    cursor: pointer;
}

button.ht-nav-button:hover:not(:disabled) {
    background-color: var(--color-primary-tint);
}

button.ht-nav-button:focus-visible {
    outline: 2px solid var(--color-primary-dark);
    outline-offset: 2px;
}

button.ht-nav-button:disabled {
    border-color: var(--control-border);   /* 4.5:1 on white — disabled UI is AA-exempt */
    color: var(--text-tertiary);
    cursor: default;
}

/* Reader nav: icon buttons on the left, the section title truly centered —
   the right-hand spacer mirrors the three-button group's width. */
button.ht-nav-icon {
    width: 44px;
    height: 44px;
    padding: 0;
    font-size: 1.25em;
    line-height: 1;
    border: 1px solid var(--color-primary-dark);
    border-radius: var(--radius-md);
    background-color: var(--surface);
    color: var(--color-primary-dark);
    cursor: pointer;
}

button.ht-nav-icon:hover:not(:disabled) {
    background-color: var(--color-primary-tint);
}

button.ht-nav-icon:focus-visible {
    outline: 2px solid var(--color-primary-dark);
    outline-offset: 2px;
}

button.ht-nav-icon:disabled {
    border-color: var(--control-border);
    color: var(--text-tertiary);
    cursor: default;
}

.ht-guide-nav-spacer {
    width: 148px;   /* three 44px buttons + two 0.5em gaps */
    flex-shrink: 1;
}

.ht-guide-where {
    flex: 1;
    text-align: center;
    color: var(--text-primary);
    font-weight: 600;
}

.ht-guide-page {
    max-height: calc(100vh - 21em);
    min-height: 14em;
    overflow-y: auto;
    padding-right: 0.6em;
}

/* ── immersive chrome (owner 2026-09-01): while reading a guide section or
   playing a course video, the screen heading is hidden and the view takes
   the full width and the remaining viewport height. Chrome above the page
   shrinks to the app banner + tabs + nav bar (~12em). ── */
.ht-view.ht-immersive {
    max-width: none;
}

.ht-view.ht-immersive .ht-guide-body {
    max-width: none;
}

.ht-view.ht-immersive .ht-guide-page {
    max-height: calc(100vh - 12em);
}

.ht-guide-page:focus-visible {
    outline: 2px solid var(--color-primary-dark);
    outline-offset: 2px;
}

.ht-toc-chapter {
    color: var(--color-primary-dark);
    margin: 1em 0 0.2em 0;
}

/* ── the course's full-size player ── */
.ht-player-title {
    margin-left: 0.4em;
}

/* The stage's height is set in px by DemoVideoLibrary.attachStageSizing —
   the MEASURED viewport remainder below the back bar (re-measured on
   resize and tab re-show) — so the whole frame always fits on screen. No
   em estimates here (owner bug 2026-09-01: the old max-height guesses put
   the burned-in captions below the fold). The video's own sizing lives on
   .tq-video-player above. */
.ht-player-stage {
    background-color: #000;
    border-radius: var(--radius-md);
    display: flex;
    align-items: center;
    justify-content: center;
}

.ht-guide-body a {
    color: var(--color-primary-dark);
}

.ht-guide-body code {
    background-color: var(--bg-secondary);
    border-radius: var(--radius-sm);
    padding: 0.05em 0.3em;
    color: var(--text-primary);
}

.ht-guide-body h4:focus-visible,
.ht-chapter-title:focus-visible {
    outline: 2px solid var(--color-primary-dark);
    outline-offset: 2px;
}

.tq-guide-img {
    max-width: 100%;
    border: 1px solid var(--control-border);
    border-radius: var(--radius-md);
}

/* Screenshot stand-in (placeholder:<key> images) until the screenshot
   pipeline lands: a clearly-styled box carrying the alt text plus the
   localized "coming" note the view appends. */
/* Blockquote callouts in the online guide (the '>' notes in the chapters). */
.tq-guide-callout {
    margin: 0.8em 0;
    padding: 0.6em 0.9em;
    border-left: 4px solid var(--color-primary-dark);
    border-radius: 0 6px 6px 0;
    background-color: var(--bg-secondary);
    color: var(--text-primary);
}

.tq-guide-callout p {
    margin: 0;
}

.tq-guide-screenshot-placeholder {
    display: flex;
    flex-direction: column;
    gap: 0.3em;
    align-items: center;
    justify-content: center;
    min-height: 7em;
    margin: 0.8em 0;
    padding: 1em;
    border: 2px dashed var(--control-border);
    border-radius: var(--radius-md);
    background-color: var(--fill);
    color: var(--text-tertiary);
    font-weight: 600;
}

/* A captured screenshot replacing a placeholder's content: fit the page
   column, and let the box drop its dashed "coming" chrome. */
.tq-guide-screenshot {
    display: block;
    max-width: 100%;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-1);
}

.tq-guide-screenshot-placeholder.ht-screenshot-filled {
    min-height: 0;
    padding: 0;
    border: none;
    background-color: transparent;
}

.ht-screenshot-note,
.ht-video-coming {
    font-size: 0.9em;
    font-weight: normal;
    font-style: italic;
    color: var(--text-primary);
}

.ht-video-coming {
    display: inline-block;
    margin-top: 0.6em;
}

div.tq-property-body {
    position: relative;
    padding-left: 1.25em;
    padding-top: 4px;
}

    .tq-pattern-dislay,
    div.tq-property-body button.tq-constraint-display {
        display: inline-flex;
        justify-content: space-evenly;
        width: 100%;
        padding-left: 0;
        border-radius: var(--radius-sm, 6px);
        border: 1px solid var(--color-border);
    }
    div.tq-property-body > div.RadioGroup_div0 > ul.RadioGroup_window {
        display: inline-flex;
        justify-content: space-between;
        width: 100%;
        padding-left: 0;
        border-radius: var(--radius-sm, 6px);
        border: 1px solid var(--color-border);
    }

    div.tq-property-body .p-qti-eq-frame {
        min-width: 100%;
    }

div.tq-property-body button:disabled {
    background-color: var(--color-disabled-bg);
    color: var(--color-disabled-text);
}
div.tq-property-body input {
    z-index: unset;
}

/* A wide table in a property card (the Same Solutions As sample) scrolls
   sideways in its own .tq-table-scroll (styles.css), never the 320px panel:
   inline-size containment keeps the table's width from widening the card,
   and the import report's 720px floor is dropped (the columns keep theirs). */
div.tq-property-body .tq-table-scroll {
    contain: inline-size;
}

div.tq-property-body .tq-table-scroll > table {
    min-width: 0;
}

/* The Same Solutions As sample's "Follows from, or why not" column (the
   fourth) holds a sentence: a floor of 16em keeps it to a few lines instead
   of a word or two per line, and the table scrolls sideways for it. Wrapped,
   never cut with an ellipsis: the whole reason stays readable without a
   tooltip a keyboard or touch user cannot reach. */
div.tq-property-body .tq-same-solutions-table.tq-table-scroll > table td:nth-child(4),
div.tq-property-body .tq-same-solutions-table.tq-table-scroll > table th:nth-child(4) {
    min-width: 16em;
}

div.tq-property-widget .tq-disable-sheild {
    background-color: transparent;
    position: absolute;
    z-index: 5;
    width: 100%;
    height: 100%;
    top: 0;
    left: 0;
    pointer-events: all;
}

div.tq-property-body:has(.tq-disable-sheild) > *:not(.tq-disable-sheild) {
    opacity: 0.38;
    pointer-events: none;
}

/* Open/close + selected styling key off the "exemplified" TOGGLE only. The
   :has() is scoped to .tq-property-toggle (the title-bar checkbox wrapper) on
   purpose: an unscoped :has(input[type=checkbox]...) also matches checkboxes
   INSIDE the editor body (e.g. the number widget's relative-tolerance checkbox,
   or the valid-comparison rows checkboxes), which kept those properties
   collapsed even when the author checked the toggle. Do not widen this. */
/* Selected (checked) property widget — title bar highlighted */
div.tq-property-widget:has(.tq-property-toggle input[type="checkbox"]:checked) div.tq-property-widget-title {
    background-color: var(--color-primary-tint);
    color: var(--color-primary-dark);
}

/* Non-selected (unchecked) property widget — collapse the body and show only a
   greyed-out header, so an inactive virtual-entity property reads as disabled
   without taking up space with its (unused) options. */
div.tq-property-widget:has(.tq-property-toggle input[type="checkbox"]:not(:checked)) div.tq-property-body {
    display: none;
}
div.tq-property-widget:has(.tq-property-toggle input[type="checkbox"]:not(:checked)) div.tq-property-widget-title {
    background-color: var(--fill);
    color: var(--text-primary);
}
div.tq-property-widget:has(.tq-property-toggle input[type="checkbox"]:not(:checked)) div.tq-property-widget-title > label {
    opacity: 0.5;
}

/* ===== Human-Scoring Rubric widgets (left scoring panel) =====
   Two property-widget-styled blocks (Shared Rubrics / Item-Specific
   Rubric) rendered by HumanScoringRubricSection. They reuse the
   tq-property-widget chrome; the rules below cover only their
   internals. */
.tq-human-rubric-section {
    margin: 4px 0 8px;
}

/* No enable toggle on rubric widgets — keep the title bar's label
   flush left where the toggle would have been. */
div.tq-rubric-widget div.tq-property-widget-title > label {
    margin-left: 0;
}

.tq-rubric-group {
    padding: 4px 0;
}

.tq-rubric-row {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 2px 0;
}

.tq-rubric-name {
    flex: 1;
    overflow-wrap: anywhere;
}

/* 7.46:1 on white — WCAG AAA for normal text. */
.tq-rubric-none {
    flex: 1;
    color: var(--text-secondary);
}

.tq-rubric-interaction-id {
    display: block;
    font-family: monospace;
    /* 7:1+ on white (AAA). */
    color: var(--text-primary);
}

/* In-development badge: white on #5c3c00 is ~9.4:1 (AAA). */
.tq-rubric-badge {
    margin-left: 6px;
}

.tq-rubric-status {
    font-size: 0.85em;
}

/* Visible placeholder shown when a property's widget fails to render, so it
   never silently vanishes from the panel. High-contrast warning, not colour-
   only (a leading warning glyph) for WCAG. */
div.tq-property-render-failed {
    display: flex;
    align-items: center;
    gap: 0.4em;
    padding: 0.4em 0.6em;
    border: 1px solid var(--status-danger);
    border-radius: var(--radius-sm);
    background-color: var(--status-danger-tint);
    color: var(--status-danger);
}

div.tq-property-render-failed::before {
    content: "\26A0";   /* ⚠ warning sign */
    font-weight: 600;
}

/* A compact field in the scoring panel. A fixed 24px, the smallest target
   the accessibility standard allows: in em it shrank with the field text. */
div.tq-property-body input.TextInput_window {
    height: 24px;
}

/* Region-predicate widget: status line above the "Choose region" button. */
div.tq-region-status {
    margin-bottom: 0.35em;
    font-style: italic;
    color: var(--text-primary);
}

/* Small icon button (a circle next to a square) that opens the drawing
   canvas. Mirrors the .tq_external_link reference button so the region
   widget's two actions read as a matched pair. */
button.tq-region-choose {
    background-image: var(--icon-circle-square);
    background-repeat: no-repeat;
    background-size: 1.25em 1.25em;
    background-position: center;
    background-color: transparent;
    min-width: 44px;
    min-height: 44px;
    border: 1px solid transparent;
    border-radius: var(--radius-sm, 4px);
    cursor: pointer;
    transition: background-color 120ms ease, border-color 120ms ease;
}
button.tq-region-choose:hover {
    background-color: var(--color-primary-tint);
    border-color: var(--color-primary);
}

/* Value editor = number field + reference (link) + delete (trash) buttons,
   living in one half-width grid cell. The two 44px (WCAG) buttons on the same
   row would crowd the field down to nothing (and the editor overflowed its
   cell). Let the field take a full row with the buttons wrapping beneath it,
   and min-width:0 so the editor (a grid item) shrinks to its cell instead of
   overflowing. */
.tq-number-property-editor {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 4px;
    min-width: 0;
}
.tq-number-property-editor > input.TextInput_window {
    flex: 1 1 100%;
    min-width: 0;
    box-sizing: border-box;
}

/* TextContains property widget — rubric authoring.
   The body lays out a label, a multi-line textarea, and an inline help
   line. Matches the surrounding tq-property-body shadow / radius so the
   control reads as part of the property family rather than a foreign
   input. Field colors stay at the default body/text colors (>= 7:1 on
   the body background per WCAG AAA); the help line uses a slightly
   muted hue but stays at the AAA 4.5:1 minimum for non-essential text.
   Browser focus ring is intentionally preserved (no outline override)
   so keyboard focus is visible. */
label.tq-property-textcontains-label {
    display: block;
    margin: 0.5rem 0 0.25rem 0;
    font-weight: 600;
}

textarea.tq-property-textcontains-input {
    display: block;
    width: 100%;
    min-height: 4.5em;
    resize: vertical;
}

div.tq-property-textcontains-help {
    margin: 0.4rem 0 0.25rem 0;
    color: var(--text-primary);                       /* >= 4.5:1 against #fff body */
    font-size: 0.9rem;
    line-height: 1.4;
}

/* SHADOW NOTE (keep in sync): scoring-entity highlights are stamped INSIDE
   shadow-rendered items — the live copies of the .tq-highlight /
   .p-qti-selected rules ride in DefineItemScoringView._presentItem's
   scoring extra sheet. These page rules remain for light-DOM widgets
   (simple-scoring panels, editor surfaces). */
.tq-highlight {
    background-color: var(--color-primary-tint, #F3EEFF);
    cursor: pointer;
}

/* The CustomSelectWidget button (used by InlineChoice) has an
   explicit `background: white` in PaldroeStyles.css at the same
   specificity as .tq-highlight, so the cascade order determines
   which wins — making the scoring-author hover highlight invisible.
   Raise specificity so .tq-highlight wins over the button's white
   default.

   Inputs and textareas don't usually carry a default background
   from a stylesheet, but the same rule covers them so the purple
   hover highlight on TextEntry / ExtendedText is robust against
   any future per-element background. */
button.tq-highlight,
input.tq-highlight,
textarea.tq-highlight,
.p-qti-custom-select-button.tq-highlight {
    background-color: var(--color-primary-tint, #F3EEFF);
}

.tq-dialog-widgets div.tq-reorderable-list ul {
    max-height: 9em;
    overflow: auto
}

figure {
    display: inline-block;
    margin-top: 0px;
}

div.p-qti-selected {
    outline: 3px solid red;
}

.tq_resizable.p-qti-columns {
    border: 1px dashed darkgrey;
    border-right: 1px dashed darkgrey;
    min-height: 2em;
    width: 100%;
    display: grid;

}

button.tq-draggable-indicator {
    background-image: var(--icon-menu);
    background-repeat: no-repeat;
    background-size: 20px 20px;
    background-position: center;
    border: none;
    height: 44px;
    width: 44px;
    flex-shrink: 0;
    margin-right: 0.5rem;
    color: var(--text-tertiary); /* text-gray-400 */
    padding: 0;
    border-radius: 0.125rem; /* rounded-sm */
    transition: color 150ms ease-in-out, box-shadow 150ms ease-in-out;
    outline: none; /* focus:outline-none */
}
    button.tq-draggable-indicator:hover {
        cursor: grab;
        box-shadow: var(--shadow-1); /* hover:shadow-md */
    }

button.tq_edit {
    background-image: var(--icon-edit);
    background-repeat: no-repeat;
    background-size: 1.5em 1.5em;
    background-position: center;
    min-width: 44px;
    min-height: 44px;
    border: none;
    background-color: transparent;
    cursor: pointer;
    border-radius: var(--radius-control);
    transition: background-color 120ms ease;
}
button.tq_edit:hover {
    background-color: var(--color-primary-tint);
}
button.tq_edit:focus-visible {
    outline: var(--focus-outline);
    outline-offset: var(--focus-offset, 2px);
}

/* Every toolbar TestQuill.makeQuill builds carries .tq-editor-toolbar —
   scope shared editor-toolbar chrome to THAT marker, never to an
   enumerated list of host window classes (each newly listed host was a
   bug waiting to happen: any editor host missing from the list rendered
   the custom buttons with no icon face — hit live in the rubric editor). */

/* WCAG 2.1 SC 2.5.5 requires minimum 44x44px touch targets */
div.ql-toolbar.ql-snow.tq-editor-toolbar button {
    min-width: 44px;
    min-height: 44px;
    padding: 8px;
}

div.ql-toolbar.ql-snow.tq-editor-toolbar button.ql-qti-interaction {
    background-image: url('/images/interaction-button.svg');
    background-repeat: no-repeat;
    background-size: 24px 24px;
    background-position: center;
}

div.ql-toolbar.ql-snow.tq-editor-toolbar button.ql-qti-markup {
    background-image: url('/images/markup-button.svg');
    background-repeat: no-repeat;
    background-size: 24px 24px;
    background-position: center;
}

div.ql-toolbar.ql-snow.tq-editor-toolbar button.ql-suppress-tts {
    background-image: url('/images/suppress-tts.svg');
    background-repeat: no-repeat;
    background-size: 24px 24px;
    background-position: center;
}

/* Compact the toolbar to help it stay on one line: trim the inter-group
   margin (Quill default 15px) and the toolbar padding. This reclaims width
   WITHOUT shrinking any button — the 24px targets stay at the WCAG AA floor
   (AAA target size is 44px, which a toolbar can't meet). */
div.ql-toolbar.ql-snow.tq-editor-toolbar {
    padding: 5px 6px;
}

div.ql-toolbar.ql-snow.tq-editor-toolbar .ql-formats {
    margin-right: 6px;
}

div.ql-toolbar.ql-snow.tq-editor-toolbar button.ql-columns {
    background-image: url('/images/columns.svg');
    background-repeat: no-repeat;
    background-size: 24px 24px;
    background-position: center;
}

div.ql-toolbar.ql-snow.tq-editor-toolbar button.ql-table {
    background-image: url('/images/table.svg');
    background-repeat: no-repeat;
    background-size: 24px 24px;
    background-position: center;
}

/* Section-break (horizontal rule) button — a line glyph via SVG data URI. */
div.ql-toolbar.ql-snow.tq-editor-toolbar button.ql-hr {
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 18 18'%3E%3Crect x='2' y='8' width='14' height='2' rx='1' fill='%23444'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-size: 24px 24px;
    background-position: center;
}

/* The section break as authors see it — the editor match to the delivery
   rule in QTIScripts/css/QtiBaseStyles.css (hr: 1px solid black top border,
   1rem vertical margins), so what the author sees is what candidates get. */
div.ql-editor hr {
    border: none;
    border-top: 1px solid #000;
    margin: 1rem 0;
    width: 100%;
}

/* Click-to-view button — a dialog-window glyph via SVG data URI. */
div.ql-toolbar.ql-snow.tq-editor-toolbar button.ql-click-to-view {
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 18 18'%3E%3Crect x='2' y='3' width='14' height='12' rx='1.5' fill='none' stroke='%23444' stroke-width='1.5'/%3E%3Cline x1='2' y1='6.5' x2='16' y2='6.5' stroke='%23444' stroke-width='1.5'/%3E%3Ccircle cx='9' cy='11' r='1.6' fill='%23444'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-size: 24px 24px;
    background-position: center;
}

/* Click-to-view box as the AUTHOR sees it in the body editor: the label
   renders as the same button-face students get (mirrors the delivery
   trigger styling in QTIScripts/css/PaldroeStyles.css); the content rides
   along hidden; a pencil appears on hover/focus to open the dialog. */
div.ql-editor .p-qti-click-to-view {
    position: relative;
    display: block;
    margin: 0.5em 0;
}

div.ql-editor .p-qti-click-to-view > .p-qti-ctv-label {
    display: inline-block;
    padding: 8px 16px;
    border: 1px solid #475467;
    border-radius: 6px;
    background: #f0f4f8;
    color: #101828;
    cursor: pointer;
    /* The label is a native <summary>; the box face reads as a button,
       not a disclosure widget — hide the marker (toggle is suppressed in
       the editor anyway; clicking opens the authoring dialog). */
    list-style: none;
}

div.ql-editor .p-qti-click-to-view > .p-qti-ctv-label::-webkit-details-marker {
    display: none;
}

div.ql-editor .p-qti-click-to-view > .p-qti-ctv-label:hover,
div.ql-editor .p-qti-click-to-view > .p-qti-ctv-label:focus {
    background: #e4e9f0;
}

/* Label lines are Quill <div> blocks; render them inline in the face. */
div.ql-editor .p-qti-click-to-view > .p-qti-ctv-label div {
    display: inline;
}

div.ql-editor .p-qti-click-to-view > .p-qti-ctv-content {
    display: none;
}

div.ql-editor .p-qti-click-to-view > button.tq-ctv-edit {
    position: absolute;
    top: 2px;
    left: -2px;
    transform: translateX(-100%);
    display: none;
    padding: 2px 6px;
    border: 1px solid #d0d5dd;
    border-radius: 6px;
    background: #ffffff;
    color: #101828;
    cursor: pointer;
    font-size: 14px;
    line-height: 1.2;
}

div.ql-editor .p-qti-click-to-view:hover > button.tq-ctv-edit,
div.ql-editor .p-qti-click-to-view:focus-within > button.tq-ctv-edit {
    display: inline-block;
}

/* The click-to-view authoring dialog: a modal-styled overlay, NOT the top
   layer. Everything that can open on top of it is either a showModal()
   top-layer dialog (interaction template, equation, special chars, image /
   asset dialogs, WAF.notify) — always above regardless of z-index — or
   stacked by z-index and must exceed these values: the interaction picker
   (.ip-overlay 199 / .ip-panel 200, styles.css) and the interaction hover
   toolbar (.tq-interaction-toolbar 1000). Keep this overlay/panel BELOW 199
   or the picker opens behind the dialog (a real, reported bug). */
.tq-ctv-overlay {
    position: fixed;
    inset: 0;
    z-index: 150;
    background: var(--scrim);
}

.tq-ctv-panel {
    position: fixed;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    z-index: 160;
    width: min(960px, 94vw);
    max-height: 88vh;
    overflow: auto;
}

.tq-ctv-panel > label {
    display: block;
    margin: 12px 0 4px;
    font-weight: 600;
    color: var(--text-primary);
}

.tq-ctv-panel .tq-ctv-content-editor .ql-container {
    min-height: 240px;
}

.tq-ctv-panel .tq-dialog-buttons {
    margin-top: 16px;
    display: flex;
    gap: 8px;
    justify-content: flex-end;
}

/* Special-character palette button — a glyph rather than an SVG asset. */
div.ql-toolbar.ql-snow.tq-editor-toolbar button.ql-special-char::before {
    content: "\03A9"; /* Ω */
    font-size: 15px;
    font-weight: 600;
    line-height: 1;
}

div.ql-toolbar.ql-snow.tq-editor-toolbar button.ql-restore-interaction {
    background-image: url('/images/restore-trash.svg');
    background-repeat: no-repeat;
    background-size: 24px 24px;
    background-position: center;
}

/* ============================================================
   Content tables (TQTable) — author-inserted semantic tables,
   distinct from the student-fillable TableInput interaction.
   ============================================================ */

/* Size to content and stay resizable. Quill's base stylesheet forces
   `.ql-editor table { width:100%; table-layout:fixed }`, which stretched every
   table across the whole editor; override it (higher specificity) so a new
   table is only as wide as its content and an author-set inline width wins. */
.ql-editor table.tq-content-table,
table.tq-content-table {
    width: auto;
    table-layout: auto;
    max-width: 100%;
    border-collapse: collapse;
    margin: 0.6em 0;
}

table.tq-content-table > tbody > tr > th,
table.tq-content-table > tbody > tr > td {
    border: 1px solid #98a2b3;
    padding: 6px 10px;
    min-width: 3em;
    vertical-align: top;
    text-align: left;
}

/* Header cells (column or row headers) read as emphasized. */
table.tq-content-table > tbody > tr > th {
    background: #eef2f6;
    font-weight: 600;
}

/* Content-editable cells shouldn't paint the browser's focus outline over
   the cell border; use a subtle inset highlight instead. */
table.tq-content-table > tbody > tr > td:focus,
table.tq-content-table > tbody > tr > th:focus {
    outline: none;
    box-shadow: inset 0 0 0 2px #b2ccff;
}

/* ---- cell lines + in-cell lists (cell-line model) ----------------------
   A cell holds one or more qti-cell-line elements (custom element, so it
   needs display:block); consecutive list lines group under qti-cell-list
   (role="list"; lines carry role="listitem"). Markers come from CSS —
   bullets via list-style, numbering via a counter reset per list, so a
   second list in the same cell restarts at 1. */
qti-cell-line,
qti-col-line {
    display: block;
}

qti-cell-list {
    display: block;
    padding-left: 1.6em;
    counter-reset: tq-cell-ol;
}

qti-cell-list > qti-cell-line,
qti-cell-list > qti-col-line {
    display: list-item;
}

qti-cell-list[data-list-kind="bullet"] > qti-cell-line,
qti-cell-list[data-list-kind="bullet"] > qti-col-line {
    list-style-type: disc;
}

qti-cell-list[data-list-kind="ordered"] > qti-cell-line,
qti-cell-list[data-list-kind="ordered"] > qti-col-line {
    list-style-type: none;
    counter-increment: tq-cell-ol;
}

qti-cell-list[data-list-kind="ordered"] > qti-cell-line::before,
qti-cell-list[data-list-kind="ordered"] > qti-col-line::before {
    content: counter(tq-cell-ol) ". ";
}

/* ---- contextual controls (portalled to <body>, positioned via inline styles) ---- */
.tq-table-controls {
    display: none;
    font-family: inherit;
}

/* Pills group the three actions for the hovered column (horizontal) or row
   (vertical) so they read as one control and stay compact near an edge. */
.tq-tc-pill {
    display: flex;
    gap: 3px;
    padding: 3px;
    border-radius: var(--radius-md);
    background: var(--surface);
    box-shadow: var(--shadow-1);
}

/* 24px hit target (WCAG 2.2 SC 2.5.8 AA); the equivalent right-click menu
   covers the 44px AAA target-size path. White glyph on a dark fill gives AAA
   text contrast (>=7:1) — see the per-kind notes below. */
.tq-tc-btn {
    width: 24px;
    height: 24px;
    padding: 0;
    box-sizing: border-box;
    border: 1px solid transparent;
    border-radius: 50%;
    color: var(--text-on-accent);
    font-size: 16px;
    font-weight: 600;
    line-height: 1;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    box-shadow: var(--shadow-1);
}

/* Insert = green, delete = red, so intent is obvious at a glance. */
.tq-tc-insert {
    background: var(--status-success); /* white on #14532d ~= 9.1:1 (AAA) */
}

.tq-tc-delete {
    background: var(--status-danger); /* white on #7f1d1d ~= 10.0:1 (AAA) */
}

/* Hover feedback that does NOT lighten the fill (which would erode the AAA
   contrast) — a focus-style ring instead. */
.tq-tc-btn:hover {
    box-shadow: var(--shadow-1),0 0 0 3px var(--focus-ring);
}

/* Visible keyboard focus (WCAG 2.4.7 / AAA 2.4.13 focus appearance). */
.tq-tc-btn:focus-visible {
    outline: 3px solid var(--focus-ring);
    outline-offset: 2px;
}

/* Right-edge drag handle to resize the table width. */
.tq-tc-resize {
    width: 10px;
    height: 40px;
    border-radius: var(--radius-sm);
    background: var(--accent-fill);
    border: 2px solid var(--surface);
    box-shadow: var(--shadow-1);
    cursor: ew-resize;
}

.tq-tc-resize:hover {
    background: var(--accent-fill-hover);
}

/* While a table-width drag is live (TQTableControls stamps this on
   <html>): keep the resize cursor and suppress text selection when the
   pointer outruns the handle mid-drag. */
html.tq-col-resizing,
html.tq-col-resizing * {
    cursor: ew-resize !important;
    -webkit-user-select: none !important;
    user-select: none !important;
}

/* ============================================================
   Special-character palette (SpecialCharPicker)
   ============================================================ */
dialog.tq-charpicker {
    width: min(560px, 92vw);
    max-height: 82vh;
    overflow: hidden;
}

dialog.tq-charpicker::backdrop {
    background: rgba(16, 24, 40, 0.35);
}

.tq-charpicker-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 12px 16px;
    border-bottom: 1px solid var(--divider);
}

.tq-charpicker-title {
    margin: 0;
}

.tq-charpicker-close {
    width: 28px;
    height: 28px;
    border: none;
    border-radius: var(--radius-md);
    background: transparent;
    font-size: 20px;
    line-height: 1;
    cursor: pointer;
    color: var(--text-secondary);
}

.tq-charpicker-close:hover {
    background: var(--fill-hover);
}

.tq-charpicker-closeafter-row {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 10px 16px;
    border-bottom: 1px solid var(--divider);
    font-size: 13px;
    color: var(--text-primary);
    cursor: pointer;
}

.tq-charpicker-body {
    padding: 8px 16px 16px;
    overflow-y: auto;
    max-height: calc(82vh - 130px);
}

.tq-charpicker-heading {
    margin: 12px 0 6px;
}

.tq-charpicker-grid {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
}

.tq-charpicker-char {
    width: 36px;
    height: 36px;
    padding: 0;
    box-sizing: border-box;
    border: 1px solid var(--divider);
    border-radius: var(--radius-md);
    background: var(--surface);
    font-size: 20px;
    line-height: 1;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}

.tq-charpicker-char:hover {
    background: var(--fill-hover);
    border-color: var(--divider);
}

.tq-charpicker-char:focus-visible {
    outline: 2px solid var(--focus-ring);
    outline-offset: 1px;
}

/* ============================================================
   Footnote block style (header value 'footnote' -> div.qti-footnote)
   ============================================================ */
/* Styles-dropdown option label (mirrors Quill's built-in header labels). */
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="footnote"]::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="footnote"]::before {
    content: "Footnote";
    font-size: 0.8em;
}

/* Footnote appearance in the editor — mirrors the delivery rule in
   QTIScripts/css/PaldroeStyles.css so authoring matches what students see. */
.qti-footnote {
    font-size: 0.85em;
    color: #475467;
    border-top: 1px solid #d0d5dd;
    margin-top: 0.75em;
    padding-top: 0.4em;
}

/* QtiMarkup content styling - blue text and blue borders */
tq-markup {
    color: #1565c0;
}

tq-markup img,
tq-markup figure,
tq-markup iframe {
    border: 2px solid #1565c0;
}

/* SuppressTTS content styling - red underline */
tq-suppress-tts {
    text-decoration: underline;
    text-decoration-color: #c62828;
    text-decoration-thickness: 2px;
}

div.ql-toolbar.ql-snow.tq-editor-toolbar button.ql-float {
    background-image: url('/images/floatNone.png');
    background-repeat: no-repeat;
    background-size: contain;
    height: 1em;
    width: 1em;
    margin: .1em .1em.1em.1em;
}
    div.ql-toolbar.ql-snow.tq-editor-toolbar button.ql-float[value=left] {
        background-image: url('/images/floatLeft.png');
        background-repeat: no-repeat;
        background-size: contain;
        height: 1em;
        width: 1em;
        margin: .1em .1em.1em.1em;
    }

    div.ql-toolbar.ql-snow.tq-editor-toolbar button.ql-float[value=right] {
        background-image: url('/images/floatRight.png');
        background-repeat: no-repeat;
        background-size: contain;
        height: 1em;
        width: 1em;
        margin: .1em .1em.1em.1em;
    }

span.tq_resizable.tq-stand-in[data-tq-type="figure"] {
    display: inline-block;
    text-align: center;
    margin: 1em 1em 1em 1em;
}
/* Paragraph blocks: tag-agnostic. The Paragraph blot renders a <qti-span>
   (Paragraph.js tagName='qti-span'), so a div-only selector left new paragraphs
   as the custom element's default display:inline — Enter created a paragraph but
   the caret didn't visually move to a new line (it lagged a line behind). Match
   the paragraph by its data-tq-type, whatever element carries it. */
.tq-stand-in[data-tq-type="p"] {
    display: block;
}

.tq-stand-in.ql-align-center[data-tq-type="p"] {
    display: flex;
    width: 100%;
    flex-direction: row;
    justify-content: center;
}
.tq-stand-in.ql-align-right[data-tq-type="p"] {
    display: flex;
    width: 100%;
    flex-direction: row;
    justify-content: end;
}
.tq-stand-in.ql-align-center[data-tq-type="p"] {
    display: flex;
    width: 100%;
    flex-direction: row;
    align-content: center;
}

.tq-stand-in[data-tq-type="p"]:has(br:first-child) {
    display: block;
}

/* Shift+Enter's soft break: the SoftBreak blot renders <qti-softbreak data-tq-type="br">, a custom
   element (inline by default) holding a placeholder space, so it breaks the line only as a block.
   Editor-only: the export and every render turn it into a plain <br>, which needs no rule (until
   2026-10-02 this was `.p-qti-soft-break` in PaldroeStyles.css, and the class rode out on every
   exported and previewed br). */
.tq-stand-in[data-tq-type="br"] {
    display: block;
}

span.TreeNode_normal.tq_highlight {
    border:groove;
    background-color: var(--accent-tint);
}

div.tq-gap-images-container {
    display: flex;
    flex-direction: row;
    flex-wrap: wrap;
    gap: 1em;
    padding: 1em;
    margin-top: 1em;
    border: 2px dashed var(--divider);
    border-radius: var(--radius-sm);
    background: var(--bg-secondary);
    min-height: 60px;
}

div.tq-gap-image {
    width: 50px;
    height: auto;
    resize: horizontal;      /* width-only; height follows the locked aspect-ratio (set in GapImage.js) so the picture never stretches */
    display: block;
    overflow: hidden;
    position: relative;
    border: 2px solid var(--divider);
    border-radius: var(--radius-sm);
    background: var(--surface);
    cursor: pointer;
    transition: all 0.2s;
    /* aspect-ratio will be set dynamically via JavaScript */
}

    div.tq-gap-image:hover {
        border-color: var(--accent);
        transform: scale(1.05);
    }

    div.tq-gap-image.p-qti-selected {
        border-color: #0066cc;
        box-shadow: 0 0 5px rgba(0, 102, 204, 0.5);
    }

div.tq-gap-image > img {
    width: 100%;
    height: auto;
}

    div.tq-gap-image > button {
        position: absolute;
        top: 0px;
        left: 0px;
        z-index: 10;
    }

/* A TEXT choice (qti-gap-text) in the graphic gap match palette, beside the
   images (Q8-L2-A6). Its text is the author's; the focus ring is the
   house focus outline (WCAG 2.4.7 / 2.4.13). */
div.tq-gap-text {
    display: inline-flex;
    align-items: center;
    gap: 0.25em;
    position: relative;
    min-height: 44px;
    padding: 0.25em 0.75em;
    border: 2px solid var(--control-border);
    border-radius: var(--radius-sm);
    background: var(--surface);
    color: var(--text-primary);
    cursor: pointer;
}
    div.tq-gap-text.p-qti-selected {
        border-color: #0066cc;
        box-shadow: 0 0 5px rgba(0, 102, 204, 0.5);
    }
    div.tq-gap-text:focus-visible {
        outline: var(--focus-outline);
        outline-offset: var(--focus-offset, 2px);
    }
    div.tq-gap-text > button.tq_properties {
        position: static;
    }

button.tq-tool-button {
    width: 36px;
    height: 36px;
    border: 3px groove var(--divider);
    padding: 0px 0px 0px 0px;
}

.tq-missing-required {
    background-color: var(--status-danger-tint);
    border: 2px solid var(--status-danger);
}

.tq_button_span {
    display: inline-flex;
    align-items: center;
    margin-left: auto;
    flex-shrink: 0;
}

.node-widget > div:first-child {
    display: flex;
    align-items: center;
    min-height: 44px;
    padding: 0 4px;
}

.tq_properties {
    background-image: var(--icon-settings);
    background-repeat: no-repeat;
    background-size: 1.5em 1.5em;
    background-position: center;
    min-width: 44px;
    min-height: 44px;
    border: none;
    background-color: transparent;
    cursor: pointer;
    border-radius: var(--radius-control);
    transition: background-color 120ms ease;
}
.tq_properties:hover {
    background-color: var(--color-primary-tint);
}
.tq_properties:focus-visible {
    outline: var(--focus-outline);
    outline-offset: var(--focus-offset, 2px);
}
/* The settings wheel hosts a background-image gear icon and sets
   border:none / background-color:transparent, which (equal specificity,
   later in source) overrode the generic .tq-missing-required red flag — so
   a missing required attribute marked the wheel but it never visibly turned
   red, i.e. validation failed silently. Re-assert the red error state with
   higher specificity so the wheel clearly turns red while the gear stays
   legible. */
.tq_properties.tq-missing-required {
    background-color: var(--status-danger-tint);
    border: 2px solid var(--status-danger);
}
.tq_delete {
    background-image: var(--icon-trash-2);
    background-repeat: no-repeat;
    background-size: 1.5em 1.5em;
    background-position: center;
    min-width: 44px;
    min-height: 44px;
    border: none;
    background-color: transparent;
    cursor: pointer;
    border-radius: var(--radius-control);
    transition: background-color 120ms ease;
}
.tq_delete:hover {
    background-color: var(--status-danger-tint);
}
.tq_delete:focus-visible {
    outline: var(--focus-outline);
    outline-offset: var(--focus-offset, 2px);
}

/* Choice reorder buttons — same icon-button pattern as their
   siblings; chevrons from the shared icon set. */
.tq_move_up,
.tq_move_down {
    background-repeat: no-repeat;
    background-size: 1.5em 1.5em;
    background-position: center;
    min-width: 44px;
    min-height: 44px;
    border: none;
    background-color: transparent;
    cursor: pointer;
    border-radius: var(--radius-control);
    transition: background-color 120ms ease;
}
.tq_move_up { background-image: var(--icon-chevron-up); }
.tq_move_down { background-image: var(--icon-chevron-down); }
.tq_move_up:hover,
.tq_move_down:hover {
    background-color: var(--color-primary-tint);
}
.tq_move_up:focus-visible,
.tq_move_down:focus-visible {
    outline: var(--focus-outline);
    outline-offset: var(--focus-offset, 2px);
}

/* Icon buttons that share a table cell stay on one line, whatever width
   the table gives that cell. Left to wrap, the three buttons of a row stood
   one above the other and made every row three buttons tall. */
td:has(> .tq_copy, > .tq_rename, > .tq_delete) {
    white-space: nowrap;
}

/* A tag beside the buttons (Shared) sits level with their middle. */
td:has(> .tq_copy, > .tq_rename, > .tq_delete) > * {
    vertical-align: middle;
}

/* Copy / rename siblings of .tq_delete — same icon-button pattern,
   non-destructive hover tint. */
.tq_copy,
.tq_rename,
.tq_consider,
.ih-nav-arrow,
.ih-collapse-btn {
    background-repeat: no-repeat;
    background-size: 1.5em 1.5em;
    background-position: center;
    min-width: 44px;
    min-height: 44px;
    border: none;
    background-color: transparent;
    cursor: pointer;
    border-radius: var(--radius-control);
    transition: background-color 120ms ease;
}
.tq_copy {
    background-image: var(--icon-copy);
}
.tq_rename {
    background-image: var(--icon-edit-3);
}
.tq_consider {
    background-image: var(--icon-consider-replace);
}
.tq_copy:hover,
.tq_rename:hover,
.tq_consider:hover,
.ih-nav-arrow:hover:not(:disabled),
.ih-collapse-btn:hover {
    background-color: var(--color-primary-tint);
}
.tq_copy:focus-visible,
.tq_rename:focus-visible,
.tq_consider:focus-visible {
    outline: var(--focus-outline);
    outline-offset: var(--focus-offset, 2px);
}

/* An icon button that cannot be used: half strength, like any other button. */
.tq_copy:disabled,
.tq_rename:disabled,
.tq_consider:disabled,
.tq_delete:disabled,
.ih-nav-arrow:disabled {
    opacity: 0.5;
    cursor: not-allowed;
}

div.DISView_window > div.DISView_body div.tq-numeric-buttons > button.Button_window.tq_add,
.tq_add {
    background-image: var(--icon-plus-square);
    background-repeat: no-repeat;
    background-size: 1.5em 1.5em;
    background-position: center;
    min-width: 44px;
    min-height: 44px;
    background-color: transparent;
    border: 1px solid transparent;
    cursor: pointer;
    border-radius: var(--radius-sm, 4px);
    transition: background-color 120ms ease, border-color 120ms ease;
}
div.DISView_window > div.DISView_body div.tq-numeric-buttons > button.Button_window.tq_add:hover,
.tq_add:hover {
    background-color: var(--color-primary-tint);
    border-color: var(--color-primary);
}
.tq_add:focus-visible {
    outline: var(--focus-outline);
    outline-offset: var(--focus-offset, 2px);
}
.tq_subtract {
    background-image: var(--icon-minus-square);
    background-repeat: no-repeat;
    background-size: contain;
    height: 1.5em;
    width: 1.5em;
    margin: .1em .1em.1em.1em;
}

.tq_link_edit {
    background-image: var(--icon-edit-2);
    background-repeat: no-repeat;
    background-size: 1.25em 1.25em;
    background-position: center;
    background-color: transparent;
    min-width: 44px;
    min-height: 44px;
    border: 1px solid transparent;
    border-radius: var(--radius-sm, 4px);
    cursor: pointer;
    transition: background-color 120ms ease, border-color 120ms ease;
}
.tq_link_edit:hover {
    background-color: var(--color-primary-tint);
    border-color: var(--color-primary);
}
.tq_link_edit:focus-visible {
    outline: var(--focus-outline);
    outline-offset: var(--focus-offset);
}

.tq_external_link {
    background-image: var(--icon-external-link);
    background-repeat: no-repeat;
    background-size: 1.25em 1.25em;
    background-position: center;
    background-color: transparent;
    min-width: 44px;
    min-height: 44px;
    border: 1px solid transparent;
    border-radius: var(--radius-sm, 4px);
    cursor: pointer;
    transition: background-color 120ms ease, border-color 120ms ease;
}
.tq_external_link:hover {
    background-color: var(--color-primary-tint);
    border-color: var(--color-primary);
}
.tq_remove_external_link {
    background-image: var(--icon-trash-2);
    background-repeat: no-repeat;
    background-size: 1.25em 1.25em;
    background-position: center;
    background-color: transparent;
    min-width: 44px;
    min-height: 44px;
    border: 1px solid transparent;
    border-radius: var(--radius-sm, 4px);
    cursor: pointer;
    transition: background-color 120ms ease, border-color 120ms ease;
}
.tq_remove_external_link:hover {
    background-color: var(--status-danger-tint);
    border-color: var(--status-danger);
}

.tq_start_point {
    background-image: var(--icon-start-point);
    background-repeat: no-repeat;
    background-size: contain;
    height: 1.5em;
    width: 1.5em;
    margin: .1em .1em.1em.1em;
    border: none;
}
.tq_intersects {
    background-image: var(--icon-intersects);
    background-repeat: no-repeat;
    background-size: contain;
    height: 1.5em;
    width: 1.5em;
    margin: .1em .1em.1em.1em;
    border: none;
}
.tq_points_towards {
    background-image: var(--icon-points-towards);
    background-repeat: no-repeat;
    background-size: contain;
    height: 1.5em;
    width: 1.5em;
    margin: .1em .1em.1em.1em;
    border: none;
}

.tq_close {
    background-image: var(--icon-close);
    background-repeat: no-repeat;
    background-size: contain;
    height: 1.5em;
    width: 1.5em;
    margin: .1em .1em.1em.1em;
}
.tq_circle-arrow-left {
    background-image: var(--icon-arrow-left-circle);
    background-repeat: no-repeat;
    background-size: contain;
    height: 1.5em;
    width: 1.5em;
    margin: .1em .1em.1em.1em;
    border: none;
    background-color: transparent;
}
.tq_circle-arrow-right {
    background-image: var(--icon-arrow-right-circle);
    background-repeat: no-repeat;
    background-size: contain;
    height: 1.5em;
    width: 1.5em;
    margin: .1em .1em.1em.1em;
}

.tq_layout {
    background-image: var(--icon-layout);
    background-repeat: no-repeat;
    background-size: 1.5em 1.5em;
    background-position: center;
    min-width: 44px;
    min-height: 44px;
    border: none;
    background-color: transparent;
    cursor: pointer;
    border-radius: var(--radius-control);
    transition: background-color 120ms ease;
}
.tq_layout:hover {
    background-color: var(--color-primary-tint);
}
.tq_layout:focus-visible {
    outline: var(--focus-outline);
    outline-offset: var(--focus-offset, 2px);
}
.tq_image {
    background-image: var(--icon-image);
    background-repeat: no-repeat;
    background-size: contain;
    height: 1.5em;
    width: 1.5em;
    margin: .1em .1em.1em.1em;
}

.tq_hotspot {
    background-image: var(--icon-crosshair);
    background-repeat: no-repeat;
    background-size: contain;
    height: 1.5em;
    width: 1.5em;
    margin: .1em .1em.1em.1em;
}

.tq-big-btn {
    display: block;
    width: 100%;
}

.tq-big-add-btn {
    display: block;
    background-image: var(--icon-plus-square);
    background-repeat: no-repeat;
    background-size: contain;
    background-position: center;
    background-color:var(--fill);
    width:100%;
    height: 1.5em;
}

.tq-expandable-button {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.5em;
    background-image: none;
    background-color: transparent;
    color: var(--color-text-base);
    width: 100%;
    height: auto;
    padding: 0.55em 0.75em;
    text-align: left;
    font-size: 0.875em;
    border: none;
    border-bottom: 1px solid var(--color-border);
    cursor: pointer;
    box-sizing: border-box;
    transition: var(--btn-transition, background-color 0.15s ease);
}

.tq-expandable-button::after {
    content: '';
    display: block;
    width: 0.45em;
    height: 0.45em;
    border-right: 2px solid currentColor;
    border-bottom: 2px solid currentColor;
    transform: rotate(45deg) translateY(-2px);
    flex-shrink: 0;
    transition: transform 200ms ease;
}

.tq-expandable-button.tq-selected::after {
    transform: rotate(-135deg) translateY(2px);
}

.tq-assertion-selector {
    display: block;
    width: max-content;
    background-color: var(--fill);
}
.tq-assertion-selector div.tq-title {
    text-align: center;
}

.tq-assertion-selector div.tq-body {
    display: block;
}
.tq-assertion-selector div.tq-body > span{
    display: block;
} 
.tq-assertion-selector div.tq-body input.tq-map {
    width: 5em;
}

/* The numeric score's points mapping inside its dialog (NumericMappingDialog:
 * a BasicDialog). It rendered with the side panel's grey block, browser-default
 * type and bare radios (cert set 2026-10-01 #78): now the dialog's own type, a
 * points column and the assertion beside it. */
dialog.tq-basic-dialog .tq-assertion-selector.tq-assertion-mapping {
    width: auto;
    background-color: transparent;
    font: inherit;
}
dialog.tq-basic-dialog .tq-assertion-mapping div.tq-title {
    text-align: left;
    margin-bottom: 8px;
}
dialog.tq-basic-dialog .tq-assertion-mapping div.tq-take-maximum label {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    margin-bottom: 12px;
}
dialog.tq-basic-dialog .tq-assertion-mapping div.tq-body > .tq-mapping-head,
dialog.tq-basic-dialog .tq-assertion-mapping div.tq-body > span {
    display: grid;
    grid-template-columns: 6em 1fr;
    align-items: center;
    gap: 12px;
    padding: 6px 0;
    border-bottom: 1px solid var(--divider);
}
dialog.tq-basic-dialog .tq-assertion-mapping div.tq-body input.tq-map {
    width: 5em;
    padding: 4px 6px;
    border: 1px solid var(--field-border);
    border-radius: var(--radius-field);
    font: inherit;
}

div.tq-calc {
    margin-top: 1em;
}

div.tq-calc button.Button_window {
    width: 100%;
}

.tq_dialog {
    display: flex;
    flex-direction: column;
}
/* Legacy alias — CssClassEditor now uses .app-dialog */
.tq-entity-dialog {
    display: grid;
    background-color: var(--fill);
    border: 4px outset;
    border-radius: 5%;
    width: max-content;
}

.tq-side-panel {
    max-width: none;
    padding: 0 12px;
    display: flex;
    flex-direction: column;
    background-color: var(--surface);
    border-right: 1px solid var(--divider);
    box-sizing: border-box;
}

div.tq-side-panel div.tq-calc {
    overflow-y: auto;
    position: relative;
}

.tq-entity-dialog > div.tq-controls {
    justify-content: space-around;
    border-bottom: none;
    padding: 0;
}

.tq-side-panel > button.Button_window {
    background-color: transparent;
    border: none;
    border-bottom: 1px solid var(--divider);
    width: calc(100% + 24px);
    margin-left: -12px;
    margin-right: -12px;
    height: 40px;
    min-height: 40px;
    flex-shrink: 0;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    border-radius: 0;
    box-sizing: border-box;
    background-position: center;
    background-size: 20px 20px;
}

.tq-side-panel > button.Button_window:hover {
    background-color: var(--fill-hover);
}

.tq-side-panel > button.Button_window:focus-visible {
    outline: 3px solid var(--color-primary);
    outline-offset: -3px;
}

button.tq-panel-toggle-btn {
    background-color: transparent;
    box-shadow: none;
    border: none;
    width: 44px;
    height: 44px;
    min-width: 44px;
    min-height: 44px;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    padding: 0;
    border-radius: var(--radius-control);
    transition: background-color 120ms ease;
}

button.tq-panel-toggle-btn:hover {
    background-color: var(--color-primary-tint);
    border: 1px solid var(--color-primary);
}

button.tq-panel-toggle-btn:focus-visible {
    outline: var(--focus-outline);
    outline-offset: var(--focus-offset, 2px);
}

button.tq-panel-toggle-btn.tq_circle-arrow-right,
button.tq-panel-toggle-btn.tq_circle-arrow-left {
    background-image: none;
    height: 44px;
    width: 44px;
    margin: 0;
}

button.tq-panel-toggle-btn::after {
    content: '';
    display: block;
    width: 7px;
    height: 7px;
    border-right: 2px solid var(--control-border);
    border-top: 2px solid var(--control-border);
}

button.tq-panel-toggle-btn.tq_circle-arrow-right::after {
    transform: rotate(45deg);
}

button.tq-panel-toggle-btn.tq_circle-arrow-left::after {
    transform: rotate(-135deg);
}

.tq-controls {
    display: flex;
    flex-direction: row;
    align-items: center;
    gap: 8px;
    padding: 8px 12px;
    border-bottom: 1px solid var(--divider);
    box-sizing: border-box;
}

.tq-controls > span.tq-score-action {
    margin-left: 4em;
    display: inline-flex;
    align-items: center;
    gap: 0.5em;
}

.tq-controls > span.tq-score-action input.tq-show-intermediates {
    margin: 0;
}

.tq-controls > span.tq-score-action label.tq-show-intermediates-label {
    white-space: nowrap;
    font-size: 0.72em;
    color: var(--color-text-muted);
    line-height: 1;
}

 div.tq-side-panel div.tq-calc div.tq-controls {
     display: block;
     overflow-y: auto;
     overflow-x: overlay;
     border-bottom: none;
     padding: 0;
 }
 

/* Floating Edit/Reload toolbar for interactions. It is a single element
   appended to <body> (not inside the Quill editor content), shown via JS on
   hover over an interaction iframe and pinned to the iframe's top-right corner
   with position:fixed. Kept out of the editor's content tree so Quill never
   reparents the iframe (which would reload it). JS toggles display:flex;
   default is hidden. */
.tq-interaction-toolbar {
    position: fixed;
    z-index: 1000;
    display: none;
    gap: 4px;
    padding: 4px;
    border-radius: var(--radius-md);
    background: var(--surface);
    border: 1px solid var(--divider);
    box-shadow: var(--shadow-1);
}

/* Self-contained icon buttons for the interaction toolbar. Not coupled to the
   shared tq_edit icon class — this toolbar owns its button styling and icon
   size, so it doesn't have to match every other edit button. The 44x44 hit-area
   (WCAG 2.5.5) is kept; only the <img> glyph is smaller. */
.tq-interaction-toolbar button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 44px;
    min-height: 44px;
    padding: 0;
    border: none;
    background-color: transparent;
    cursor: pointer;
    border-radius: var(--radius-control);
    transition: background-color 120ms ease;
}
.tq-interaction-toolbar button:hover {
    background-color: var(--color-primary-tint);
}
/* Delete is destructive — red hover like .tq_delete */
.tq-interaction-toolbar button.tq-interaction-delete-btn:hover {
    background-color: var(--status-danger-tint);
}
.tq-interaction-toolbar button:focus-visible {
    outline: var(--focus-outline);
    outline-offset: var(--focus-offset, 2px);
}
.tq-interaction-toolbar-icon {
    width: 18px;
    height: 18px;
    display: block;
}
.property-widget {
    padding-left: 2em;
}

dialog.tq-dialog {
    z-index: 50;
    position: fixed;
    align-self: anchor-center;
}

.tq-entity-dialog > caption {
    font-size:larger;
    font-weight: 600;
    align-self:center;
}

.tq-dialog-widgets {
    display: grid;
    grid-template-columns: 1fr 1fr;
}

/* Property widget label cells. Labels are camelCase i18n tags like
 * .validComparisonShowsForValues. with no whitespace wrap opportunities;
 * `overflow-wrap: anywhere` lets them break mid-token within the grid
 * cell, and `min-width: 0` lets the grid item shrink below its content's
 * intrinsic width (the default `min-width: auto` for grid items would
 * otherwise force overflow). */
.tq-dialog-widgets > span {
    overflow-wrap: anywhere;
    min-width: 0;
}

/* Same intrinsic-width containment for the grid's other direct children —
 * <label> cells and the control cells (number inputs, the linked-reference
 * flex row). Without min-width:0 an intrinsically-wide control overflows
 * the property panel's right edge instead of shrinking to its cell. */
.tq-dialog-widgets > label {
    overflow-wrap: anywhere;
    min-width: 0;
}
.tq-dialog-widgets > input:where(:not([type="checkbox"]):not([type="radio"])),
.tq-dialog-widgets > div {
    min-width: 0;
    max-width: 100%;
    box-sizing: border-box;
}

/* Cell value by row content — vertical layout spanning the 2-column grid. */
.tq-cellvalue-content {
    grid-column: 1 / -1;
    display: flex;
    flex-direction: column;
    gap: 6px;
    width: 100%;
    box-sizing: border-box;
}
.tq-cellvalue-content select,
.tq-cellvalue-content input {
    box-sizing: border-box;
    min-width: 0;
    max-width: 100%;
}
/* Target column: label + picker on one line; the picker fills the rest. */
.tq-cellvalue-field-row {
    display: flex;
    align-items: center;
    gap: 6px;
}
.tq-cellvalue-field-row > span {
    flex: 0 0 auto;
}
.tq-cellvalue-field-row > .tq-linkable-variable-selector {
    flex: 1 1 0;
    min-width: 0;
}
.tq-cellvalue-field-row > .tq-linkable-variable-selector select {
    width: 100%;
}
/* Value-property "match" single-identifier row: the picker (or the linked
 * reference chip) grows to fill the width; the link/unlink buttons sit beside
 * it and wrap beneath when the selected label is long. The selection display
 * (custom-select value AND chip) wraps inside its border rather than
 * overflowing. */
.tq-match-single {
    display: flex;
    align-items: flex-start;
    flex-wrap: wrap;
    gap: 6px;
}
.tq-match-single > .tq-value-customselect {
    flex: 1 1 auto;
    min-width: 0;
}
.tq-match-single .p-qti-custom-select-button {
    height: auto;
    align-items: flex-start;
}
.tq-match-single .p-qti-custom-select-value {
    white-space: normal;
    overflow: visible;
    text-overflow: clip;
    overflow-wrap: anywhere;
    word-break: break-word;
    min-width: 0;
}
.tq-match-single > .tq-linkable-chip {
    flex: 1 1 auto;
    min-width: 0;
    max-width: 100%;
    white-space: normal;
    overflow-wrap: anywhere;
    word-break: break-word;
}
/* Free-text Value match (string entities — text-entry / extended-text /
 * TableInput text cells): the expected-answer input fills the row like the
 * picker does. */
.tq-match-single > .tq-match-text-input {
    flex: 1 1 auto;
    min-width: 0;
}

/* EvaluatesTo property widget: the {variable = value} pairs editor above the
 * expected-value row. Rows are compact flex lines; the remove × reuses the
 * assertion-dialog remove style; the NaN warning is amber, not colour-only
 * (the text itself states the problem). */
.tq-evalto-heading {
    margin-bottom: 2px;
}

.tq-evalto-rows {
    display: flex;
    flex-direction: column;
    gap: 4px;
    margin-bottom: 4px;
}

.tq-evalto-row {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 6px;
}

/* The variable name is a read-only label (the pair set is fixed by the
 * exemplar expression); long generated names break rather than push the
 * value input past the panel edge. */
.tq-evalto-row .tq-evalto-name {
    max-width: 100%;
    overflow-wrap: anywhere;
}

.tq-evalto-row .tq-evalto-value {
    width: 8em;
    max-width: 100%;
    box-sizing: border-box;
}

.tq-evalto-warning {
    margin: 4px 0;
}

/* IsTrue's variable point: the button that opens the values dialog, the
   summary of the values in force beside it, and the line saying what those
   values do to the author's own sample relation. Both text lines span the
   full width of the 2-column tq-dialog-widgets grid so a long point wraps
   under the button instead of squeezing it. */
.tq-istrue-point {
    grid-column: 1 / -1;
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 8px;
    margin-top: 4px;
}

.tq-istrue-point-summary {
    font-size: 0.9em;
    color: var(--text-primary);
    overflow-wrap: anywhere;
}

.tq-istrue-sample {
    grid-column: 1 / -1;
    font-size: 0.9em;
    color: var(--text-secondary);
    min-height: 1.2em;
}

/* Variable-values dialog (the point for IsTrue) — same frame as the mapping
   dialog it sits beside in the scoring panel. */
.tq-variable-values-dialog {
    min-width: 340px;
    max-width: 520px;
}

.tq-variable-values-dialog h3 {
    margin: 0 0 10px 0;
}

.tq-variable-values-dialog .tq-instructions {
    margin: 0 0 15px 0;
    font-size: 0.9em;
    color: var(--text-secondary);
}

.tq-variable-values-table {
    width: 100%;
    margin-bottom: 10px;
}

.tq-variable-values-table th,
.tq-variable-values-table td {
    text-align: left;
    /* A carried row's chip wraps over several lines: its name stays on the first. */
    vertical-align: top;
}

/* The OK refusal (the shared .tq-error-message notice) takes no room until it has something to say. */
.tq-variable-values-error:empty {
    display: none;
}

.tq-variable-values-error {
    margin-bottom: 10px;
}

/* An authored variable name can be any length; let it wrap rather than push
   the value input out of the dialog. */
.tq-variable-values-name {
    overflow-wrap: anywhere;
}

.tq-variable-values-input {
    width: 8em;
    max-width: 100%;
    box-sizing: border-box;
}

/* A linkable row: the value input or the linked chip, then the link and unlink
   buttons. The chip wraps in its own column, never around the buttons. */
.tq-variable-values-link {
    display: flex;
    align-items: flex-start;
    gap: 4px;
}

.tq-variable-values-link > .tq-linkable-chip {
    flex: 1 1 auto;
    min-width: 0;
    overflow-wrap: anywhere;
}

.tq-variable-values-link > button {
    flex: 0 0 auto;
}

.tq-variable-values-sample {
    font-size: 0.9em;
    color: var(--text-secondary);
    min-height: 1.2em;
    margin-bottom: 10px;
}

/* Compact multi-select identifier picker (Contains / NoneOf, and the container
   Value/"match" widget — see IdentifierPickerControl). Vertical layout: the
   selected options are a full-width list on top (one option per row, a thin
   divider between rows), and the "Choose" button sits left-justified BELOW the
   list. grid-column makes the picker span the full width of the 2-column
   tq-dialog-widgets grid. */
.tq-contains-editor {
    grid-column: 1 / -1;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 8px;
    min-width: 0;
}
.tq-contains-editor > button {
    flex: 0 0 auto;
}
/* "Nothing chosen - not saved" hint of the Contains / Contains any / None of
   widget (PropertyWidgetContains.buildEmptyHint). Shown only while the property
   is ticked with nothing chosen; the [hidden] attribute hides it otherwise. */
.tq-property-hint {
    grid-column: 1 / -1;
    color: var(--status-warning);
    border-left: 3px solid var(--status-warning);
    padding: 2px 0 2px 8px;
}
.tq-contains-summary {
    align-self: stretch;
    min-width: 0;
    display: flex;
    flex-direction: column;
}
.tq-contains-summary-item {
    padding: 4px 2px;
    overflow-wrap: anywhere;
}
/* Thin divider between consecutive selected options. */
.tq-contains-summary-item:not(:last-child) {
    border-bottom: 1px solid var(--divider);
}

/* Thin divider between options in the multi-select checkbox dialog, so a long
   option list (e.g. dozens of distractors) is easier to scan. */
.tq-picker-dialog .tq-checkbox-option:not(:last-child) {
    border-bottom: 1px solid var(--control-border);
    padding-bottom: 0.5em;
}

/* Each row criterion is a single line: variable + value fill it, delete is a
 * fixed 1.5em square at the end. */
.tq-cellvalue-criterion {
    display: flex;
    align-items: center;
    gap: 6px;
}
.tq-cellvalue-criterion > select,
.tq-cellvalue-criterion > .tq-linkable-value-input {
    flex: 1 1 0;
    min-width: 0;
}
.tq-cellvalue-criterion > .tq-linkable-value-input {
    display: flex;
}
.tq-cellvalue-criterion > .tq-linkable-value-input > input,
.tq-cellvalue-criterion > .tq-linkable-value-input > .tq-value-customselect {
    flex: 1 1 auto;
    width: 100%;
}
.tq-cellvalue-criterion > button.tq_delete {
    flex: 0 0 1.5em;
    width: 1.5em;
    height: 1.5em;
    padding: 0;
}
/* Full-width thin add button with a centered "+". */
.tq-cellvalue-add {
    width: 100%;
    padding: 0;
    line-height: 1.3;
    font-weight: 600;
    cursor: pointer;
}
.tq-cellvalue-disc-label {
    margin-top: 4px;
}
/* Discriminator selector + its numeric-outcome variable, stacked full-width. */
.tq-cellvalue-discriminator,
.tq-cellvalue-discriminator-var select {
    width: 100%;
}

/* Checkbox grid for row selection - vertical stacking */
.tq-checkbox-grid {
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.tq-checkbox-grid-scrollable {
    max-height: 96px; /* Approximately 4 rows at ~24px each */
    overflow-y: auto;
    overflow-x: hidden;
    border: 1px solid var(--control-border);
    padding: 4px;
    border-radius: var(--radius-sm);
    background-color: var(--surface);
}

.tq-checkbox-wrapper {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 2px 4px;
    cursor: pointer;
}

.tq-checkbox-wrapper:hover {
    background-color: var(--fill-hover);
    border-radius: 2px;
}

.tq-row-checkbox {
    cursor: pointer;
    margin: 0;
}

.tq-checkbox-label {
    cursor: pointer;
    margin: 0;
    user-select: none;
}

/* Assertion authoring dialog. Uses app-dialog for centering; specific
   overrides below maintain the flex-column layout and sizing.
   High-contrast chrome + strong focus rings (AAA). */
dialog.tq-assertion-dialog {
    position: fixed;
    /* inset:0 + margin:auto centers the dialog in the viewport on both axes.
       The previous margin:0 cancelled the <dialog> UA centering, so a 90%-wide
       dialog sat off-centre and ran past the right edge, and its footer
       (Done/Cancel) fell below the bottom of the screen. With inset:0 the
       max-height:92vh box is centred and the flex footer stays on screen. */
    inset: 0;
    box-sizing: border-box;
    width: 85%;
    max-width: 1000px;
    max-height: 92vh;
    margin: auto;
}

dialog.tq-assertion-dialog[open] {
    display: flex;
    flex-direction: column;
    overflow: hidden;
}

/* Slight dim only — the VEs behind must remain readable. */
dialog.tq-assertion-dialog::backdrop {
    background: rgba(0, 0, 0, 0.18);
}

dialog.tq-assertion-dialog .app-dialog-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
    flex-shrink: 0;
}

dialog.tq-assertion-dialog .app-dialog-title {
    display: block;
    width: auto;
    margin: 0;
}

/* Header left group: title + live save-state chip sit together on the left. */
dialog.tq-assertion-dialog .app-dialog-header-left {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    min-width: 0; /* let the title shrink rather than push the chip off-row */
}

/* Save-state chip — clean (✓ all saved) vs dirty (● unsaved). Meaning is
   carried by the glyph + text, never colour alone (WCAG AAA); the colours are
   redundant reinforcement and meet 7:1 contrast (dark text on a pale fill). */
dialog.tq-assertion-dialog .tq-save-state {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    font-size: 0.8rem;
    font-weight: 600;
    line-height: 1;
    padding: 0.2em 0.55em;
    border-radius: var(--radius-tag);
    white-space: nowrap;
    border: 1px solid transparent;
}
dialog.tq-assertion-dialog .tq-save-state-icon {
    font-size: 0.9em;
}
dialog.tq-assertion-dialog .tq-save-state.is-clean {
    background: var(--status-success-tint);
    color: var(--status-success);
    border-color: var(--status-success);
}
dialog.tq-assertion-dialog .tq-save-state.is-clean .tq-save-state-icon::before {
    content: "\2713"; /* ✓ */
}
dialog.tq-assertion-dialog .tq-save-state.is-dirty {
    background: var(--status-danger-tint);
    color: var(--status-danger);
    border-color: var(--divider);
}
dialog.tq-assertion-dialog .tq-save-state.is-dirty .tq-save-state-icon::before {
    content: "\25CF"; /* ● */
}

/* Push Delete to the far left, away from the affirmative Save/Submit actions. */
dialog.tq-assertion-dialog .app-dialog-footer .tq-footer-delete {
    margin-right: auto;
}

dialog.tq-assertion-dialog .app-dialog-close {
    min-width: unset;
    min-height: unset;
    font-size: 1.4rem;
    line-height: 1;
    padding: 0.1em 0.4em;
}

dialog.tq-assertion-dialog .app-dialog-close:focus-visible {
    outline: var(--focus-outline);
    outline-offset: var(--focus-offset);
}

dialog.tq-assertion-dialog .app-dialog-body {
    flex: 1 1 auto;
    overflow: auto;
    padding: 1rem;
    margin-bottom: 0;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}

dialog.tq-assertion-dialog .tq-assertion-meta {
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
}

dialog.tq-assertion-dialog .tq-order-row {
    display: flex;
    align-items: center;
    gap: 0.5rem;
}

dialog.tq-assertion-dialog .tq-order-row label,
dialog.tq-assertion-dialog .tq-assertion-meta > label {
    font-weight: 600;
}

dialog.tq-assertion-dialog .tq-ad-order {
    width: 5em;
}

dialog.tq-assertion-dialog textarea.form-input {
    width: 100%;
    box-sizing: border-box;
    min-height: 3em;
}

dialog.tq-assertion-dialog .tq-condition-tools {
    display: flex;
    gap: 0.5rem;
    margin: 0.25rem 0;
}

dialog.tq-assertion-dialog .tq-condition-tree {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}

/* Aligned-standards section at the bottom of the assertion dialog. The
 * standard rows, "+" button, and the add dialog reuse the global ib-align-*
 * styles (styles.css) so both alignment surfaces look identical. */
dialog.tq-assertion-dialog .tq-ad-alignments {
    border-top: 1px solid var(--divider);
    margin-top: 0.75rem;
    padding-top: 0.5rem;
}

dialog.tq-assertion-dialog .tq-ad-align-title {
    margin: 0 0 0.35rem 0;
}

dialog.tq-assertion-dialog .tq-ad-align-empty {
    font-style: italic;
    color: var(--text-secondary);
    font-size: 0.9em;
}

dialog.tq-assertion-dialog .tq-ad-align-remove {
    border: none;
    background: none;
    color: var(--status-danger);
    cursor: pointer;
    font-size: 1em;
    padding: 0 4px;
}

dialog.tq-assertion-dialog .tq-ad-align-remove:focus-visible {
    outline: 2px solid var(--focus-ring);
    outline-offset: 1px;
}

dialog.tq-assertion-dialog .app-dialog-footer {
    flex-shrink: 0;
    display: flex;
    gap: 0.75rem;
    justify-content: flex-end;
    padding: 0.75rem 1rem;
    border-top: 1px solid var(--divider);
}

/* Strong, visible focus indicators (AAA). */
dialog.tq-assertion-dialog button:focus-visible,
dialog.tq-assertion-dialog input:focus-visible,
dialog.tq-assertion-dialog textarea:focus-visible,
dialog.tq-assertion-dialog select:focus-visible {
    outline: var(--focus-outline);
    outline-offset: var(--focus-offset);
}

/* Destructive outline button variant — red border/text, no fill. */
.btn--destructive-outline {
    background-color: transparent;
    color: var(--btn-destructive);
    border: 1.5px solid var(--btn-destructive);
}
.btn--destructive-outline:hover:not(:disabled):not(.btn--loading),
.btn--destructive-outline:focus:not(:disabled):not(.btn--loading) {
    background-color: var(--status-danger-tint);
}

/* Copy/Paste condition tools render as standard icon buttons (copy +
   clipboard glyphs). Accessible name comes from each button's aria-label. */
.tq_copy_conditions {
    background-image: var(--icon-copy);
    background-repeat: no-repeat;
    background-size: 1.25em 1.25em;
    background-position: center;
    background-color: transparent;
    min-width: 44px;
    min-height: 44px;
    border: 1px solid transparent;
    border-radius: var(--radius-sm, 4px);
    cursor: pointer;
    transition: background-color 120ms ease, border-color 120ms ease;
}

.tq_paste_conditions {
    background-image: var(--icon-clipboard);
    background-repeat: no-repeat;
    background-size: 1.25em 1.25em;
    background-position: center;
    background-color: transparent;
    min-width: 44px;
    min-height: 44px;
    border: 1px solid transparent;
    border-radius: var(--radius-sm, 4px);
    cursor: pointer;
    transition: background-color 120ms ease, border-color 120ms ease;
}

.tq_paste_conditions:disabled,
.tq_paste_conditions.Button_disabled {
    opacity: 0.4;
    cursor: default;
}

/* The framework's `.Button_disabled:hover { background: ... !important }`
   (styles.css) uses the background shorthand, which would wipe the icon's
   background-image on hover (paste starts disabled). Re-assert the icon with
   higher specificity so it stays visible on hover/focus, enabled or not. */
.tq_copy_conditions:hover,
.tq_copy_conditions.Button_disabled:hover,
.tq_copy_conditions.Button_disabled:focus {
    background-image: var(--icon-copy) !important;
    background-color: var(--color-primary-tint) !important;
    border-color: var(--color-primary);
}

.tq_paste_conditions:hover,
.tq_paste_conditions.Button_disabled:hover,
.tq_paste_conditions.Button_disabled:focus {
    background-image: var(--icon-clipboard) !important;
    background-color: var(--color-primary-tint) !important;
    border-color: var(--color-primary);
}

dialog.tq-assertion-dialog div.tq-assertion-definition div.tq-condition-holder {
    padding-bottom: 1em;
}

dialog.tq-assertion-dialog div.tq-assertion-definition {
    display: grid;
    grid-template-columns: 5em 1fr;
    padding-top: 1em;
}

.node_container_widgets {
    display: flex;
    flex-direction: column;
    overflow: auto;
    padding: 4px 5px;
}

.tq_interaction_dialog div.tq-p-qti-tool-editor.node_container {
    display: flex;
    flex-direction: row;
    height: fit-content;
    overflow: revert;
}

.tq_interaction_dialog {
    display: flex;
    flex-direction: column;
}
    .tq_interaction_dialog div.node_container {
        border: 1.5px solid var(--color-border);
        border-radius: var(--radius-md, 8px);
        margin: 12px 0;
        padding: 8px 12px;
        display: flex;
        flex: 1;
        flex-direction: column;
        overflow: hidden;
    }
        .tq_interaction_dialog div.node_container > div:first-child {
            border-bottom: 1.5px solid var(--color-border);
            background-color: var(--color-surface);
            color: var(--color-text-heading);
            font-weight: 600;
            display: flex;
            flex-direction: row;
            align-items: center;
            flex-wrap: nowrap;
            gap: .5em;
            padding: .35em .5em;
            margin: -8px -12px 8px -12px;
            border-radius: var(--radius-md) var(--radius-md) 0 0;
        }
        .tq_interaction_dialog div.node_container > div:first-child > label {
            flex: 1 1 auto;
            width: auto;
            display: inline-block;
            text-align: left;
            font-weight: 600;
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
        }
        .tq_interaction_dialog div.node_container > div:first-child > label:nth-child(2) {
            float: right;
            top: 0px;
        }

/* ===== Subnode row: preview + inline action buttons =====
   The per-subnode type label was dropped; the bordered preview now fills the
   row and the action buttons (properties / delete) sit inline to its right. */
.node-widget {
    display: flex;
    flex-direction: row;
    align-items: center;
    gap: .25em;
}
.node-widget > .tq-subnode-preview {
    flex: 1 1 auto;
}
.node-widget > .tq_button_span {
    flex: 0 0 auto;
    margin-left: 0;
    align-self: center;
}

/* ===== Click-to-edit subnode preview =====
   Replaces the inline Quill editor that used to fill each subnode. Shows the
   rendered content (or muted placeholder text when empty) inside a light,
   rounded border, and behaves as a button: focusable, Enter/Space activates it,
   strong visible focus ring. Colours meet WCAG AAA (>=7:1 text, >=3:1 boundary
   / focus ring). */
.tq-subnode-preview {
    border: 1px solid var(--color-input-border);
    border-radius: var(--radius-md);
    padding: .2em .5em;
    margin: .15em 0;
    min-height: 1.5em;
    background-color: var(--surface);
    color: var(--color-text-base);
    cursor: pointer;
    overflow-wrap: anywhere;
}
.tq-subnode-preview:hover {
    border-color: var(--color-primary);
    background-color: var(--color-primary-tint);
}
.tq-subnode-preview:focus,
.tq-subnode-preview:focus-visible {
    outline: var(--focus-outline);
    outline-offset: var(--focus-offset);
    border-color: var(--color-primary);
}
.tq-subnode-preview.tq-subnode-empty {
    color: var(--color-text-muted);
    font-style: italic;
}
/* A committed 'filled' asset slot carries the popup editor's revise button in
   its content; the preview is a read-only click-target (itself role=button),
   so never show a nested interactive control there. */
.tq-subnode-preview .tq-asset-revise {
    display: none;
}
/* Multi-line content shows only its first line in the compact preview; this
   note tells the author the rest exists (click through to edit it). */
.tq-subnode-preview .tq-subnode-more-note {
    display: block;
    color: var(--color-text-muted);
    font-style: italic;
    font-size: .85em;
}

/* ===== Rich note editor (asset request / revision dialogs) =====
   The TestQuill basicToolbar editor embedded in a BasicDialog. Generous
   default size, and author-SIZEABLE: the CSS resize grip on the editor box
   lets the author drag it larger (overflow:hidden is required for the grip;
   the inner .ql-editor does its own scrolling, so nothing is clipped). */
.tq-rich-note-host {
    width: min(60rem, 90vw);
}
.tq-rich-note-editor {
    height: 20rem;
    min-height: 10rem;
    min-width: 100%;
    resize: both;
    overflow: hidden;
}
.tq-rich-note-editor .ql-editor {
    height: 100%;
    overflow-y: auto;
}

/* ===== Help-text editing dialog (HelpTextEditor.js) =====
   The editor is the dialog's whole purpose, so the dialog claims most of
   the viewport and the editor stretches to fill it. Scoped to [open] so
   the closed <dialog> keeps its native display:none. The column chain
   needs min-height:0 at every level or the flex items refuse to shrink
   and the editor overflows instead of scrolling. */
.tq-help-edit-dialog[open] {
    display: flex;
    flex-direction: column;
    width: min(75rem, 92vw);
    height: 85vh;
}
.tq-help-edit-dialog .tq-dialog-widgets {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-height: 0;
    gap: 4px;
}
.tq-help-edit-dialog .tq-rich-note-host {
    width: auto;
    align-self: stretch;
    flex: 1 1 auto;
    min-height: 0;
    display: flex;
    flex-direction: column;
}
/* The Quill toolbar (the host's first child) keeps its natural height;
   the editor box takes everything below it. The drag grip is pointless
   when the editor already fills the dialog, so resize goes. */
.tq-help-edit-dialog .tq-rich-note-editor {
    flex: 1 1 auto;
    height: auto;
    min-height: 0;
    resize: none;
}

/* ===== Item-specific rubric dialog editor =====
   Same shape as the rich-note editor above: the editor is a fixed-
   height resizable box whose inner .ql-editor does the scrolling —
   nothing is clipped, and no scrollbar sits on the container itself.

   The WAF Dialog_normal box is FIXED-width (width:100% capped by
   max-width) — the host therefore uses auto width + side margins to
   fill it exactly (an explicit rem width overflowed the box), and the
   dialog itself is widened via the .tq-rubric-dialog modifier for the
   full-toolbar editor. The modifier also turns the stock 2-column
   Dialog_body grid (one widget per row) into a right-aligned
   horizontal row for the Save/Cancel pair. */
.Dialog_normal.tq-rubric-dialog {
    max-width: min(64rem, 92vw);
}
.tq-rubric-dialog .Dialog_body {
    display: flex;
    justify-content: flex-end;
    gap: 8px;
}
.tq-rubric-dialog .Dialog_body > label:empty {
    display: none;
}
.tq-rubric-block-host {
    margin: 16px 20px 0;
}
.tq-rubric-block-editor {
    height: 20rem;
    min-height: 10rem;
    min-width: 100%;
    resize: both;
    overflow: hidden;
    border: 1px solid var(--divider);
}
.tq-rubric-block-editor .ql-editor {
    height: 100%;
    overflow-y: auto;
}

/* Rich request text rendered on the specialist's work page: sample images
   (plain or resizable-figure form) must never overflow the details pane. */
.asvc-details dd img,
.asvc-details dd figure {
    max-width: 100%;
    height: auto;
}

/* Awaiting-revision marker: a delivered asset whose revision has been
   requested (or is claimed and in progress). Amber outline PLUS a visible
   text badge on the slot in every authoring surface — body editor,
   sub-editor popups, subnode previews, and the interaction stand-in (which
   also loads this sheet). The badge text arrives translated via
   data-revision-label (set alongside the class); it renders only while the
   marker class is present, and ItemTransformer strips the class from
   export, so it can never reach delivery. aria duplication is avoided: the
   slot's aria-label carries the same text, the ::after is presentational. */
.tq-asset-revision-pending {
    position: relative;
    outline: 3px solid var(--focus-ring);
    outline-offset: 2px;
    border-radius: 2px;
}
.tq-asset-revision-pending::after {
    content: attr(data-revision-label);
    position: absolute;
    top: 4px;
    left: 4px;
    z-index: 1;
    padding: 2px 8px;
    border-radius: var(--radius-sm);
    background: var(--status-warning);
    color: var(--text-on-accent);
    font-size: 12px;
    font-style: normal;
    font-weight: 600;
    line-height: 1.3;
    white-space: nowrap;
    pointer-events: none;
}

/* The specialist work page's read-only item render — the page body under
   the floating request panel. */
.asvc-item-display {
    position: relative;
    min-height: 24rem;
    border: 1px solid var(--color-input-border);
    border-radius: var(--radius-md);
    padding: 1rem;
    margin-top: 0.5rem;
    background-color: var(--surface);
}

/* ===== Full-width "add" bar at the bottom of a subnode collection =====
   Reuses the .tq_add plus-square icon, but stretched into a bar and kept
   centred (overriding .tq_add's contain/1.5em sizing). */
button.tq_subnode_add_bar {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    height: auto;
    min-height: 2.25em;
    margin: .25em 0 0 0;
    padding: .35em;
    background-color: var(--color-bg);
    background-position: center;
    background-size: 1.4em 1.4em;
    border: 2px dashed var(--color-input-border);
    border-radius: var(--radius-sm);
    cursor: pointer;
}
button.tq_subnode_add_bar:hover {
    background-color: var(--color-surface);
    border-color: var(--color-text-base);
}
button.tq_subnode_add_bar:focus,
button.tq_subnode_add_bar:focus-visible {
    outline: var(--focus-outline);
    outline-offset: var(--focus-offset);
    border-color: var(--color-primary);
}

/* ===== Rich-text editor popup (SubnodeEditor.openEditor) ===== */
dialog.tq_subnode_dialog {
    width: 70%;
    max-width: 900px;
    display: flex;
    flex-direction: column;
}
dialog.tq_subnode_dialog .tq-subnode-editor-host {
    border: 1.5px solid var(--color-input-border);
    border-radius: var(--radius-sm);
    min-height: 8em;
    margin-bottom: .75em;
}
dialog.tq_subnode_dialog .tq-subnode-dialog-buttons {
    gap: .5em;
}

/* ===== Match-set "restrict one selection per row/column" toggle ===== */
.tq-restrict-toggle {
    display: inline-flex;
    align-items: center;
    gap: .35em;
    flex: 0 0 auto;
    white-space: nowrap;
    color: var(--color-text-heading);
    font-weight: normal;
}
/* Reserve enough height to show ~3 entries before the list scrolls. */
.tq-match-set .node_container_widgets {
    min-height: 7em;
}
.tq-restrict-toggle label {
    cursor: pointer;
    color: inherit;
}

.tq-dialog-title {
    display: inline-flex;
    width: 100%;
    flex-direction: row;
    justify-content: space-between;
    flex-shrink: 0; /* Prevent dialog title from shrinking */
}

.tq-dialog-title button,
.tq-dialog-title select,
.tq-dialog-title input {
    height: 1.5em;
    padding-top: 1px;
    padding-bottom: 1px;
    margin-left: .5em;
    margin-right: .5em;
}

.tq-drop-target {
    background-color: var(--surface);
    /* Basic button styling (adjust as needed) */
    padding: 1rem 2rem;
    font-size: 1.125rem; /* text-lg */
    font-weight: 600; /* font-semibold */
    color: var(--text-on-accent); /* text-white */
    border-radius: 0.5rem; /* rounded-lg */
    transition: all 0.2s ease-in-out;
    cursor: pointer; /* Default cursor */
    /* --- Styles to invite dropping --- */
    border: 3px dashed var(--divider); /* indigo-200 - a dashed border suggests a drop zone */
    box-shadow: var(--shadow-1); /* shadow-md */
    /* Visual feedback when something is dragged over it */
    /* This class would be added via JavaScript on 'dragenter' or 'dragover' */
}

.tq-drop-target-drag-over{
    background-color: var(--accent-fill); /* indigo-500 */
    border-color: var(--accent); /* indigo-300 */
    transform: scale(1.02); /* Slight scale to emphasize */
    box-shadow: var(--shadow-2); /* shadow-lg */
    cursor: copy; /* Or 'grab', 'grabbing', 'move' depending on desired effect */
}

.tq_select_holder {
    display: flex;
    flex-direction: column;
    gap: 4px;
    margin-bottom: 12px;
}

.RIV_window .tq_resizable {
    resize: none;
}

iframe.tq_resizable,
qti-span.tq_resizable {
    resize: both;
    overflow: auto;
    height: fit-content;
    width: fit-content;
    display: inline-block;
}
    .tq_resizable > img {
        width: 100%;
        height: calc(100%-2em);
    }
    .tq_resizable > caption {
        width: 100%;
        min-height: 1.1em;
        display: block;
    }

.tq_interaction_iframe {
    border: none;
    width: fit-content;
    /* ...but never wider than what it sits in. A stand-in for a wide
       interaction (a graphic, a simulation) sized itself to its content and
       ran off the right of the screen — and the page does not scroll to reach
       it, so the far side was simply unreachable (owner report, 2026-09-11).
       Capped here, the frame scrolls its own document instead. */
    max-width: 100%;
    height: fit-content;
    display: inline;
}

div.tq-graphic-canvas-editor > div.tq-svg-holder {
    /* Width-only resize: the height is driven by the reference aspect ratio in
       GraphicCanvasEditor (updateAttributesOnResize). Allowing free 2-axis
       resize let the canvas take a shape different from the image/coordinate
       grid, which letterboxed the grid and misplaced authored hotspots. */
    resize: horizontal;
    display: inline-block;
    overflow: hidden;
}
/* BR-91: the background picture is a keyboard control (Enter changes it).
   SVG children draw outlines unreliably, so the focus ring is drawn on the
   canvas holder while the picture has focus (GraphicCanvasEditor). */
/* A ring whenever anything in the canvas has keyboard focus (a shape, the
   canvas itself), so a Tab stop inside it is never invisible — in a DIFFERENT
   colour from the background's ring, so tabbing from one to the other visibly
   changes something (owner, 2026-10-02): the warning colour here, the focus
   colour for the background. The background rule comes last so it wins while
   the picture has focus (equal specificity). */
div.tq-graphic-canvas-editor > div.tq-svg-holder:focus-within,
div.tq-graphic-canvas-editor > div.tq-svg-holder:focus-visible {
    outline: 3px solid var(--status-warning);
    outline-offset: 2px;
}
div.tq-graphic-canvas-editor > div.tq-svg-holder.tq-background-focused {
    outline: 3px solid var(--focus-ring);
    outline-offset: 2px;
}
div.tq-graphic-canvas-editor > div.tq-svg-holder > svg > image.tq-background-image:focus {
    outline: none;
}
    div.tq-graphic-canvas-editor > div.tq-svg-holder > svg {
        width: 100%;
        height: 100%;
        background-color: var(--accent-tint);
    }
    div.tq-graphic-canvas-editor > div.tq-svg-holder > svg > image {
        width: 100%;
        height: auto;
        box-sizing:border-box;
    }

        div.tq-graphic-canvas-editor > div.tq-svg-holder > svg > image.tq-btn-image {
            width: 15px;
            height: 15px;
        }

/* Ellipse and polygon hotspots (HotspotGeometry, SvgEllipse, SvgPolygon). A
   selected shape draws a heavy blue outline; a focused one a dashed outline as
   well, so the keyboard position is visible on any picture (2.4.7 / 2.4.13).
   The polygon's corner handles and the ellipse's radius handles are white with
   a dark ring - the highlighted corner (the one the arrows move) is larger and
   filled - so each reads over light and dark pictures alike (1.4.11). */
div.tq-graphic-canvas-editor svg ellipse.p-qti-added,
div.tq-graphic-canvas-editor svg polygon.p-qti-added {
    stroke: #000000;
    stroke-width: 2;
    fill: rgba(255, 255, 255, 0.01);
}
div.tq-graphic-canvas-editor svg ellipse.p-qti-added.p-qti-selected,
div.tq-graphic-canvas-editor svg polygon.p-qti-added.p-qti-selected {
    stroke: #0050a0;
    stroke-width: 3;
}
div.tq-graphic-canvas-editor svg ellipse.p-qti-added:focus,
div.tq-graphic-canvas-editor svg polygon.p-qti-added:focus {
    outline: none;
    stroke-dasharray: 6 3;
}
div.tq-graphic-canvas-editor svg polygon.p-qti-drafting {
    stroke: #0050a0;
    stroke-width: 2;
    stroke-dasharray: 4 3;
    fill: none;
}
div.tq-graphic-canvas-editor svg line.p-qti-draft-preview {
    stroke: #0050a0;
    stroke-width: 1.5;
    stroke-dasharray: 4 3;
}
div.tq-graphic-canvas-editor svg .p-qti-vertex-handle,
div.tq-graphic-canvas-editor svg .p-qti-shape-handle {
    fill: #ffffff;
    stroke: #1a1a1a;
    stroke-width: 1.5;
}
div.tq-graphic-canvas-editor svg .p-qti-vertex-handle.p-qti-vertex-focused,
div.tq-graphic-canvas-editor svg .p-qti-shape-handle.p-qti-shape-handle-active {
    fill: #0050a0;
    stroke: #ffffff;
    stroke-width: 2;
}
/* New hotspot: how a polygon is drawn, under the shape choice. */
dialog.tq-hotspot-dialog p.tq-hotspot-polygon-hint {
    max-width: 28em;
    margin: 0.25em 0 0.75em;
}

/* The canvas editor stacks its parts - tools, canvas, label tools, label
   palette - in a COLUMN. As a .node-widget it was a flex ROW, so the palette sat
   beside the canvas and the canvas, a flex item, shrank to make room; the
   shrunken width was then saved, and every reopen shrank the photo again
   (cert bug #62). The canvas never shrinks: a canvas wider than the dialog
   scrolls with it. */
div.tq-graphic-canvas-editor.node-widget {
    flex-direction: column;
    align-items: flex-start;
}
    div.tq-graphic-canvas-editor > div.tq-svg-holder {
        flex: 0 0 auto;
        max-width: none;
    }
    div.tq-graphic-canvas-editor > div.tq-gap-images-container {
        align-self: stretch;
    }

div.p-qti-quantity-stimulus {
    display: grid;
    justify-content: center;
    width: fit-content;
    height: fit-content;
    align-self:center;
}

div.tq-response-number {
    background-color: var(--fill);
    font-weight: 600;
    border: outset;
    text-align: center;
    height: fit-content;
    min-height: 1.8em;
    min-width: 1.8em;
}

div.tq-attributes {
    flex-wrap: wrap;
    gap: 20px;
    padding: 12px 16px;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md, 8px);
    margin-bottom: 16px;
}

div.tq-attributes div.attribute-widget {
    display: flex;
    flex-direction: column;
    gap: 4px;
    min-width: 130px;
}
/* A setting that does not apply right now (the number line's tick controls
   while Unbounded is ticked): kept in place, greyed, its help icon still live. */
div.tq-attributes div.attribute-widget.tq-attribute-disabled {
    opacity: 0.55;
}
div.tq-attributes div.attribute-widget.tq-attribute-disabled .attribute-input {
    cursor: not-allowed;
}
div.tq-attributes div.attribute-widget.tq-attribute-disabled .tq-info-icon {
    opacity: 1;
    cursor: pointer;
}
/* A notice under a setting that does not block Submit (the number line's
   "this interval can't be shown as fractions"); [hidden] hides it otherwise. */
div.tq-attributes div.attribute-widget .tq-attribute-notice {
    max-width: 22rem;
    font-size: 0.875rem;
    color: var(--status-warning);
    border-left: 3px solid var(--status-warning);
    padding: 2px 0 2px 8px;
}

input[type="checkbox"].attribute-input {
    margin-top: 6px;
}
span.tq-element-editor {
    padding: .1em .1em .1em .1em;
}

span.tq-element-editor:focus {
    border:none;
}

span.tq-element-editor-cursor {
    display: inline-block;
    width: 1px;
    height: 1.2em;
    padding-left: 1px;
    padding-right: 1px;
    background-color: var(--text-primary);
    animation: blink 1s linear alternate
}

@keyframes blink {
    50% {
        opacity: 0%;
    }
    100% {
        opacity: 100%;
    }

}

/*span.tq-receive-unknown {
    display:inline-block;
    height: 1em;
    width: .8em;
    background-color: yellow;
}
*/
span.tq-function {
    margin-left: .5em;
}

span.tq-close-paren {
    margin-right: .5em;
}
span.tq-function::after,
span.tq-operator::after {
    content: attr(data-value);
}

input[type="number"].tq-parameter-value::-webkit-inner-spin-button {
    -webkit-appearance: none;
    margin: 0;
}

input[type="number"].tq-parameter-value {
    -moz-appearance: textfield;
    field-sizing: content;
}

span.tq-value-reference {
    border: 2px dashed var(--status-danger);
}

div.tq-calculator-result {
    border: none;
    height: 1.5em;
    width: 100%;
    text-align: center;
    font-weight: 600;
}

div.tq-calulation-receiver {
    border: none;
    width: 100%;
    position: relative;
}

/* Dialog message area above submit/cancel buttons */
.tq-dialog-message {
    min-height: 1.5em;
    padding: 0.75em;
    margin-bottom: 1em;
    border-radius: 0.25em;
    flex-shrink: 0; /* Prevent message area from shrinking */
}

.tq-error-message { /* red-300 */
}

.tq-info-message { /* blue-300 */
}

/* Validation error border for list items */
.tq-validation-error {
    border: 2px dashed var(--status-danger) !important;
}

/* Validation message area in OutputInstructionGetter */
.tq-validation-message {
    min-height: 1.5em;
    color: var(--status-danger); /* red-600 */
    padding: 0.5em;
    margin-bottom: 0.5em;
}

/* Checkbox list for container value widgets */
.tq-checkbox-list {
    display: flex;
    flex-direction: column;
    gap: 0.5em;
}

.tq-checkbox-option {
    display: flex;
    flex-direction: row;
    align-items: center;
    gap: 0.5em;
    cursor: pointer;
}

    .tq-checkbox-option input[type="checkbox"] {
        margin: 0;
    }

    .tq-checkbox-option span {
        display: inline;
        vertical-align: middle;
    }

/* ========== Simulation Template Dialog ========== */
.tq-simulation-template-dialog {
    max-height: 85vh; /* Limit dialog to 85% of viewport height */
    max-width: 95vw; /* Limit dialog to 95% of viewport width */
    height: 85vh; /* Fixed height to ensure proper calculation */
    overflow: hidden; /* Remove default padding */
}

/* (Animation Brief Dialog CSS removed 2026-08-30 with the manual
   Generate-animation-brief button — the brief now rides implicitly in
   every animation request.) */

/* ========== Animation Studio Dialog ========== */
.tq-animation-studio-dialog {
    width: 86vw;
    max-width: 1200px;
    max-height: 90vh;
    display: flex;
    flex-direction: column;
}

    .tq-animation-studio-dialog .tq-studio-body {
        display: grid;
        grid-template-columns: minmax(0, 3fr) minmax(0, 2fr);
        gap: 16px;
        flex: 1 1 auto;
        min-height: 0;
        overflow: hidden;
    }

    .tq-animation-studio-dialog .tq-studio-stage-pane {
        display: flex;
        flex-direction: column;
        gap: 10px;
        min-height: 0;
        overflow-y: auto;
    }

    .tq-animation-studio-dialog .tq-studio-stage {
        border: 1px solid var(--divider);
        border-radius: var(--radius-md);
        background: var(--bg-secondary);
        min-height: 240px;
    }

        .tq-animation-studio-dialog .tq-studio-stage svg {
            display: block;
            width: 100%;
            height: auto;
        }

    .tq-animation-studio-dialog .tq-studio-scene-tag {
        font-family: monospace;
        font-size: 0.75rem;
        color: var(--text-secondary);
    }

    .tq-animation-studio-dialog .tq-studio-run-row {
        display: flex;
        align-items: center;
        gap: 12px;
        flex-wrap: wrap;
    }

    .tq-animation-studio-dialog .tq-studio-conv-pane {
        display: flex;
        flex-direction: column;
        gap: 8px;
        min-height: 0;
    }

    .tq-animation-studio-dialog .tq-studio-sent-line {
        font-size: 0.8rem;
        color: var(--text-secondary);
        margin: 0;
    }

    .tq-animation-studio-dialog .tq-studio-revisions {
        display: flex;
        gap: 6px;
        flex-wrap: wrap;
    }

    .tq-animation-studio-dialog .tq-studio-rev-chip {
        border-radius: var(--radius-tag);
        padding: 2px 12px;
        font-size: 0.8rem;
    }

        .tq-animation-studio-dialog .tq-studio-rev-chip[aria-pressed="true"] {
            background: var(--fill);
            border-color: var(--accent);
        }

    .tq-animation-studio-dialog .tq-studio-transcript {
        flex: 1 1 auto;
        min-height: 120px;
        overflow-y: auto;
        border: 1px solid var(--divider);
        border-radius: var(--radius-md);
        padding: 8px;
        display: flex;
        flex-direction: column;
        gap: 6px;
    }

    .tq-animation-studio-dialog .tq-studio-msg {
        font-size: 0.85rem;
        border-radius: var(--radius-md);
        padding: 6px 10px;
        max-width: 94%;
    }

    .tq-animation-studio-dialog .tq-studio-msg-model {
        background: var(--bg-secondary);
        align-self: flex-start;
    }

    .tq-animation-studio-dialog .tq-studio-msg-author {
        background: var(--fill);
        align-self: flex-end;
    }

    .tq-animation-studio-dialog .tq-studio-msg-who {
        display: block;
        font-size: 0.68rem;
        text-transform: uppercase;
        letter-spacing: 0.08em;
        color: var(--text-secondary);
    }

    .tq-animation-studio-dialog .tq-studio-working {
        font-size: 0.85rem;
        color: var(--status-warning);
        border: 1px dashed var(--divider);
        border-radius: var(--radius-md);
        padding: 6px 10px;
    }

    .tq-animation-studio-dialog .tq-studio-feedback textarea {
        width: 100%;
        min-height: 60px;
        box-sizing: border-box;
        resize: vertical;
    }

    .tq-animation-studio-dialog .tq-studio-feedback-row {
        display: flex;
        justify-content: space-between;
        align-items: center;
        gap: 10px;
    }

    .tq-animation-studio-dialog .tq-studio-round {
        font-size: 0.8rem;
        color: var(--text-secondary);
    }

    .tq-animation-studio-dialog .tq-studio-footer {
        display: flex;
        justify-content: flex-end;
        gap: 10px;
        border-top: 1px solid var(--divider);
        padding-top: 10px;
        margin-top: 10px;
    }

    .tq-animation-studio-dialog .tq-visually-hidden {
        position: absolute;
        width: 1px;
        height: 1px;
        overflow: hidden;
        clip: rect(0 0 0 0);
        white-space: nowrap;
    }

/* ========== Simulation Template Content ========== */
.tq-simulation-template-content {
    display: flex;
    flex-direction: column;
    height: 100%; /* Fill the dialog */
    overflow: hidden; /* Prevent dialog content from scrolling */
}

/* ========== Simulation Template Scrollable Content ========== */
.tq-simulation-scrollable-content {
    flex: 1; /* Take remaining space */
    overflow-y: auto; /* Enable vertical scrolling */
    overflow-x: hidden; /* Prevent horizontal scrolling */
    min-height: 0; /* Allow flex child to shrink below content size */
    padding: 0 1rem 1rem 1rem; /* Add padding for content spacing */
}

/* ========== Tab View Styles ========== */
.tq-tab-view {
    display: flex;
    flex-direction: column;
    height: 100%;
    min-height: 0; /* Allow flex child to shrink below content size */
}

.tq-tab-buttons {
    padding: 0;
    margin-bottom: 16px;
    flex-shrink: 0;
}

.tq-tab-content {
    flex: 1;
    overflow-y: auto;
    min-height: 0; /* Allow flex child to shrink below content size */
}

.tq-tab-panel {
    height: 100%;
}

/* ========== Two-Column Layout ========== */
.tq-simulation-two-column {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 24px;
    flex: 1; /* Take up remaining space in flex container */
    min-height: 0; /* Allow flex child to shrink below content size */
    padding: 16px;
    overflow: hidden; /* Prevent container from scrolling */
}

.tq-simulation-left-column {
    display: flex;
    flex-direction: column;
    border-right: 1px solid var(--divider);
    padding-right: 16px;
    overflow: hidden; /* Prevent column itself from scrolling */
    min-height: 0; /* Allow grid child to shrink below content size */
    height: 100%; /* Ensure column takes full height of grid cell */
}

/* A simulation tab's panel: a header row carrying the area's name and its help
   icon, then the tab's own content. The icon cannot sit on the tab itself —
   TabView builds each tab as a <button>, and a <button> inside a <button> is
   invalid — so the panel carries it instead. The panel must not eat the
   column's height budget: the content below it is what scrolls. */
.tq-sim-tab-panel {
    display: flex;
    flex-direction: column;
    min-height: 0;
    height: 100%;
}

.tq-sim-tab-header {
    display: flex;
    align-items: center;
    gap: 6px;
    flex: 0 0 auto;
    padding: 2px 0 6px 0;
}

.tq-sim-tab-panel > :not(.tq-sim-tab-header) {
    flex: 1 1 auto;
    min-height: 0;
    overflow: auto;
}

.tq-simulation-right-column {
    display: flex;
    flex-direction: column;
    gap: 16px;
    overflow-y: auto; /* Allow right column to scroll */
    min-height: 0; /* Allow grid child to shrink below content size */
    height: 100%; /* Ensure column takes full height of grid cell */
    padding-right: 8px; /* Add padding for scrollbar */
}

/* ========== Title Bar ========== */
.tq-simulation-title-bar {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
    gap: 16px;
    padding: 16px;
    background: var(--bg-secondary);
    border-bottom: 1px solid var(--divider);
    flex-shrink: 0; /* Prevent title bar from shrinking */
}

.tq-simulation-title-bar-group {
    display: flex;
    flex-direction: column;
    gap: 4px;
}

/* ========== Preview Sections ========== */
.tq-preview-section {
    padding: 16px;
}

.tq-preview-section h3 {
    margin: 0 0 12px 0;
}

/* Preview table styling */
.tq-simulation-output-table {
    width: 100%;
}

.tq-simulation-output-table th,
.tq-simulation-output-table td {
    text-align: center;
}

.tq-simulation-output-table td {
    font-style: italic;
}

/* Scene list styling */
.tq-scene-item {
    border: 1px solid var(--divider);
    border-radius: var(--radius-sm);
    padding: 12px;
    margin-bottom: 12px;
    background-color: var(--bg-secondary);
}

.tq-scene-item:last-child {
    margin-bottom: 0;
}

.tq-scene-item-top-row {
    display: flex;
    gap: 16px;
    margin-bottom: 8px;
}

.tq-scene-name-group {
    flex: 1;
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.tq-scene-name-group label {
    font-size: 12px;
    font-weight: 600;
    color: var(--text-secondary);
}

.tq-scene-duration-group {
    width: 120px;
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.tq-scene-duration-group label {
    font-size: 12px;
    font-weight: 600;
    color: var(--text-secondary);
}

.tq-scene-description-row {
    display: flex;
    flex-direction: column;
    gap: 4px;
    margin-bottom: 8px;
}

.tq-scene-description-row label {
    font-size: 12px;
    font-weight: 600;
    color: var(--text-secondary);
}

.tq-scene-description-row textarea {
    resize: vertical;
}

.tq-delete-scene-button {
    border: none;
    align-self: flex-start;
}

.tq-add-scene-button {
    border: none;
    margin-top: 12px;
}

/* Dialog header buttons */
.tq-dialog-header-buttons {
    display: flex;
    gap: 8px;
    align-items: center;
}

.tq-submit-button {
    border: none;
}

/* Entity description area (always visible space) */
.tq-entity-description-area {
    min-height: 24px;
    padding: 6px 8px;
    margin-bottom: 8px;
    border: 1px solid transparent;
    border-radius: var(--radius-sm);
    transition: all 0.2s ease;
}

/* Clickable mapping style (for identifier containers) */
.tq-clickable-mapping {
    background-color: var(--accent-tint);
    border: 1px solid var(--accent);
    cursor: pointer;
}

.tq-clickable-mapping:hover {
    background-color: var(--fill-hover);
    border-color: var(--accent);
}

.tq-entity-description-text {
    font-size: 0.9em;
    color: var(--text-primary);
}

.tq-clickable-mapping .tq-entity-description-text {
    color: var(--accent);
    font-weight: 500;
}

/* Mapping dialog */
.tq-mapping-dialog {
    min-width: 400px;
    max-width: 600px;
}

.tq-mapping-dialog h3 {
    margin: 0 0 10px 0;
}

.tq-mapping-dialog .tq-instructions {
    margin: 0 0 15px 0;
    font-size: 0.9em;
    color: var(--text-secondary);
}

/* Options picker: cap the dialog height and let only the option list
 * scroll, so the select-all toolbar and the OK/Cancel footer stay
 * visible no matter how many options there are. */
.tq-picker-dialog {
    display: flex;
    flex-direction: column;
    max-height: 85vh;
}

.tq-picker-dialog .tq-checkbox-list {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
}

.tq-picker-dialog .tq-dialog-buttons {
    flex: 0 0 auto;
}

.tq-picker-toolbar {
    flex: 0 0 auto;
    display: flex;
    gap: 14px;
    margin: 0 0 10px 0;
}

.tq-picker-toolbar button {
    background: none;
    border: none;
    padding: 0;
    color: var(--accent);
    cursor: pointer;
    font-size: 0.9em;
    text-decoration: underline;
}

.tq-picker-toolbar button:hover,
.tq-picker-toolbar button:focus-visible {
    color: var(--accent-hover);
}

.tq-mapping-table {
    width: 100%;
    margin-bottom: 15px;
}

.tq-mapping-table th,
.tq-mapping-table td {
    text-align: left;
}

.tq-mapping-label {
    cursor: help;
    font-size: 0.9em;
}

.tq-mapping-value-input {
    width: 80px;
    padding: 4px 8px;
    border: 1px solid var(--field-border);
    border-radius: var(--radius-field);
    font-size: 0.9em;
}

.tq-mapping-value-input.error {
    border-color: var(--status-danger);
    background-color: var(--status-danger-tint);
}

.tq-no-values-message {
    text-align: center;
    color: var(--text-secondary);
    font-style: italic;
    padding: 20px;
}

.tq-dialog-buttons {
    display: flex;
    flex-wrap: wrap; /* wrap rather than overflow past the dialog's left edge */
    justify-content: flex-end;
    gap: 10px;
}

.tq-button-primary,
.tq-button-secondary {
    border: 1px solid transparent;
}

/* Destructive action (e.g. "Lose Changes and Exit", DeleteConfirmation).
   Dark red on white clears WCAG AAA contrast (~9:1). */
.tq-button-danger {
    border: 1px solid transparent;
}

/* Quill editor containers for widget and outcome labels */
div.tq-widget-label-editor-container,
div.tq-outcome-label-editor {
    border: 1px solid var(--divider);
    border-radius: var(--radius-sm);
    background: var(--surface);
    margin-bottom: 8px;
}

    /* Target the actual Quill container div (has both tq-widget-label-editor and ql-container classes) */
    div.tq-widget-label-editor.ql-container,
    div.tq-outcome-label-editor.ql-container {
        max-height: 15em;
        overflow-y: auto;
        height: auto;
    }

        /* Make Quill editor content area grow with content */
        div.tq-widget-label-editor.ql-container .ql-editor,
        div.tq-outcome-label-editor.ql-container .ql-editor {
            min-height: 3em;
            height: auto;
        }

    /* Ensure resizable images work inside label editors */

    div.tq-widget-label-editor iframe.tq_resizable,
    div.tq-widget-label-editor qti-span.tq_resizable,
    div.tq-outcome-label-editor qti-span.tq_resizable {
        resize: both !important;
        overflow: auto !important;
        display: inline-block
    }

/* Option label editor in LabelValuePairGetter dialog */
div.tq-option-label-editor-container {
    border: 1px solid var(--divider);
    border-radius: var(--radius-sm);
    background: var(--surface);
    margin-bottom: 8px;
}

div.tq-option-label-editor.ql-container {
    max-height: 15em;
    overflow-y: auto;
    height: auto;
}

div.tq-option-label-editor.ql-container .ql-editor {
    min-height: 3em;
    height: auto;
}

/* Ensure resizable images work inside option label editors */
div.tq-option-label-editor .tq_resizable {
    resize: both !important;
    overflow: auto !important;
    display: inline-block;
}

/* Simulation Prompt Section (Template Editor) */
.tq-simulation-prompt-section {
    margin-bottom: 1.5rem;
    padding: 1rem;
}

.tq-simulation-prompt-section .node-widget {
    margin: 0;
}

/* ========== ResizableImage (Embed-based) ========== */

/* Main embed wrapper - must be inline for text flow */
span.tq-image-embed {
    display: inline;
}

/* The contentNode wrapper created by Quill's Embed */
span.tq-image-embed > span[contenteditable="false"] {
    display: inline-block;
    vertical-align: top;
}

/* The figure inside the embed */
span.tq-image-embed figure.tq-image {
    display: inline-block;
    margin: 0.5em;
    padding: 0;
    text-align: center;
    /* Resizable */
    resize: both;
    overflow: hidden;
    /* Minimum size to allow resize handle */
    min-width: 50px;
    min-height: 50px;
}

/* The image inside the figure */
span.tq-image-embed figure.tq-image > img {
    display: block;
    width: 100%;
    height: auto;
    /* Maintain aspect ratio when figure is resized */
    object-fit: contain;
}

/* Selection indicator when image embed is selected */
span.tq-image-embed.p-qti-selected > span[contenteditable="false"],
span.tq-image-embed:focus-within figure.tq-image {
    outline: 3px solid #007bff;
    outline-offset: 2px;
}

/* The image's caption, shown under the picture while editing (a display copy:
   the caption is stored on the img, ResizeableImage.js). It sits outside the
   figure, whose resize handle needs overflow: hidden. Inline-size containment:
   the caption wraps to the picture's width and never widens the image box.
   Delivery draws the real figcaption the same way (PaldroeStyles.css). */
span.tq-image-embed .tq-caption-view {
    display: block;
    contain: inline-size;
    box-sizing: border-box;
    padding: 0 0.5em 0.25em;
    text-align: center;
    font-size: 0.9em;
    line-height: 1.4;
    overflow-wrap: anywhere;
    white-space: normal;
}

/* Hover state for better UX */
span.tq-image-embed figure.tq-image:hover {
    outline: 2px dashed var(--focus-ring);
    outline-offset: 1px;
    cursor: pointer;
}

/* Float support */
span.tq-image-embed[style*="float: left"] {
    margin-right: 1em;
}

span.tq-image-embed[style*="float: right"] {
    margin-left: 1em;
}

/* Inside label editors - ensure resizable works */
div.tq-widget-label-editor span.tq-image-embed figure.tq-image,
div.tq-outcome-label-editor span.tq-image-embed figure.tq-image,
div.tq-option-label-editor span.tq-image-embed figure.tq-image {
    resize: both !important;
    overflow: auto !important;
}

/* ===============================================
   Markup Editor Styles
   =============================================== */

/* Main view layout */
.MEView_window {
    height: 100%;
    display: flex;
    flex-direction: column;
}

.MEView_body {
    display: flex;
    flex-direction: row;
    flex: 1;
    overflow: hidden;
}

/* Toolbar */
.me-toolbar {
    display: flex;
    flex-direction: row;
    align-items: center;
    padding: 0.5em;
    gap: 0.5em;
    background-color: var(--bg-secondary);
    border-bottom: 1px solid var(--divider);
}

button.me-btn-markup {
    border-color: var(--accent);
    background-image: var(--icon-markup-button);
    background-repeat: no-repeat;
    background-size: 70%;
    background-position: center;
    width: 32px;
    height: 32px;
    padding: 0;
    font-size: 0;
    color: transparent;
}

button.me-btn-markup:hover:not(:disabled) {
    background-color: var(--accent-fill-hover);
}

button.me-btn-suppress-tts {
    border-color: var(--status-danger);
    background-image: url('/images/suppress-tts.svg');
    background-repeat: no-repeat;
    background-size: 70%;
    background-position: center;
    width: 32px;
    height: 32px;
    padding: 0;
    font-size: 0;
    color: transparent;
}

button.me-btn-suppress-tts:hover:not(:disabled) {
    background-color: var(--status-danger-hover);
}

button.me-btn-screen-reader {
    border-color: var(--status-danger);
    background-image: var(--icon-screen-reader-text);
    background-repeat: no-repeat;
    background-size: 70%;
    background-position: center;
    width: 32px;
    height: 32px;
    padding: 0;
    font-size: 0;
    color: transparent;
}

button.me-btn-screen-reader:hover:not(:disabled) {
    background-color: var(--status-danger-hover);
}

/* Long-description tool (compliance plan S2): framed graphic + text lines —
 * "an image with its extended description". Icon-button pattern matches
 * me-btn-markup: the button keeps its text content (font-size 0) as the
 * accessible name and its title attribute as the hover tooltip. */
button.me-btn-long-desc {
    border-color: var(--accent);
    background-image: var(--icon-long-description);
    background-repeat: no-repeat;
    background-size: 70%;
    background-position: center;
    width: 32px;
    height: 32px;
    padding: 0;
    font-size: 0;
    color: transparent;
}

button.me-btn-long-desc:hover:not(:disabled) {
    background-color: var(--accent-fill-hover);
}

/* aria-label tool (compliance plan S2): luggage tag carrying an "A" —
 * "a label attached to an element". */
button.me-btn-aria-label {
    border-color: var(--accent);
    background-image: var(--icon-aria-label-tag);
    background-repeat: no-repeat;
    background-size: 70%;
    background-position: center;
    width: 32px;
    height: 32px;
    padding: 0;
    font-size: 0;
    color: transparent;
}

button.me-btn-aria-label:hover:not(:disabled) {
    background-color: var(--accent-fill-hover);
}

/* Edit-replacement tool: the replace-text "A" (same blue as
 * screen-reader-text.svg) under a pencil — red border like the other
 * replace-text tool it edits. */
button.me-btn-edit-replacement {
    border-color: var(--status-danger);
    background-image: url('/images/edit-replacement.svg');
    background-repeat: no-repeat;
    background-size: 70%;
    background-position: center;
    width: 32px;
    height: 32px;
    padding: 0;
    font-size: 0;
    color: transparent;
}

button.me-btn-edit-replacement:hover:not(:disabled) {
    background-color: var(--status-danger-hover);
}

button.me-btn-remove {
    border-color: var(--control-border);
    background-image: var(--icon-trash);
    background-repeat: no-repeat;
    background-size: 70%;
    background-position: center;
    width: 32px;
    height: 32px;
    padding: 0;
    font-size: 0;
    color: transparent;
}

button.me-btn-remove:hover:not(:disabled) {
    background-color: var(--fill-pressed);
}

/* The icon tools now sit in the COMMON TOOLBAR STANDARD bar (styles.css
 * .di-toolbar) as .btn.btn--outline.btn--md + their me-btn-* class — the
 * per-tool rules above (no longer qualified by the retired .me-toolbar
 * container) supply the image, border colour and hidden label; this rule
 * squares them to the design system's 44px target instead of the old 32px
 * (.btn--md's min-height would otherwise leave a 44-tall, 32-wide box). */
.di-toolbar-actions button[class*="me-btn-"] {
    width: 44px;
    min-width: 44px;
    height: 44px;
    padding: 0;
}

.me-toolbar-spacer {
    flex: 1;
}

/* Display area */
.me-display-area {
    flex: 1;
    overflow: auto;
    padding: 1em 2em;
    position: relative;
}

/* Disabled interactions - visible but not clickable */
.me-interaction-disabled {
    pointer-events: none;
    position: relative;
}

.me-interaction-disabled::after {
    content: '';
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background-color: rgba(200, 200, 200, 0.1);
    pointer-events: none;
}

/* Markup tag styling - editor only.
 *
 * SHADOW NOTE (keep in sync): the tags are stamped INSIDE shadow-rendered
 * items — the live copies of every in-item me-* rule below (through the
 * inline-choice block) plus the tracked markers (~:6567-6681) ride in
 * MarkupItemRenderer.present's extra sheet. The page rules remain for the
 * light-DOM Quill editor surfaces.
 *
 * MarkupItemRenderer adds .me-markup-tag / .me-suppress-tts-tag /
 * .me-screen-reader-tag classes to spans the markup-creation editor
 * exposes for region authoring. The bare span[data-catalog-idref]
 * (and span[data-qti-suppress-tts]) selectors used to ride the same
 * rule, but those attributes are present on every rendered SBAC item
 * — so the editor's blue dashed border and shaded background bled
 * into student rendering. Whether a student sees any visual
 * indication is decided at render time by the QTI renderer
 * (RenderingTools._processFromLink adds .p-qti-clickable, which the
 * QTIScripts CSS underlines), not by the presence of catalog-idref. */
.me-markup-tag {
    color: #1565c0;
    background-color: rgba(21, 101, 192, 0.1);
    border: 1px dashed #1565c0;
    border-radius: 2px;
    padding: 0 2px;
    cursor: pointer;
    display: inline;
}

.me-markup-tag:hover {
    background-color: rgba(21, 101, 192, 0.2);
}

/* Suppress TTS tag — editor only */
.me-suppress-tts-tag {
    text-decoration: underline wavy #c62828;
    background-color: rgba(198, 40, 40, 0.1);
    border-radius: 2px;
    padding: 0 2px;
    cursor: pointer;
    display: inline;
}

.me-suppress-tts-tag:hover {
    background-color: rgba(198, 40, 40, 0.2);
}

/* Screen-reader-only tag — editor only */
.me-screen-reader-tag {
    color: #1565c0;
    background-color: rgba(21, 101, 192, 0.08);
    border: 1px dashed #c62828;
    border-radius: 2px;
    padding: 0 2px;
    cursor: pointer;
    display: inline;
    font-style: italic;
}

.me-screen-reader-tag:hover {
    background-color: rgba(21, 101, 192, 0.2);
}

/* Long-description anchor — editor only (plan S2). Outlines the described
   visual (img / svg / table) so the tagger sees which visuals carry one. */
.me-long-desc-tag {
    display: inline-block;
    border: 2px dashed #6a1b9a;
    border-radius: 2px;
    padding: 2px;
    cursor: pointer;
}

.me-long-desc-tag:hover {
    background-color: rgba(106, 27, 154, 0.1);
}

/* aria-label marker — editor only (plan S2). The attribute is invisible by
   nature; the outline shows the tagger which elements carry an authored
   label. Colour meets 3:1 against white for non-text indicators. */
.me-aria-label-tag {
    outline: 2px dotted #00695c;
    outline-offset: 1px;
}

/* Spoken-replacement chip — editor only. The delivery `qti-visually-hidden`
   rule clips this off-screen; inside the markup editor the author MUST see
   the replacement words, styled distinctly as "what TTS speaks instead".
   Colour pair #14401a on #e6efe6 is ~11:1 (WCAG 2.x AAA). */
.me-display-area .qti-visually-hidden,
.me-display-area .me-replacement-text {
    position: static !important;
    clip: auto !important;
    clip-path: none !important;
    width: auto !important;
    height: auto !important;
    overflow: visible !important;
    display: inline !important;
    margin: 0 0 0 2px;
    padding: 0 4px;
    background-color: #e6efe6;
    color: #14401a;
    border: 1px dashed #2e7d32;
    border-radius: 2px;
    font-style: italic;
    font-size: 0.9em;
    cursor: pointer;
}

.me-display-area .qti-visually-hidden::before {
    content: '\1F50A\00A0'; /* speaker glyph — signals "spoken replacement" */
    font-style: normal;
}

.me-display-area .qti-visually-hidden:hover {
    background-color: #d4e6d4;
}

/* Selected tag for removal */
.me-tag-selected {
    outline: 2px solid #000;
    outline-offset: 1px;
}

/* An equation selected as an ATOMIC tag target (click-to-tag — no text selection is
   possible over MathML). Dashed to distinguish "about to be tagged" from the solid
   outline of an existing tag selected for removal. */
.me-display-area math {
    cursor: pointer;
}
.me-equation-selected {
    outline: 2px dashed var(--focus-ring);
    outline-offset: 2px;
    background-color: var(--accent-tint);
}

/* Selection indicator when text is selected */
.me-has-selection button.me-btn-markup,
.me-has-selection button.me-btn-suppress-tts,
.me-has-selection button.me-btn-screen-reader {
    animation: me-pulse 1s ease-in-out infinite;
}

@keyframes me-pulse {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.6; }
}

/* Status message — screen readers only (owner, 2026-09-11): the span also
   carries .tq-sr-only, so it is announced, never seen, and can never re-wrap
   the sticky bar under a drag. No visual rules belong here. */

/* Interaction overlay for selection */
.me-interaction-overlay {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background-color: transparent;
    z-index: 1;
}

/* Expanded inline choice in markup editor */
.me-inline-choice-expanded {
    display: inline-block;
    border: 1px solid var(--divider);
    border-radius: var(--radius-sm);
    padding: 4px 8px;
    background-color: var(--bg-secondary);
    margin: 2px 0;
}

.me-inline-choice-header {
    font-size: 0.75em;
    color: var(--accent);
    margin-bottom: 2px;
    user-select: none;
}

.me-inline-choice-option {
    padding: 2px 4px;
    border-bottom: 1px dotted var(--divider);
    user-select: text;
    cursor: text;
}

.me-inline-choice-option:last-child {
    border-bottom: none;
}

/* Interaction label in markup editor */
.me-interaction-label {
    position: absolute;
    top: 0;
    right: 0;
    background-color: rgba(0, 0, 0, 0.6);
    color: white;
    font-size: 0.75em;
    padding: 0.2em 0.5em;
    border-radius: 0 0 0 4px;
    z-index: 2;
}

/* ==========================================================================
   Markup Creation System (mc- prefix)
   ========================================================================== */

/* Main layout */
.MCView_window {
    height: 100%;
    display: flex;
    flex-direction: column;
}

.mc-header {
    display: flex;
    align-items: baseline;
    gap: 1em;
    padding: 0.5em 1em;
    border-bottom: 1px solid var(--divider);
}

.mc-header h1 {
    margin: 0;
}

.mc-item-info {
    font-size: 0.9em;
    color: var(--text-secondary);
}

/* Toolbar */
.mc-toolbar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    padding: 0.5em;
    gap: 0.5em;
    background-color: var(--bg-secondary);
    border-bottom: 1px solid var(--divider);
}

/* Buttons */
.mc-btn {
    display: inline-flex;
    align-items: center;
    gap: 0.3em;
    border: 1px solid transparent;
}

/* Tag navigation stepper - now rendered in panel header, see .mc-panel-nav */

/* Content area */
.mc-content.mc-content-full {
    flex: 1;
    overflow: auto;
    position: relative;
}

.mc-display-area {
    padding: 1em 2em;
    min-height: 200px;
}

.mc-no-item-message {
    color: var(--text-secondary);
    font-style: italic;
    text-align: center;
    padding: 3em 1em;
}

.mc-no-regions-note {
    color: var(--text-secondary);
    font-style: italic;
    padding: 0.5em;
}

/* Support-type picker — rendered only for purposes that declare more than
   one catalog support type (Content Supports, Simplified Content). Sits
   above the editors because it selects which card they are bound to. */
.mc-support-type-section {
    padding: 0.5em;
    margin-bottom: 0.5em;
    border-bottom: 1px solid var(--divider);
}

.mc-support-type-label {
    display: block;
    margin-bottom: 0.25em;
    font-weight: 600;
    color: var(--text-primary);
}

.mc-support-type-section select {
    width: 100%;
}

/* Status bar */
.mc-status-bar {
    padding: 0.3em 0.5em;
    font-size: 0.85em;
    color: var(--text-secondary);
    font-style: italic;
    border-top: 1px solid var(--divider);
    background-color: var(--bg-secondary);
}

/* Draggable editor panel */
.mc-draggable-panel {
    position: fixed;
    z-index: 1000;
    width: 400px;
    background-color: var(--surface);
    border: 2px solid var(--accent);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-2);
    display: flex;
    flex-direction: column;
    max-height: 60vh;
}

.mc-draggable-panel-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0.4em 0.6em;
    background-color: var(--accent-fill);
    color: var(--text-on-accent);
    border-radius: 4px 4px 0 0;
    cursor: grab;
    user-select: none;
    flex-shrink: 0;
}

.mc-draggable-panel-header:active {
    cursor: grabbing;
}

.mc-draggable-panel-title {
    font-size: 0.9em;
    font-weight: 600;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    flex-shrink: 1;
}

.mc-draggable-panel-minimize {
    background: none;
    border: none;
    color: var(--text-on-accent);
    font-size: 1.3em;
    cursor: pointer;
    padding: 0 0.3em;
    line-height: 1;
    border-radius: var(--radius-sm);
    flex-shrink: 0;
}

.mc-draggable-panel-minimize:hover {
    background-color: var(--fill-hover);
}

.mc-draggable-panel-content {
    padding: 0.6em;
    overflow: auto;
    flex: 1;
    min-height: 0;
}

.mc-draggable-panel-footer {
    display: flex;
    justify-content: flex-end;
    align-items: center;
    gap: 0.4em;
    padding: 0.4em 0.6em;
    border-top: 1px solid var(--divider);
}

.mc-btn-danger {
    border: 1px solid transparent;
}

/* Minimized state: header only, clickable to restore */
.mc-draggable-panel-minimized {
    max-height: none;
}

.mc-draggable-panel-minimized .mc-draggable-panel-header {
    border-radius: var(--radius-sm);
    cursor: pointer;
}

/* Panel header navigation buttons */
.mc-panel-nav {
    display: inline-flex;
    align-items: center;
    gap: 2px;
    margin-left: auto;
    margin-right: 0.4em;
    flex-shrink: 0;
}

.mc-panel-nav-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: none;
    border: none;
    color: var(--text-on-accent);
    cursor: pointer;
    padding: 2px;
    border-radius: var(--radius-sm);
    position: relative;
    min-width: 24px;
    min-height: 24px;
}

.mc-panel-nav-btn:hover:not(:disabled) {
    background-color: var(--fill-hover);
}

.mc-panel-nav-btn:disabled {
    opacity: 0.35;
    cursor: not-allowed;
}

.mc-panel-nav-progress {
    font-size: 0.8em;
    color: var(--text-on-accent);
    padding: 0 0.3em;
    white-space: nowrap;
    user-select: none;
}

.mc-nav-badge {
    position: absolute;
    bottom: -1px;
    right: -2px;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 12px;
    height: 12px;
    background-color: var(--surface);
    color: var(--accent);
    border: 1px solid var(--accent);
    border-radius: 2px;
    font-size: 8px;
    font-weight: 600;
    line-height: 1;
    pointer-events: none;
}

/* ───────────────────────── AfA PnP Dialog ───────────────────────── */

dialog.tq-pnp-dialog {
    z-index: 50;
    position: fixed;
    align-self: anchor-center;
    width: 60%;
    max-width: 800px;
    max-height: 80vh;
    display: flex;
    flex-direction: column;
    font-family: inherit;
    font-size: 1rem;
    line-height: 1.45;
}

dialog.tq-pnp-dialog::backdrop {
    background-color: rgba(15, 23, 42, 0.55);
}

.tq-pnp-dialog-content {
    flex: 1;
    overflow-y: auto;
    padding: 12px 16px;
}

.tq-pnp-dialog-buttons {
    display: flex;
    justify-content: flex-end;
    gap: 10px;
    padding: 12px 16px;
    border-top: 1px solid var(--divider);
    background-color: var(--bg-secondary);
    border-radius: 0 0 10px 10px;
}

/* Collapsible sections */

.tq-pnp-section {
    /* Its header strip runs to the edges: clipped, so the card's corners stay round. */
    overflow: hidden;
    margin-bottom: 8px;
}

.tq-pnp-section-header {
    display: flex;
    flex-direction: row;
    align-items: center;
    gap: 8px;
    padding: 8px 12px;
    cursor: pointer;
    background-color: var(--bg-secondary);
    user-select: none;
    border-radius: var(--radius-sm);
}

.tq-pnp-section-header:hover {
    background-color: var(--fill-hover);
}

.tq-pnp-chevron {
    font-size: 0.7em;
    width: 12px;
    text-align: center;
    color: var(--text-secondary);
}

.tq-pnp-section-body {
    padding: 12px;
}

/* Form grid — label + control pairs */

.tq-pnp-form-grid {
    display: grid;
    grid-template-columns: auto 1fr;
    gap: 8px 12px;
    align-items: center;
}

.tq-pnp-form-grid > label {
    font-weight: 500;
    white-space: nowrap;
}

/* Checkbox grids — 3-column */

.tq-pnp-checkbox-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 6px 12px;
}

/* Checkbox row — inline flow */

.tq-pnp-checkbox-row {
    display: flex;
    flex-wrap: wrap;
    gap: 8px 16px;
    margin-bottom: 4px;
}

/* Individual checkbox item */

.tq-pnp-checkbox-item {
    display: flex;
    align-items: center;
    gap: 4px;
}

.tq-pnp-checkbox-item label {
    cursor: pointer;
}

/* Form row — single label + input */

.tq-pnp-form-row {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-top: 6px;
}

/* Sub-labels within sections */

.tq-pnp-sub-label {
    font-weight: 600;
    margin-top: 10px;
    margin-bottom: 6px;
    font-size: 0.9em;
    color: var(--text-primary);
}

/* Input styling */

.tq-pnp-input {
    min-width: 120px;
}

.tq-pnp-number-input {
    width: 80px;
}

.tq-pnp-select {
    min-width: 140px;
}

.tq-pnp-color-input {
    width: 50px;
    height: 28px;
    padding: 2px;
    border: 1px solid var(--control-border);
    border-radius: var(--radius-field);
    cursor: pointer;
}

/* Radio groups */

.tq-pnp-radio-group {
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.tq-pnp-radio-row {
    display: flex;
    align-items: center;
    gap: 6px;
}

.tq-pnp-radio-row label {
    cursor: pointer;
}

/* Enable/disable toggle row */

.tq-pnp-enable-row {
    margin-bottom: 8px;
}

/* Detail controls — disabled state */

.tq-pnp-detail-controls[data-disabled="true"] {
    opacity: 0.5;
    pointer-events: none;
}

/* Sub-groups within a section */

.tq-pnp-sub-group {
    border-top: 1px solid var(--divider);
    padding-top: 10px;
    margin-top: 10px;
}

.tq-pnp-sub-group:first-child {
    border-top: none;
    padding-top: 0;
    margin-top: 0;
}

/* Timing group */

.tq-pnp-timing-group {
    display: flex;
    flex-direction: column;
    gap: 6px;
}

/* Font name chips */

.tq-pnp-font-name-row {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-top: 6px;
    flex-wrap: wrap;
}

.tq-pnp-chip-list {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
}

.tq-pnp-chip {
    display: inline-flex;
    align-items: center;
    gap: 4px;
}

.tq-pnp-chip-remove {
    cursor: pointer;
    font-weight: 600;
    color: var(--text-secondary);
    margin-left: 2px;
}

.tq-pnp-chip-remove:hover {
    color: var(--status-danger);
}

.tq-pnp-small-btn {
    padding: 3px 10px;
    font-size: 0.85em;
}

/* ── Accommodation Picker ── */

.tq-acc-description {
    font-size: 0.8em;
    color: var(--text-secondary);
    font-style: italic;
    margin-top: 2px;
    line-height: 1.3;
}

.tq-acc-hint {
    margin-top: 8px;
}

.tq-acc-radio-group {
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.tq-acc-combo-detail {
    margin-left: 24px;
    padding: 6px 0;
}

.tq-acc-combo-detail[data-disabled="true"] {
    opacity: 0.5;
    pointer-events: none;
}

/* ==========================================================================
   Preview View (tq-pv- prefix) — item / passage-set / stimulus preview
   with the always-visible settings bar
   ========================================================================== */

.PreviewView_window {
    height: 100%;
    display: flex;
    flex-direction: column;
}

.tq-pv-header {
    border-bottom: 1px solid var(--divider);
}

/* The way back out of Preview: its own row directly under the settings panel,
   far left, carrying the same circle-arrow-left icon the scoring view's
   return uses (owner, 2026-09-12). Outside the panel because the panel is
   collapsed on every arrival that has somewhere to return to. */
.tq-pv-return-row {
    display: flex;
    justify-content: flex-start;
    padding: 6px 0 2px 8px;
}

.tq-pv-h1 {
    margin: 0;
}

/* The title bar IS the settings-accordion toggle: full-width, clearly
   interactive, 7:1 text contrast, visible keyboard focus. */
.tq-pv-header-toggle {
    display: flex;
    align-items: baseline;
    gap: 0.75em;
    width: 100%;
    padding: 0.5em 1em;
    background: none;
    border: none;
    font: inherit;
    font-weight: 600;
    color: var(--text-primary);
    text-align: left;
    cursor: pointer;
}

.tq-pv-header-toggle:hover {
    background-color: var(--fill-hover);
}

.tq-pv-header-toggle:focus-visible {
    outline: 3px solid var(--focus-ring);
    outline-offset: -3px;
}

.tq-pv-chevron {
    font-size: 0.9em;
    color: var(--text-primary);
}

.tq-pv-title {
    font-size: 1em;
}

.tq-pv-settings {
    padding: 0.5em;
    background-color: var(--bg-secondary);
    border-bottom: 1px solid var(--divider);
}

.tq-pv-row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5em;
    padding: 0.25em 0.5em;
}

.tq-pv-row label {
    font-weight: 500;
    white-space: nowrap;
}

.tq-pv-row label[data-disabled="true"] {
    opacity: 0.5;
}

.tq-pv-select {
    min-width: 180px;
}

/* 7:1 contrast on the light settings bar (WCAG AAA) */
.tq-pv-modified {
    color: var(--status-warning);
    font-weight: 600;
    font-size: 0.9em;
}

.tq-pv-chips {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.4em;
    padding: 0.25em 0.5em 0.4em;
}

.tq-pv-chips-label {
    font-size: 0.85em;
    font-weight: 600;
    color: var(--text-primary);
}

.tq-pv-chip-none {
    background-color: var(--fill);
    color: var(--text-primary);
    font-style: italic;
}

.tq-pv-notice p {
    margin: 0;
    font-size: 0.9em;
}

/* Preview fills the shell body it sits in — a flex column the height of
   .MTView_body (a definite flex item, so the percentage resolves) — and
   the display takes whatever the header, settings panel, return row,
   notice and status bar leave. That is what lets a paginated render
   (PaginatedPresentation.css, HOST FIT) put its pagers at the bottom of
   the window instead of below it, and re-page live when the settings
   panel opens or closes. A stacked render keeps its engine height and
   scrolls inside the wrapper, as it scrolled inside the body before.

   The 200px floor sits on the WRAPPER, the flex item that actually
   shrinks: in a short window, or at high zoom with the settings panel
   open, the chrome alone is taller than the root, and a wrapper with
   min-height 0 shrinks to 0px, hiding the item (a floor on the display
   inside it does not stop that; the display just overflows a 0px
   scroller). With the floor the root overflows instead and the shell
   body scrolls to the item. min-height rather than flex: 1 0 200px, so
   the floor is independent of the .mc-content-full flex shorthand the
   other views share. The display keeps its own floor, so content
   shorter than 200px still gets a usable box. */
.tq-pv-root {
    display: flex;
    flex-direction: column;
    height: 100%;
}

.tq-pv-root > .mc-content-full {
    display: flex;
    flex-direction: column;
    min-height: 200px;
}

.tq-pv-display {
    padding: 1em 2em;
    min-height: 200px;
    flex: 1 1 0;
}

.tq-pv-stimulus {
    max-width: 60em;
    margin: 0 auto;
}

.tq-pv-status {
    padding: 0.3em 0.5em;
    font-size: 0.85em;
    color: var(--text-secondary);
    font-style: italic;
    border-top: 1px solid var(--divider);
    background-color: var(--bg-secondary);
}

/* ========== Math Formula Blot (Inline Equation Editor) ========== */

/* Inline blot wrapper */
qti-span.tq-math-formula {
    display: inline-block;
    vertical-align: middle;
}

/* Math element inside the blot */
qti-span.tq-math-formula math {
    cursor: pointer;
    padding: 0 2px;
    /* As in delivery (PaldroeStyles.css math[data-eq-value]): display style,
       so a fraction is at text size. */
    math-style: normal;
}

/* Hover indicator for editable equation */
qti-span.tq-math-formula:hover math {
    outline: 2px dashed #1565c0;
    outline-offset: 2px;
    border-radius: 2px;
}

/* Toolbar button icon - sigma symbol via SVG data URI */
div.ql-toolbar.ql-snow.tq-editor-toolbar button.ql-math-formula {
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 18 18'%3E%3Cpath d='M3 2h12v2.5H8.5L12 9l-3.5 4.5H15V16H3v-2.5l5-5.5L3 4.5z' fill='%23444'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-size: 24px 24px;
    background-position: center;
}

/* Asset Services "Request graphic" toolbar button — artist's beret +
   paintbrush, so it can't be confused with the framed-picture Insert
   Image icon beside it (they used to be nearly identical). Foreground
   is the Asset Studio card's violet (#5E00BD, see images/AssetStudio.svg)
   to tie the button to the studio it sends work to. Brush anatomy:
   round-ended handle, thick ferrule band, bristle head that bulges
   wider than the handle before tapering (a straight taper read as a
   knife blade). */
div.ql-toolbar.ql-snow.tq-editor-toolbar button.ql-asset {
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 18 18'%3E%3Cpath d='M1.8 6.4 Q1.5 3.5 5.2 2.7 Q9 1.9 10.2 4.3 Q10.7 5.5 9.4 6.2 Q5.3 7.6 1.8 6.4 Z' fill='%235E00BD'/%3E%3Ccircle cx='6' cy='2.1' r='0.8' fill='%235E00BD'/%3E%3Cpath d='M16.4 6.6 L12.6 10.4' stroke='%235E00BD' stroke-width='1.5' stroke-linecap='round'/%3E%3Cpath d='M12.6 10.4 L11.15 11.85' stroke='%235E00BD' stroke-width='2.4'/%3E%3Cpath d='M10.3 11.0 L12.0 12.7 Q11.5 15.0 7.2 15.4 Q7.9 12.3 10.3 11.0 Z' fill='%235E00BD'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-size: 24px 24px;
    background-position: center;
}

/* Asset Services placeholder (pending) box in the editor. */
.tq-asset-pending {
    display: inline-block;
    padding: 6px 10px;
    border: 2px dashed var(--control-border);
    border-radius: var(--radius-sm);
    background: var(--bg-secondary);
    color: var(--text-primary);
    font-style: italic;
}

/* AI provider's note on a slot (why the last round died / needs a human).
   Dark red on the light pending background — 7:1+ contrast (WCAG AAA). */
.tq-asset-provider-note {
    display: block;
    margin-top: 4px;
    font-size: 0.85em;
    font-style: normal;
    color: var(--status-danger);
}

/* Asset Services filled slot: the asset + a "request revision" icon button that
   is revealed on hover (mouse) or keyboard focus. The button is a real, always-
   in-tab-order <button>, so keyboard users can Tab to it (it becomes visible on
   :focus) and press Enter/Space to open the revision panel. */
.tq-asset-filled {
    position: relative;
    display: inline-block;
}
/* Delivered graphics / video are resizable, like images (mirrors
   span.tq-image-embed figure.tq-image): drag the figure's corner handle. The
   .tq-asset-filled wrapper is inline-block, so it grows with the figure and the
   revise button stays pinned to its top-right corner. */
span.tq-asset-slot figure.tq-asset-media {
    display: inline-block;
    margin: 0;
    padding: 0;
    text-align: center;
    resize: both;
    overflow: hidden;
    min-width: 50px;
    min-height: 50px;
}
span.tq-asset-slot figure.tq-asset-media > img,
span.tq-asset-slot figure.tq-asset-media > video {
    display: block;
    width: 100%;
    height: auto;
    object-fit: contain;
}
/* Cert set 2026-10-01 #74: a picture or video keeps its proportions when it
   is resized. Once the media's size is known the figure carries its
   aspect-ratio and no height (FigureAspect.js), so the handle sets the width
   only and the ratio decides the height; `height: auto` also overrides a
   height an older body still stores. And the figure never runs past the
   content column. */
span.tq-asset-slot .tq-asset-filled,
span.tq-image-embed > span[contenteditable="false"],
span.tq-image-embed figure.tq-image,
span.tq-asset-slot figure.tq-asset-media {
    max-width: 100%;
    box-sizing: border-box;
}
span.tq-image-embed figure.tq-image[style*="aspect-ratio"],
span.tq-asset-slot figure.tq-asset-media[style*="aspect-ratio"] {
    resize: horizontal;
    height: auto !important;
}
.tq-asset-revise {
    position: absolute;
    top: 4px;
    right: 4px;
    width: 28px;
    height: 28px;
    line-height: 24px;
    padding: 0;
    font-size: 16px;
    text-align: center;
    color: var(--text-primary);
    background: var(--surface);
    border: 1px solid var(--control-border);
    border-radius: var(--radius-sm);
    cursor: pointer;
    opacity: 0;
    transition: opacity 0.12s ease-in-out;
}
.tq-asset-filled:hover .tq-asset-revise,
.tq-asset-revise:focus {
    opacity: 1;
}
.tq-asset-revise:hover {
    background: var(--fill-hover);
}
.tq-asset-revise:focus {
    outline: 2px solid var(--focus-ring);
    outline-offset: 1px;
}
/* A delivered video's Captions button (QTI A-13b, AssetSlot.buildCaptionsButton):
   it shares the revise button's look and hover reveal, sitting to its left.
   Filled in once captions are attached, so their presence shows at a glance. */
.tq-asset-captions {
    right: 36px;
    width: 32px;
    font-size: 12px;
    font-weight: 600;
}
.tq-asset-captions.tq-has-captions {
    color: var(--text-on-accent);
    background: var(--accent-fill);
    border-color: var(--accent);
}
.tq-asset-captions.tq-has-captions:hover {
    background: var(--accent-fill-hover);
}
/* GetCaptionTrackDialog: what is attached now, and why a pick was refused.
   Both notes span the two-column label | control grid. The "attached" note sat
   in the first cell, which pushed every label into the right-hand column, one
   row out of line with its control, and left the Remove checkbox alone on the
   last row (cert set 2026-10-03, bug #91). */
.tq-captions-current {
    grid-column: 1 / -1;
    margin: 0 0 8px 0;
}
.tq-captions-problem {
    grid-column: 1 / -1;
    color: var(--status-danger);
    margin: 8px 0 0 0;
}
/* GetVideoReplacementDialog (bug #98): a video that replaces a delivered one.
   The flag says the pre-filled alt text describes the PREVIOUS video, and the
   field keeps an amber edge until the deliverer edits it; the captions choice
   is a radio group spanning both columns. Not colour alone: the flag's words. */
.tq-replace-alt-flag {
    grid-column: 1 / -1;
    margin: 0;
    padding: 6px 10px;
    border-left: 4px solid var(--status-warning);
    background: var(--status-warning-tint);
    color: var(--status-warning);
}
dialog.tq-video-replace-dialog textarea.tq-replace-alt-old,
dialog.tq-alt-replace-dialog textarea.tq-replace-alt-old {
    border: 2px solid var(--status-warning);
}
.tq-replace-captions-choice {
    grid-column: 1 / -1;
    margin: 0;
    padding: 8px 12px;
    border: 1px solid var(--divider);
    border-radius: var(--radius-sm);
}
.tq-replace-captions-choice.tq-missing-required {
    border: 2px solid var(--status-danger);
}
.tq-replace-captions-option {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 4px 0;
}
.tq-replace-captions-option input[type="radio"] {
    margin: 0;
}
/* Its columns are every BasicDialog's (dialog.tq-basic-dialog > .tq-dialog-widgets). */
dialog.tq-captions-dialog .tq-dialog-widgets {
    align-items: center;
    column-gap: 16px;
    row-gap: 12px;
}
dialog.tq-captions-dialog .tq-dialog-widgets > input[type="checkbox"] {
    justify-self: start;
    margin: 0;
}
dialog.tq-captions-dialog .tq-dialog-widgets > input:focus-visible,
dialog.tq-captions-dialog .tq-dialog-widgets > select:focus-visible {
    outline: 3px solid var(--focus-ring);
    outline-offset: 2px;
}

/* Equation editor dialog */
dialog.tq-equation-dialog {
    z-index: 50;
    position: fixed;
    align-self: anchor-center;
    min-width: 500px;
    max-width: 90vw;
}

dialog.tq-equation-dialog::backdrop {
    background-color: rgba(0, 0, 0, 0.4);
}

dialog.tq-equation-dialog .tq-dialog-title {
    padding: 10px 16px;
    border-bottom: 1px solid var(--divider);
    background-color: var(--bg-secondary);
    border-radius: 6px 6px 0 0;
}

dialog.tq-equation-dialog .tq-equation-editor-container {
    padding: 16px;
    min-height: 200px;
}

dialog.tq-equation-dialog .tq-dialog-buttons {
    padding: 10px 16px;
    border-top: 1px solid var(--divider);
    background-color: var(--bg-secondary);
    border-radius: 0 0 6px 6px;
}

/* ========== HOTTEXT AUTHORING ========== */

.tq-hottext-markup-section {
    margin: 12px 0;
}

.tq-hottext-toolbar {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin-bottom: 8px;
}

/* The marking buttons are app buttons (.btn .btn--secondary, HottextTemplate.js;
 * cert set 2026-10-01 item 43) - no rule here may restyle them. */

/* Include text in item / Link to stimulus: two radio options with room
 * between them and between each radio and its words (item 43). */
.tq-hottext-mode-selector {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem 1.5rem;
    margin: 0.75rem 0;
}
.tq-hottext-mode-selector label {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    cursor: pointer;
}

.tq-hottext-editor {
    border: 1px solid #bbb;
    border-radius: 4px;
    padding: 10px;
    min-height: 120px;
    max-height: 400px;
    overflow-y: auto;
    line-height: 1.8;
    background: white;
}

.tq-hottext-editor:focus {
    outline: 2px solid #0078D4;
    outline-offset: 1px;
}

/* Gap match passage panel (GapMatchTemplate.js; cert set 2026-10-01 item 26):
 * the Insert gap button and the "every gap must be filled" checkbox sat
 * touching each other on one unstyled line. A row with a real gap between
 * them, the checkbox's label clickable as a whole. */
.tq-gap-match-toolbar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 1rem;
    margin: 0.5rem 0;
}
.tq-gap-match-required {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    cursor: pointer;
}
.tq-gap-match-required input[type="checkbox"] {
    margin: 0;
}
.tq-gap-match-hint,
.tq-gap-match-count {
    margin: 0.4rem 0;
}
.tq-gap-match-editor .ql-editor {
    min-height: 8rem;
}

/* Authoring-only highlight for marked hottext regions — shown ONLY
 * inside the Quill editor (.ql-editor) so it never leaks into rendered or
 * preview contexts (the stimulus context panel, defineScoring, delivery),
 * where the runtime hottext widget controls region appearance instead
 * (plain until hover/focus). The qti-hottext-authoring class still rides
 * along in saved bodies but is inert outside the editor. */
.ql-editor .qti-hottext-authoring {
    background-color: #fff3cd;
    border-bottom: 2px dashed #d4a017;
    padding: 1px 2px;
    border-radius: 2px;
}

/* Accessibility content (qti-visually-hidden / qti-hidden) is hidden in
 * delivery (QtiBaseStyles.css), but inside the Quill editor (.ql-editor) it
 * must stay VISIBLE and editable — otherwise an author can't see or change the
 * screen-reader / spoken-replacement text. Defeat the delivery hide (the
 * visually-hidden recipe uses `position: fixed !important`, so the un-hide
 * needs !important too) and give it a muted dashed affordance so the author
 * can tell it's special-purpose content. The classes still ride along in
 * saved bodies and behave normally outside the editor. */
.ql-editor .qti-visually-hidden,
.ql-editor .qti-hidden {
    position: static !important;
    overflow: visible;
    clip: auto;
    width: auto;
    height: auto;
    margin: 0;
    display: inline;
    outline: 1px dashed #6c8ebf;
    outline-offset: 1px;
    background-color: #eef3fb;
    color: #335;
}

/* qti-keyword-emphasis is gated by .pnp-keyword-emphasis at delivery, so it
 * looks ordinary outside that context. In the editor the author must still see
 * which words they've marked, so always show the emphasis here. */
.ql-editor .qti-keyword-emphasis {
    font-weight: 700;
}

.tq-hottext-region-list {
    margin-top: 8px;
}

.tq-hottext-region-table {
    width: 100%;
}

.tq-hottext-region-table td:first-child {
    /* Wide enough for a generated identifier (a GUID-length WAF.makeID) -
     * 120px clipped them (item 43). */
    width: 38ch;
    max-width: 50%;
}

.tq-hottext-region-table td:last-child {
    width: 30px;
    text-align: center;
}

.tq-hottext-region-table button {
    background: none;
    border: none;
    cursor: pointer;
    color: var(--status-danger);
    font-size: 1rem;
}

.tq-hottext-region-id {
    width: 100%;
    box-sizing: border-box;
    padding: 2px 4px;
    border: 1px solid transparent;
    background: transparent;
    font-family: inherit;
    font-size: inherit;
    font-weight: 600;
}

.tq-hottext-region-id:hover,
.tq-hottext-region-id:focus {
    border-color: var(--divider);
    background: var(--fill-hover);
    outline: none;
}

.tq-hottext-region-jump {
    color: var(--accent);
    text-decoration: none;
    cursor: pointer;
}

.tq-hottext-region-jump:hover,
.tq-hottext-region-jump:focus {
    text-decoration: underline;
}

.tq-hottext-empty {
    color: var(--text-secondary);
    font-style: italic;
}

.tq-hottext-prompt-section {
    margin: 12px 0;
}

.tq-hottext-prompt-editor {
    border: 1px solid var(--divider);
    border-radius: var(--radius-sm);
    padding: 8px;
    min-height: 40px;
    background: var(--surface);
}

.tq-hottext-prompt-editor:focus {
    outline: 2px solid var(--focus-ring);
    outline-offset: 1px;
}

/* ----- Simple-scoring panel layout -----
   The panel renders inside .tq-side-panel (max-width: 30% of the
   viewport). Its WAF.Table2D (long expected-value strings, item-id
   columns, button labels) and inline editors otherwise overflow
   horizontally and obscure the item display next to the panel.
   Constrain everything inside the panel to the side-panel width;
   long content scrolls inside the panel rather than escaping it. */

div.tq-simple-scoring-panel {
    box-sizing: border-box;
    width: 100%;
    max-width: 100%;
    overflow: auto;
    padding: 0.5em;
}

div.tq-simple-scoring-panel * {
    box-sizing: border-box;
    max-width: 100%;
}

div.tq-simple-scoring-panel div.tq-simple-scoring-table {
    overflow-x: auto;
    width: 100%;
}

/* Table2D-rendered cells: wrap long values rather than running off
   the right edge. The exemplar table includes captured-response
   summaries (identifier lists, equation strings) that can be wide. */
div.tq-simple-scoring-panel table {
    width: 100%;
    table-layout: fixed;
    word-break: break-word;
}

div.tq-simple-scoring-panel table td,
div.tq-simple-scoring-panel table th {
    overflow-wrap: anywhere;
    word-break: break-word;
}

/* Per-option response table for the "correct"/"mapping" template
   editors (SimpleScoringPanel._renderMappingTable / _renderCorrectTable):
   option | score-or-contribution | delete. Light borders + padding so
   the columns read as a table. */
div.tq-simple-scoring-panel table.tq-simple-scoring-response-table {
    border-collapse: collapse;
    margin: 0.4em 0;
}
div.tq-simple-scoring-panel table.tq-simple-scoring-response-table td,
div.tq-simple-scoring-panel table.tq-simple-scoring-response-table th {
    border: 1px solid var(--divider);
    padding: 0.25em 0.5em;
    text-align: left;
    vertical-align: middle;
}
/* The panel-wide table rule above forces table-layout:fixed, so COLUMN
   widths come from the HEADER row (a td width is ignored) — without
   these the columns split equally and a narrow panel squeezed the
   controls, while the option column lost the room long content needs.
   One narrow, fixed control column (the contribution input stacked over
   the tq_delete icon); the option/answer column takes the remainder. */
div.tq-simple-scoring-panel table.tq-simple-scoring-response-table th.tq-simple-scoring-col-compact {
    width: 5.5em;
}
div.tq-simple-scoring-panel table.tq-simple-scoring-response-table th.tq-simple-scoring-col-part {
    width: 10em;
}
/* The compact control cell: contribution input above the delete icon,
   centered, hugging the top of tall option rows. */
div.tq-simple-scoring-panel td.tq-simple-scoring-cell-compact {
    vertical-align: top;
    text-align: center;
}
div.tq-simple-scoring-panel div.tq-simple-scoring-cell-stack {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.15em;
}
/* Long unbreakable content (equations, wide images) scrolls INSIDE its
   cell instead of overflowing the column/panel. word-break/overflow-wrap
   (panel-wide rules above) handle ordinary text. */
div.tq-simple-scoring-panel td.tq-simple-scoring-cell-option {
    overflow-x: auto;
}
div.tq-simple-scoring-panel td.tq-simple-scoring-cell-option img {
    max-width: 100%;
    height: auto;
}
div.tq-simple-scoring-panel td.tq-simple-scoring-cell-option math {
    display: block;
    display: block math; /* keep MathML layout: a plain block stacks an equation's parts one per line */
    max-width: 100%;
    overflow-x: auto;
}
/* Small contribution input — a number input's INTRINSIC width (~10em)
   otherwise pokes past the narrow fixed column. Deliberately compact:
   the option content owns the table's width. */
div.tq-simple-scoring-panel input.tq-simple-scoring-cell-score {
    width: 4.5em;
    max-width: 100%;
    box-sizing: border-box;
    font-size: 0.85em;
    padding: 0.15em 0.3em;
}
div.tq-simple-scoring-panel div.tq-simple-scoring-fullcredit-heading {
    margin: 0.5em 0 0.25em 0;
}
/* F5: a chosen scoring template still waiting for its answer - a WARNING, not an
 * error (the tq-score-notice amber: #7c2d12 on #fef3c7 is AAA, with a glyph so it
 * is not colour-only). The list names each interaction that needs its answer. */
div.tq-simple-scoring-panel div.tq-simple-scoring-warning {
    /* Long unbroken text (a label, a URL) wraps inside the narrow side panel
     * instead of running past the box's border (cert-set bug 21). */
    overflow-wrap: anywhere;
    max-width: 100%;
    box-sizing: border-box;
    margin: 0.5em 0;
}
div.tq-simple-scoring-panel div.tq-simple-scoring-warning > p:first-child::before {
    content: "\26A0\00A0";   /* ⚠ warning sign */
    font-weight: 600;
}
div.tq-simple-scoring-panel div.tq-simple-scoring-warning > p {
    margin: 0 0 0.25em 0;
}
div.tq-simple-scoring-panel div.tq-simple-scoring-warning ul.tq-scoring-gaps {
    margin: 0.25em 0 0 1.25em;
    padding: 0;
}
/* The same gap lines in a notify dialog or the item history wrap too. */
ul.tq-scoring-gaps {
    overflow-wrap: anywhere;
}

/* Inline-edit number inputs (Score column, default-score field).
   Without a max-width they default to a wide native size. */
div.tq-simple-scoring-panel input[type="number"],
div.tq-simple-scoring-panel input[type="text"] {
    max-width: 8em;
    box-sizing: border-box;
}

div.tq-simple-scoring-panel select {
    max-width: 100%;
    box-sizing: border-box;
}

/* Template-picker (CustomSelectWidget) — max 90% of its container so
   it sits comfortably next to the picker label, and let the long
   description text wrap inside both the closed-state button and the
   open-state dropdown options. Without these rules the widget's
   default styles (PaldroeStyles.css §"CUSTOM SELECT WIDGET") render
   single-line text with overflow:hidden + text-overflow:ellipsis on
   templates with longer descriptions (TplA2-MatchCorrectAll,
   TplI-CrossInteractionIter, etc.). 2026-05-20 UI tweaks.

   The two-part fix:
   (a) Override the value-span's nowrap+ellipsis so the text wraps.
       The value-span is a flex child (flex:1) inside a flex button;
       set min-width:0 too — without it, the span won't shrink below
       its content's min-content width and the long text pushes the
       button (and the page) wider, producing a horizontal scrollbar.
   (b) Drop the widget's default max-width:400px AND let its inner
       button/dropdown grow to the container's bound. The container
       itself is the 90%-of-parent cap that the page-layout asks for.
   (c) Switch button + option alignment from align-items:center to
       align-items:flex-start so multi-line wrapped text grows
       downward instead of pushing the icon (arrow) around. */
div.tq-simple-scoring-panel div.tq-simple-scoring-template-select {
    max-width: 90%;
    box-sizing: border-box;
}
div.tq-simple-scoring-panel div.tq-simple-scoring-template-select
    .p-qti-custom-select {
    width: 100%;
    max-width: 100%;
    box-sizing: border-box;
}
div.tq-simple-scoring-panel div.tq-simple-scoring-template-select
    .p-qti-custom-select-button {
    width: 100%;
    max-width: 100%;
    box-sizing: border-box;
    align-items: flex-start;
    height: auto;
}
div.tq-simple-scoring-panel div.tq-simple-scoring-template-select
    .p-qti-custom-select-value {
    white-space: normal;
    overflow: visible;
    text-overflow: clip;
    overflow-wrap: anywhere;
    word-break: break-word;
    min-width: 0;
}
div.tq-simple-scoring-panel div.tq-simple-scoring-template-select
    .p-qti-custom-select-dropdown {
    max-width: 100%;
    box-sizing: border-box;
}

/* Template-picker status line: the long description of the highlighted
   (dropdown open) or selected (dropdown closed) scoring template.
   Reserve a little height so the panel doesn't jump as the text
   appears/changes. #3d3d3d on white is 10.4:1 (AAA). */
div.tq-simple-scoring-panel .tq-sst-status {
    max-width: 90%;
    min-height: 2.4em;
    margin: 4px 0 8px;
    font-size: 0.9em;
    line-height: 1.35;
    color: var(--text-primary);
}
div.tq-simple-scoring-panel div.tq-simple-scoring-template-select
    .p-qti-custom-select-option {
    white-space: normal;
    overflow-wrap: anywhere;
    word-break: break-word;
    align-items: flex-start;
    height: auto;
}

/* Editor pane that renders below the table when an Edit button is
   clicked. Kept inside the panel so the user can scroll vertically
   without the editor pushing content off the right edge. */
div.tq-simple-scoring-editor {
    width: 100%;
    box-sizing: border-box;
    margin-top: 0.5em;
    padding: 0.5em;
    border-top: 1px solid var(--divider);
}

/* Edit-in-place bar inside .tq-simple-scoring-editor: shown when
   the user clicks Edit on an exemplar row. The item shield has
   already been lifted at this point so the user can interact with
   the item; this bar lets them set the score and Save / Cancel. */

div.tq-simple-scoring-edit-bar {
    width: 100%;
    box-sizing: border-box;
    background: var(--bg-secondary);
    border: 1px solid var(--divider);
    border-radius: var(--radius-sm);
    padding: 0.5em;
}

div.tq-simple-scoring-edit-bar p.tq-simple-scoring-edit-intro {
    margin: 0 0 0.5em 0;
    font-size: 0.9em;
    color: var(--text-primary);
}

div.tq-simple-scoring-edit-score-row {
    display: flex;
    align-items: center;
    gap: 0.5em;
    margin-bottom: 0.5em;
}

div.tq-simple-scoring-edit-score-row input.tq-simple-scoring-edit-score-input {
    width: 6em;
}

div.tq-simple-scoring-edit-buttons {
    display: flex;
    gap: 0.5em;
}

/* BR-99: the range editor ("The answer is a number in a range"). */
div.tq-simple-scoring-range-row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5em;
    margin-bottom: 0.5em;
}

div.tq-simple-scoring-range-row input[type="number"] {
    width: 8em;
}

label.tq-simple-scoring-range-include {
    display: inline-flex;
    align-items: center;
    gap: 0.25em;
}

/* ===== Assertion All / None / Any row editor (AssertionDnfEditor) ===== */
.tq-dnf-editor { width: 100%; }
.tq-dnf-grid {
    display: grid;
    grid-template-columns: auto 1fr 1fr 1fr;
    gap: 0.45em;
    align-items: stretch;
}
.tq-dnf-colhead {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.4em;
    font-weight: 600;
    padding: 0.35em 0.5em;
    background-color: var(--accent-fill-hover);   /* white-on-dark: AAA contrast */
    color: var(--text-on-accent);
    border-radius: var(--radius-sm);
}
.tq-dnf-rowgutter {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.25em;
    min-width: 2.6em;
}
.tq-dnf-or { font-weight: 600; color: var(--color-primary); }
.tq-dnf-row-delete,
.tq-dnf-chip-remove {
    background: transparent;
    border: 1px solid var(--accent);
    color: var(--color-primary);
    border-radius: 50%;
    width: 1.4em;
    height: 1.4em;
    padding: 0;
    line-height: 1;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}
.tq-dnf-chip-remove { color: var(--color-primary-dark); }
.tq-dnf-row-delete:hover,
.tq-dnf-chip-remove:hover { background: var(--fill-hover); border-color: var(--status-danger); color: var(--status-danger); }
.tq-dnf-cell {
    border: 1px solid var(--divider);
    border-radius: var(--radius-sm);
    padding: 0.4em;
    min-height: 3em;
    display: flex;
    flex-direction: column;
    gap: 0.4em;
    background: var(--surface);
}
.tq-dnf-cell-tools { display: flex; gap: 0.3em; flex-wrap: wrap; }
.tq-dnf-tool {
    cursor: pointer;
    border: 1px solid var(--divider);
    background: var(--surface);
    border-radius: var(--radius-sm);
    padding: 0.15em 0.45em;
    min-width: 1.9em;
    min-height: 1.9em;
}
.tq-dnf-tool:hover { background: var(--fill-hover); }
.tq-dnf-tool:focus-visible,
.tq-dnf-row-delete:focus-visible,
.tq-dnf-chip-remove:focus-visible,
.tq-dnf-addrow:focus-visible { outline: 3px solid var(--color-primary); outline-offset: 1px; }
.tq-dnf-chips { display: flex; flex-wrap: wrap; gap: 0.3em; }
.tq-dnf-chip {
    display: inline-flex;
    align-items: center;
    gap: 0.3em;
    border: 1px solid var(--color-primary);
    border-radius: var(--radius-lg);
    padding: 0.1em 0.55em 0.1em 0.3em;
    background: var(--accent-tint);
    color: var(--color-primary-dark);
}
.tq-dnf-chip-calc .tq-dnf-chip-label { cursor: pointer; }
.tq-dnf-chip.tq-missing-reference { border-color: var(--status-danger); background: var(--status-danger-tint); color: var(--status-danger); }
.tq-dnf-addrow {
    grid-column: 1 / -1;
    cursor: pointer;
    border: 1px dashed var(--accent);
    background: var(--color-primary-tint);
    border-radius: var(--radius-sm);
    padding: 0.45em;
    font-weight: 600;
    color: var(--color-primary);
}
.tq-dnf-addrow:hover { background: var(--fill-hover); }
.tq-dnf-error {
    grid-column: 1 / -1;
}

/* Visibly-disabled scoring toolbar controls. In test-score mode only Score /
   Test Score / Clear stay enabled; every other control is disabled and must
   read as disabled (not just be unclickable). The dimming carries that; the
   pointer stays the plain arrow — `not-allowed` is drawn by Windows as a red
   circle with a slash, which read as "do not enter" over the parked Close /
   Exit / help controls (bug report #24). Nothing is forbidden; they wait. */
.tq-controls button:disabled {
    opacity: 0.45;
    cursor: default;
}
.tq-scoring-mode-label {
    font-size: 0.72em;
    color: var(--color-text-muted);
    white-space: nowrap;
}

.tq-scoring-mode-dropdown.tq-disabled,
.tq-show-intermediates-label.tq-disabled {
    opacity: 0.45;
    pointer-events: none;
}

/* Virtual-entity name prompt (ItemShield) + shared small-dialog bits */
.tq-ve-name-dialog .tq-ve-name-input {
    width: 100%;
    box-sizing: border-box;
    padding: 0.35em;
    margin: 0.3em 0;
}
.tq-dialog-label { font-weight: 600; display: block; margin-top: 0.4em; }
.tq-dialog-error { color: var(--status-danger); min-height: 1.2em; }

/* Assertion VE picker (buildVeList, AssertionLogicWidget.js): the empty-state
   note and the automatic (implicit) rows that cannot be linked. Shown, not
   hidden, so an author who renamed the response's automatic entry sees why
   it is not offered (bug report #17). */
.tq-ve-list-empty {
    margin: 0 0 0.4em 0;
    max-width: 28em;
    color: var(--color-text-base);
}
.tq-ve-row-automatic {
    color: var(--color-text-muted);
}
.tq-ve-row-automatic .tq-ve-automatic-note {
    display: block;
    margin-left: 1.6em;
    max-width: 28em;
    font-size: 0.85em;
}

/* Loading overlay (publication state load, etc.) */
.mt-load-overlay {
    position: fixed;
    inset: 0;
    background: var(--scrim);
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 10000;
}
.mt-load-box {
    background: var(--surface);
    padding: 1.5em 2em;
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-2);
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 1em;
}
.mt-load-spinner {
    width: 2.5em;
    height: 2.5em;
    border: 4px solid var(--divider);
    border-top-color: var(--accent);
    border-radius: 50%;
    animation: mt-load-spin 0.8s linear infinite;
}
@keyframes mt-load-spin {
    to { transform: rotate(360deg); }
}
.mt-load-label {
    font-size: 0.95em;
    color: var(--text-primary);
}

/* ── VE context-menu (ItemShield interaction click) ──────────────── */
.tq-ve-context-menu {
    background: var(--surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-2);
    overflow: hidden;
    min-width: 180px;
    padding: 0;
}

.tq-ve-context-menu::before {
    content: attr(data-title);
    display: block;
    color: var(--color-text-muted);
    font-weight: 600;
    font-size: 0.75em;
    padding: 7px 14px 5px;
    border-bottom: 1px solid var(--color-border);
    pointer-events: none;
    user-select: none;
}

.tq-ve-context-menu .menu_menu {
    border: none;
    border-bottom: 1px solid var(--color-border);
    text-align: left;
    padding: 9px 14px;
    color: var(--color-text-base);
    font-style: normal;
    font-size: 0.9em;
    cursor: pointer;
    transition: background 0.1s;
}

.tq-ve-context-menu .menu_menu:last-child {
    border-bottom: none;
}

.tq-ve-context-menu .menu_menu:hover,
.tq-ve-context-menu .menu_active {
    background: var(--color-primary-tint);
    color: var(--color-primary-dark);
    font-style: normal;
}

/* ==========================================================================
   Set Construction view (sc- prefix)
   Collapsible left construction panel + right assembled-set preview.
   The collapse mechanism reuses the global .tq-side-panel / .tq-panel-*
   rules; everything below is self-contained so the view doesn't depend on
   the DISView-scoped scoring styles.
   ========================================================================== */

/* Two-pane work area: fixed-width side panel + flexible preview pane. */
.sc-workarea {
    display: flex;
    width: 100%;
    align-items: stretch;
    gap: 8px;
    min-height: 78vh;
}

.sc-workarea > .tq-full-width {
    flex: 1 1 0;
    min-width: 0;
    width: auto;
}

/* Right-hand assembled-set preview — the sole scroll container. */
.sc-preview {
    height: 80vh;
    overflow: auto;
    padding: 1em;
    box-sizing: border-box;
    border: 1px solid var(--divider);
    border-radius: var(--radius-sm);
}

/* Passage name heading at the top of the construction panel. */
.sc-passage-title {
    margin: 8px 6px;
    font-size: 1.1em;
    color: var(--text-primary);            /* >7:1 on white (AAA) */
    overflow-wrap: anywhere;
}

.sc-accordion-host {
    margin-top: 8px;
}

/* Membership checkbox list. */
ul.sc-member-list {
    list-style: none;
    margin: 0;
    padding: 0;
}

/* Note shown in the membership block when the passage has no
   associated items yet (an empty block would read as broken). */
p.sc-member-empty {
    margin: 4px 2px;
    font-style: italic;
    color: var(--text-primary);            /* AAA contrast */
}

li.sc-member-row {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 4px 2px;
}

li.sc-member-row input[type="checkbox"] {
    width: 18px;
    height: 18px;
    flex-shrink: 0;
    cursor: pointer;
}

li.sc-member-row input[type="checkbox"]:focus-visible {
    outline: 3px solid var(--color-primary);
    outline-offset: 2px;
}

label.sc-member-label {
    cursor: pointer;
    color: var(--text-primary);            /* AAA contrast */
    overflow-wrap: anywhere;
}

/* Reorder-only mode for the order list: membership is driven by the
   checkboxes, so suppress the ReorderableList's own add / edit / delete
   affordances (drag + keyboard reorder remain). */
.tq-reorder-only .tq_edit,
.tq-reorder-only .tq_delete,
.tq-reorder-only .tq-big-add-btn,
.tq-reorder-only .tq-center-span {
    display: none !important;
}

/* ---- Tracked editorial suggestions (tq-ins / tq-del) ----
   Rendered only inside a tracked Editorial Review or a Post-Editorial Content
   Review; ItemTransformer strips both markers before the item is delivered or
   exported, so these styles never reach a student.

   WCAG AAA: meaning is never carried by colour alone. An insertion is underlined
   and a deletion is struck through, so the distinction survives greyscale, and
   both colours are >= 7:1 on white. The ::after label is decorative (aria-hidden
   via CSS content is not exposed as text to AT); the Changes panel is the
   accessible surface, and each marker carries an accessible name there. */
tq-ins,
tq-del {
    border-radius: 2px;
    padding: 0 1px;
}

tq-ins {
    color: #0b5c2e;                 /* 7.4:1 on white */
    background-color: #e6f4ea;
    text-decoration: underline;
    text-decoration-thickness: 2px;
}

tq-del {
    color: #8a1c1c;                 /* 7.1:1 on white */
    background-color: #fdeaea;
    text-decoration: line-through;
    text-decoration-thickness: 2px;
}

/* An insertion or deletion that wraps an embed (image, equation, interaction)
   cannot show a text decoration, so it gets a visible border instead — again,
   shape not colour. */
tq-ins:has(img, figure, iframe, math, .tq-image-embed),
tq-del:has(img, figure, iframe, math, .tq-image-embed) {
    display: inline-block;
    border: 3px solid currentColor;
    text-decoration: none;
}

tq-del:has(img, figure, iframe, math, .tq-image-embed) {
    border-style: dashed;
}

/* ---- Changes summary bar + in-place resolve popover (Post-Editorial Content Review) ----
   Per-change accept/reject is done IN THE ITEM via the popover; this slim sticky bar carries the
   outstanding count (which gates completion), the bulk actions, and the keyboard walk. Meaning is
   never carried by colour alone: in the popover an addition is underlined and a removal struck
   through, each also labelled in words. */
.tq-changes-panel {
    position: sticky;
    top: 0;
    z-index: 5;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.4rem 0.75rem;
    padding: 0.5rem 0.75rem;
    margin: 0 0 0.5rem 0;
}

.tq-changes-heading {
    margin: 0;                 /* AAA */
}

.tq-changes-count {
    margin: 0;
    margin-right: auto;             /* push the bulk actions to the far end of the bar */
    font-weight: 600;
    color: var(--text-primary);                 /* AAA — this is the number that gates completion */
}

.tq-changes-nav,
.tq-changes-actions {
    display: flex;
    gap: 0.4rem;
    flex-wrap: wrap;
}

/* Clickable-suggestion affordance — only in the RESOLVING editor, never the read-only suggesting
   review. The marker's own styling still distinguishes ins/del/comment; this only signals that it
   can be acted on. */
.tq-resolving tq-ins,
.tq-resolving tq-del,
.tq-resolving tq-comment {
    cursor: pointer;
}
.tq-resolving tq-ins:hover,
.tq-resolving tq-del:hover,
.tq-resolving tq-comment:hover {
    outline: 2px solid #1a1a1a;
    outline-offset: 1px;
}

/* The in-place resolve popover: click a suggestion → Accept / Reject (or Dismiss, for a comment).
   Above the table's row/column pills (.tq-table-controls, z-index 2000), which otherwise drew
   over it when a suggestion sat in a table cell. */
.tq-change-popover {
    position: absolute;
    z-index: 2100;
    max-width: 22rem;
    padding: 0.6rem 0.7rem;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md, 6px);
    background-color: var(--surface);
    box-shadow: var(--shadow-2);
}

.tq-change-popover-kind {
    font-weight: 600;
    font-size: 0.8125rem;
    color: var(--text-primary);                 /* AAA */
    margin-bottom: 0.25rem;
}

.tq-change-popover-text {
    color: var(--text-primary);
    overflow-wrap: anywhere;
    max-height: 6rem;
    overflow-y: auto;
    margin-bottom: 0.5rem;
}

.tq-change-popover-text--insert {
    text-decoration: underline;
    text-decoration-thickness: 2px;
}

.tq-change-popover-text--delete {
    text-decoration: line-through;
    text-decoration-thickness: 2px;
}

.tq-change-popover-actions {
    display: flex;
    gap: 0.375rem;
    flex-wrap: wrap;
}

/* "Suggestions in this interaction" — the strip the resolving review puts at the top of an
   interaction's template (InteractionResolveController.decorateTemplate). One row per suggestion,
   the one Next edit landed on highlighted, each with its Accept / Reject (Dismiss for a comment). */
.tq-template-changes {
    margin: 0 0 0.75rem 0;
    padding: 0.5rem 0.75rem;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md, 6px);
    background-color: var(--bg-secondary);
}

.tq-template-changes-heading {
    margin: 0 0 0.375rem 0;                 /* AAA */
}

.tq-template-changes-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 0.375rem;
}

.tq-template-change {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.375rem 0.75rem;
    padding: 0.375rem 0.5rem;
    border: 1px solid transparent;
    border-radius: var(--radius-md, 6px);
}

.tq-template-change--current {
    border-color: var(--control-border);
    background-color: var(--surface);
}

.tq-template-change-kind,
.tq-template-change-where {
    font-weight: 600;
    font-size: 0.8125rem;
    color: var(--text-primary);                 /* AAA */
}

.tq-template-change-text {
    color: var(--text-primary);
    overflow-wrap: anywhere;
    margin-right: auto;             /* push the buttons to the far end of the row */
}

.tq-template-change-text--insert {
    text-decoration: underline;
    text-decoration-thickness: 2px;
}

.tq-template-change-text--delete {
    text-decoration: line-through;
    text-decoration-thickness: 2px;
}

.tq-template-change-actions {
    display: flex;
    gap: 0.375rem;
    flex-wrap: wrap;
}

/* A suggestion decided in this sitting: it stays in the strip, dashed and quieter, with its
   outcome in words ("Kept", "Removed" ...) and an Undo, so a mis-click can be corrected. */
.tq-template-change--resolved {
    border-style: dashed;
    border-color: var(--control-border);          /* 3:1 non-text contrast on the sunken surface */
}

.tq-template-change-outcome {
    font-weight: 600;
    font-size: 0.8125rem;
    color: var(--text-primary);                 /* AAA */
}

/* The strip's polite status line (a decision or an undo is announced). Never display:none —
   a hidden live region is not announced; an empty paragraph takes no height anyway. */
.tq-template-changes-status {
    margin: 0;
    font-size: 0.8125rem;
    color: var(--text-primary);                 /* AAA */
}

/* The marker the strip is talking about, inside the template's option preview. */
.tq-change-current {
    outline: 2px solid var(--focus-ring);
    outline-offset: 1px;
}

/* Screen-reader-only live region. */
.tq-visually-hidden {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
    border: 0;
}

/* Tracked editorial suggestions — the markers a Tracked Editorial Review produces, whether
   created surgically over the rendered view (TrackedSuggestReviewView) or by the Quill blots
   (TrackedChangeBlots.js).
   SHADOW NOTE (keep in sync): in shadow-rendered items the live copies of
   the tq-ins/tq-del/tq-comment marker rules ride in
   MarkupItemRenderer.present's extra sheet (the .tq-resolving affordance
   becomes :host(.tq-resolving) there — the resolving view toggles the
   class on each [data-shadow-item] host). These page rules remain for the
   Quill blots. Colour is reinforcement only; the strike / underline carries the
   meaning, so colour-blind and forced-colours users still read it. Contrast targets AAA (7:1). */
tq-ins, .tq-stand-in[data-tq-type="ins"] {
    text-decoration: underline;
    text-decoration-thickness: 2px;
    color: #0a5c2a;
    text-decoration-color: #0a5c2a;
}
tq-del, .tq-stand-in[data-tq-type="del"] {
    text-decoration: line-through;
    text-decoration-thickness: 2px;
    color: #8a1c10;
    text-decoration-color: #8a1c10;
}
/* The comment highlight must WIN against author-styled content in the
   commented range (Word-pasted background-colored spans — hit live in a
   rubric table, where the comment was invisible and findable only by
   clicking). Quill merges inline formatting onto the fewest elements, so
   the author's inline background-color can land in EITHER place:
     - on the tq-comment element ITSELF (style attr beats a stylesheet rule
       — hence the !important on the marker's own background), or
     - on a child span inside the marker (hence the transparent override).
   Neither touches the stored content: resolving unwraps the marker and the
   author styling returns untouched. */
tq-comment, .tq-stand-in[data-tq-type="comment"] {
    background-color: #fff3cd !important;
    border-bottom: 2px dotted #7a5b00;
    cursor: pointer;
}
tq-comment [style*="background"],
.tq-stand-in[data-tq-type="comment"] [style*="background"] {
    background-color: transparent !important;
}
/* A comment wrapping a PICTURE was invisible, and that is why one "seemed to
   disappear" (owner report, 2026-09-11). The highlight paints BEHIND the
   content, an opaque image hides it completely, and the marker's inline box is
   one text line tall — measured on a choice option, a 120x80 image inside a
   120x17 marker, with the dotted underline behind the image too. The comment
   was attached the whole time; nothing showed it.

   So for a marker that wraps replaced content, draw the mark AROUND it rather
   than behind it: a box of its own, a FRAME, and the speech-balloon glyph in a
   gutter beside the picture.

   The first version of this used a dotted outline and a small trailing glyph,
   and the owner's verdict was "barely visible" (2026-09-11, second round): a
   dotted ring reads as chrome against a photograph, and a 0.9em glyph after the
   image is lost in the line. What replaces it:

     - a SOLID 3px frame in the comment ink, which reads at a glance and, being
       a border rather than an outline, survives forced-colours mode as a
       system colour;
     - the amber the highlight already uses, now VISIBLE because the padding
       puts it beside the picture instead of behind it;
     - the balloon in that left gutter — never over the picture (a reviewer must
       still see what they are commenting on), never outside the box (an
       ancestor with overflow:hidden would clip it), and vertically centred so a
       tall image does not strand it.

   Text comments keep the highlight they have — a frame on a run that wraps
   across lines would be busier than the highlight it replaces.

   KEEP IN SYNC with the shadow copy in MarkupItemRenderer.present: items render
   inside shadow roots, where these page rules do not reach. The graphic rules
   were missing from that sheet entirely until 2026-09-11, which is why the mark
   was fainter on the item surfaces than in the Quill body editor. */
tq-comment:has(img, svg, video, iframe, object, canvas, figure, picture),
.tq-stand-in[data-tq-type="comment"]:has(img, svg, video, iframe, object, canvas, figure, picture) {
    display: inline-block;
    position: relative;
    background-color: #fff3cd !important;
    border: 3px solid #7a5b00;
    border-radius: 3px;
    padding: 3px 3px 3px 22px;
    outline: none;
}

tq-comment:has(img, svg, video, iframe, object, canvas, figure, picture)::after,
.tq-stand-in[data-tq-type="comment"]:has(img, svg, video, iframe, object, canvas, figure, picture)::after {
    content: "💬";
    position: absolute;
    left: 2px;
    top: 50%;
    transform: translateY(-50%);
    font-size: 1.1rem;
    line-height: 1;
}

/* A POINT comment has no wrapped text — it is an empty anchor shown as a speech-balloon glyph.
   The glyph is CSS ::before (not real DOM), so unwrapping the marker changes no content. */
tq-comment.tq-point-comment {
    display: inline-block;
    background: none;
    border: none;
    vertical-align: text-bottom;
}
tq-comment.tq-point-comment::before {
    content: "\1F4AC";
    font-size: 0.9em;
}
/* The read-only suggesting surface: text is selectable (that is how you suggest), but the
   rendered content is not itself editable. */
.tsr-display-area {
    user-select: text;
}
.tsr-suggest-bar {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.25rem 0;
}
/* Live count of suggestions + comments on the entry (mirrors .tq-changes-count on the
   Post-Editorial bar — same completion stakes, so the same weight and AAA ink). */
.tsr-suggestion-count {
    margin-left: auto;
    font-weight: 600;
    color: var(--text-primary);                 /* AAA */
}

/* ===== Media interaction template panel (MediaInteractionTemplate.js) =====
   The one panel this dialog adds to the standard template: the audio-or-video
   choice, the file currently attached, and the two ways of attaching one. Laid
   out to match div.tq-attributes above, which is the surface it sits under. */
.tq-media-panel {
    padding: 12px 16px;
    margin-bottom: 16px;
}

.tq-media-heading {
    margin: 0 0 8px 0;
}

.tq-media-row,
.tq-media-actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 12px;
    margin-bottom: 8px;
}

.tq-media-current {
    margin: 8px 0;
}

.tq-media-current audio,
.tq-media-current video {
    max-width: 100%;
}

.tq-media-empty {
    color: var(--text-secondary);                 /* AAA on the panel's surface */
    font-style: italic;
}

.tq-media-status {
    font-size: 0.9em;
    min-height: 1.2em;
}

/* ── Item set panel ────────────────────────────────────────────────────────
   The other items on this item's stimulus, with where each one stands: an
   accordion at the TOP OF THE LEFT SIDEBAR, above the passage itself, holding a
   two-column Table2D (owner, 2026-09-11). Hidden entirely when the item has no
   set. See Documents/ItemSetBottleneckPlan.md. */

.tq-item-set-panel {
    font-size: 0.85em;
    line-height: 1.5;
    border-bottom: 1px solid var(--color-border);
    background-color: var(--bg-secondary);
}

/* AccordionGroup sizes ITSELF to the view's height — a ResizeObserver writes an
   inline height and .AccGroup_window is height:100%/overflow:auto. In a 320px
   sidebar that would turn a two-row table into a full-height scrolling box, so
   here it flows with the content instead (the documented override). */
.tq-item-set-panel div.AccGroup_window {
    height: auto !important;
    overflow: visible;
}

.tq-item-set-panel div.AccGroup_window div.AccBlock_body {
    border: none;
    margin: 0;
}

.tq-item-set-panel .Table2D_titletext {
    font-size: 0.95rem;
    font-weight: 600;
}

/* The roster table has a narrow column to live in: let it use the width it has
   and scroll sideways only if a name is genuinely too long for it. */
.tq-item-set-panel .Table2D_window {
    width: 100%;
}

.tq-item-set-panel .AccBlock_body {
    overflow-x: auto;
}

/* The item cell is the switch control — a String cell carrying a click payload,
   so the widget renders it as a plain div. It reads as a control. */
.tq-item-set-panel td div {
    cursor: pointer;
    color: var(--color-primary-dark);
    text-decoration: underline;
}

/* ── The set-member dialog ─────────────────────────────────────────────────
   One member of the set, rendered read-only so the user can look before
   deciding (owner, 2026-09-11). Wider than the stock dialog because it holds a
   real item; the same modifier shape the work queue's dialog uses. */
.Dialog_normal.tq-set-member-box {
    max-width: 70vw;
}

/* The rendered item is the only thing that scrolls. That is achieved by making
   the content column SHRINK inside the box (flex + min-height:0), never by
   clamping the box itself: WAF's .Dialog_normal owns overflow-y:auto, and a
   Ments rule that overrode it is exactly how bug #10 shipped — content painted
   outside the white box, unreachable. So the box keeps its safety net and
   simply never has anything to scroll (owner, 2026-09-11;
   Scripts/__tests__/WafDialogScrolling.test.js pins the rule I tried to break). */

/* This dialog has no WAF widgets, so its .Dialog_body is empty — but WAF gives
   that box `flex: 1` and `overflow-y: auto`, so an empty grid sat between the
   title and the item taking 44px of the dialog and carrying a scroll context of
   its own. Nothing renders there; take it out of the layout entirely. */
.tq-set-member-box .Dialog_body {
    display: none;
}

.tq-set-member-dialog {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-height: 0;
    overflow: hidden;
    padding: 12px 20px 16px;
    gap: 10px;
}

.tq-set-member-status {
    color: var(--text-secondary);                 /* AAA on white */
    font-size: 0.9em;
}

/* The rendered item brings its OWN scrollers: PaldroeStyles.css gives
   div.p-qti-stimulus and div.p-qti-item-container `height: calc(100vh - 40px);
   overflow: auto` — sized to the VIEWPORT. Inside a dialog that is already
   shorter than the viewport those panes always overflow their host, so the
   host scrolled too and the user got a second, outer scrollbar (owner,
   2026-09-11). Here the panes take the height the DIALOG gives them and remain
   the only things that scroll — which is right for a split passage/item view,
   where each pane wants to scroll on its own. */
.tq-set-member-render {
    flex: 1 1 auto;
    min-height: 0;
    overflow: auto;
    padding: 12px;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md, 8px);
}

/* Those panes are sized to the VIEWPORT and scroll themselves, which inside a
   shorter dialog meant the host scrolled as well — two bars for one item. Here
   they simply flow, and the host is the single scroller. A preview scrolls as
   one document; independent pane scrolling is for the full-screen delivery
   layout those rules were written for. */
.tq-set-member-render div.p-qti-stimulus,
.tq-set-member-render div.p-qti-item-container {
    height: auto;
    max-height: none;
    overflow: visible;
}

.tq-set-member-problem {
    margin: 0;
    color: var(--text-secondary);
}

.tq-set-member-footer {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 10px;
}

/* Why there is no switch button, beside the one that closes. */
.tq-set-member-note {
    margin-right: auto;
    color: var(--text-secondary);
    font-size: 0.9em;
}

/* Said when the set could not be read. */
.tq-item-set-row {
    padding: 4px 8px;
    color: var(--text-secondary);                 /* AAA on the sunken surface */
}

/* The work queue's item-set cell: the stimulus a row is written against, then
   how many of its set are still at this step. */
.wq-set-progress {
    color: var(--text-secondary);                 /* AAA on the table surface */
    font-size: 0.9em;
    white-space: nowrap;
}

/* ── The author's set drafting picker ─────────────────────────────────────
   The stimuli ready to be written against, each with the items so far.
   See Documents/ItemSetBottleneckPlan.md. */

.tq-set-draft-picker {
    padding: 16px;
    max-width: 900px;
}

.tq-set-draft-heading {
    font-weight: 600;
    font-size: 1.1em;
    margin-bottom: 10px;
    color: var(--text-primary);
}

.tq-set-draft-row {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 8px 10px;
    border-bottom: 1px solid var(--color-border);
}

.tq-set-draft-name {
    flex: 1 1 auto;
    font-weight: 600;
    color: var(--text-primary);
}

.tq-set-draft-count {
    color: var(--text-secondary);                 /* AAA on the page surface */
    white-space: nowrap;
}

.tq-set-draft-empty {
    color: var(--text-secondary);
    font-style: italic;
    padding: 8px 0;
}

/* The media panel's state line: what is attached and where it came from, and
   the failure note when the browser cannot load it. A bare player says none of
   this, which read to the first author who used it as "nothing is there". */
.tq-media-caption {
    font-size: 0.9em;
    color: var(--text-secondary);                 /* AAA on the panel's surface */
    margin-top: 4px;
}
.tq-media-failed {
    font-size: 0.9em;
    color: var(--status-danger);                 /* AAA; matches the app's error ink */
    margin-top: 4px;
}
.tq-media-revise {
    margin-top: 6px;
}

/* ── What's New (Documents/WhatsNewPlan.md) ─────────────────────────────
   The release note shown once after a release. Deliberately plain: it is
   reading matter, not a screen. Width is capped for line length rather than
   filling the dialog, and the body scrolls inside WAF's own dialog box — a
   long note must never push its dismiss button off the bottom, which is the
   shape that makes a dialog unusable on a short screen. */
.mt-whats-new {
    max-width: 46em;
}

.mt-whats-new-date {
    margin: 0 0 1em 0;
    color: var(--text-secondary);
    font-size: 0.9em;
}

.mt-whats-new-body {
    /* Cap the reading area, not the dialog: the box already scrolls, and this
       keeps a long release from becoming an endless page. */
    max-height: 60vh;
    overflow-y: auto;
    padding-right: 0.6em;
    line-height: 1.5;
}

.mt-whats-new-body h4 {
    margin: 1.2em 0 0.4em 0;
    color: var(--purpleText);
}

.mt-whats-new-body h4:first-child {
    margin-top: 0;
}

.mt-whats-new-body p,
.mt-whats-new-body li {
    margin: 0.4em 0;
}

.mt-whats-new-body ul {
    padding-left: 1.3em;
}

/* The What's New tab on Help & Training: the same notes the popup shows, kept
   readable after they have been dismissed. The dates down the left, the one
   you pick on the right — only the newest note is ever shown as a popup, so
   every earlier one is something you come here to FIND, and a list of dates is
   how you find it. Wraps to one column when the row will not fit rather than
   at a breakpoint: this stylesheet carries no media queries. */
.ht-whats-new {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    gap: 0.8em 2em;
    padding: 0.5em 0;
}

.ht-whats-new-list {
    flex: 0 0 10em;
}

.ht-whats-new-list ul {
    list-style: none;
    margin: 0;
    padding: 0;
}

button.ht-whats-new-pick {
    display: block;
    width: 100%;
    background: none;
    border: none;
    border-left: 3px solid transparent;
    padding: 0.4em 0.6em;
    font-size: 1em;
    text-align: left;
    color: var(--color-primary-dark);
    cursor: pointer;
}

button.ht-whats-new-pick:hover {
    background-color: var(--fill-hover);
}

/* The one being read. Marked by weight AND a bar, never by colour alone. */
button.ht-whats-new-pick[aria-current="true"] {
    border-left-color: var(--color-primary-dark);
    background-color: var(--bg-secondary);
    font-weight: 600;
}

button.ht-whats-new-pick:focus-visible {
    outline: 2px solid var(--color-primary-dark);
    outline-offset: 2px;
}

/* Keeps the reading measure the row no longer imposes. min-width lets it
   shrink before the row wraps, instead of pushing the list off the side. */
.ht-whats-new-pane {
    flex: 1 1 24em;
    min-width: 0;
    max-width: 46em;
}

.ht-whats-new-date {
    margin: 0 0 0.6em 0;
    color: var(--text-secondary);
    font-size: 0.95em;
    font-weight: 600;
}

/* Focused only when a reader picks a date, so the note they asked for is read
   out and the keyboard lands in it. It is a heading, not a control: no ring. */
.ht-whats-new-date:focus {
    outline: none;
}

/* Inside the tab the body is the whole page, so it must NOT take the popup's
   height cap — that cap exists to keep a dialog's dismiss button reachable,
   and there is no button here. */
.ht-whats-new .mt-whats-new-body {
    max-height: none;
    overflow-y: visible;
    padding-right: 0;
}

/* The only child of the row when nothing has been announced: it takes the
   whole width so the sentence is not squeezed into a list-width column. */
.ht-whats-new-empty {
    flex: 1 1 100%;
    max-width: 46em;
    color: var(--text-secondary);
}

/* ========== UNDO / REDO (BR-56, BR-59) ========== */
/* Quill gives a toolbar button no disabled appearance of its own, and these two
   are the only buttons here that go inert — they are disabled whenever there is
   nothing left to undo or redo, so that the pair says whether pressing them
   would do anything. Dimming only: the button keeps its size, so nothing in a
   wrapping, sticky toolbar moves when the state flips. */
.ql-toolbar.ql-snow button.ql-undo:disabled,
.ql-toolbar.ql-snow button.ql-redo:disabled {
    opacity: 0.35;
    cursor: default;
}

/* Quill's hover rule colours the strokes on every button; suppress it on the
   two that are doing nothing, or a dead button still lights up under the
   pointer and reads as available. */
.ql-toolbar.ql-snow button.ql-undo:disabled:hover .ql-stroke,
.ql-toolbar.ql-snow button.ql-redo:disabled:hover .ql-stroke {
    stroke: #444;
}

.ql-toolbar.ql-snow button.ql-undo:disabled:hover .ql-fill,
.ql-toolbar.ql-snow button.ql-redo:disabled:hover .ql-fill {
    fill: #444;
}

/* ===================== Rights & permissions (S2b) =====================
   The copyright request slot (CopyrightSlot.js), its chip, the credit line
   it becomes when approved, the request dialog and the rights panel. */

/* The toolbar's "Insert permission request" button: a © mark. */
div.ql-toolbar.ql-snow.tq-editor-toolbar button.ql-copyright {
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 18 18'%3E%3Ccircle cx='9' cy='9' r='7' fill='none' stroke='%235E00BD' stroke-width='1.6'/%3E%3Cpath d='M11.6 6.9 A3.3 3.3 0 1 0 11.6 11.1' fill='none' stroke='%235E00BD' stroke-width='1.6' stroke-linecap='round'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-size: 22px 22px;
    background-position: center;
}

/* The chip: a real button inside the embed. Colours are >= 7:1 on their
   backgrounds (WCAG AAA). */
span.tq-copyright-slot {
    display: inline;
}
button.tq-copyright-chip {
    display: inline-block;
    margin: 0 2px;
    padding: 2px 8px;
    border: 1px dashed var(--control-border);
    border-radius: var(--radius-lg);
    background: var(--bg-secondary);
    color: var(--text-primary);
    font: inherit;
    font-size: 0.85em;
    line-height: 1.5;
    cursor: pointer;
    vertical-align: baseline;
    text-align: left;
}
button.tq-copyright-chip:hover { background: var(--fill-hover); }
button.tq-copyright-chip:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 1px; }
button.tq-copyright-chip[data-rights-state="denied"],
button.tq-copyright-chip[data-rights-state="expired"] {
    border-color: var(--status-danger);
    background: var(--status-danger-tint);
    color: var(--status-danger);
    text-decoration: line-through;
}
button.tq-copyright-chip[data-rights-state="unlinked"] {
    border-color: var(--status-warning);
    background: var(--status-warning-tint);
    color: var(--status-warning);
}
/* Approved: the credit line itself, in place — no chip chrome, but still
   recognisably a rights slot (cert set #106): a dotted purple underline and
   a small © mark, the toolbar button's colour (>= 7:1 on white). */
button.tq-copyright-chip[data-rights-state="approved"] {
    border: none;
    border-bottom: 1px dotted var(--accent);
    border-radius: 0;
    background: transparent;
    padding: 0 2px;
    font-size: inherit;
    color: var(--text-primary);
    cursor: pointer;
}
button.tq-copyright-chip[data-rights-state="approved"]::before {
    content: "©";
    color: var(--accent);
    font-size: 0.75em;
    vertical-align: super;
    margin-right: 2px;
}
button.tq-copyright-chip[data-rights-state="approved"]:hover { background: var(--fill-hover); }
/* Credit due, not yet written by the specialist: the pending chip, flagged. */
button.tq-copyright-chip[data-rights-state="awaitingcredit"] {
    border-color: var(--status-warning);
    background: var(--status-warning-tint);
    color: var(--status-warning);
}
span.tq-credit-line { font-style: normal; }
span.tq-copyright-slot--selected > button.tq-copyright-chip {
    box-shadow: 0 0 0 3px var(--focus-ring);
}

/* The request dialog: two columns like the asset dialog, wider text. */
/* A set width, so the credit-line fields stay comfortable now that the label
   column no longer takes half; the minimum never exceeds a phone's screen. */
dialog.tq-basic-dialog.tq-copyright-dialog {
    width: min(56rem, 90vw);
    min-width: min(560px, calc(100vw - 2rem));
    max-width: 90vw;
}
dialog.tq-copyright-dialog .tq-dialog-widgets textarea { min-height: 3.5em; }
dialog.tq-copyright-dialog .tq-rights-hint { color: var(--text-secondary); font-weight: normal; }
dialog.tq-copyright-dialog .tq-rights-readonly { padding: 4px 0; color: var(--text-secondary); }

/* The rights panel (shares .ib-attr-panel's docked layout). */
.tq-rights-panel .tq-rights-status:empty { display: none; }
.tq-rights-panel .tq-rights-message {
    margin: 0 0 8px 0;
}
.tq-rights-panel .tq-rights-declaration-row { margin: 0 0 6px 0; font-size: 0.9em; }
.tq-rights-panel .tq-rights-declaration-name { font-weight: 600; }
.tq-rights-panel .tq-rights-link {
    margin-left: 8px;
    border: none;
    background: none;
    color: var(--accent);
    text-decoration: underline;
    cursor: pointer;
    font: inherit;
    padding: 0;
}
.tq-rights-panel .tq-rights-empty { color: var(--text-primary); font-size: 0.9em; }
.tq-rights-panel .tq-rights-actions { display: flex; gap: 8px; align-items: center; margin-top: 8px; }
.tq-rights-panel .tq-rights-selected { font-weight: 600; margin-right: 8px; }

/* BasicDialog (Scripts/Widgets/BasicDialog.js) — the Insert table dialog, the
 * interaction / attribute help, the image alt-text and request dialogs …
 * They had no rule of their own and rendered as the browser's bare <dialog>:
 * a black frame, a 2em serif h1 title and native buttons (cert set 2026-10-01
 * item 12). Same chrome as .app-dialog (styles.css), without its fixed max
 * width, which the larger BasicDialogs (help editor, copyright) override. */
dialog.tq-basic-dialog {
    /* Never wider than a phone's screen (reflow at 320px). */
    min-width: min(340px, calc(100vw - 2rem));
    max-width: min(90vw, 56rem);
    box-sizing: border-box;
    font-size: 1rem;
    line-height: 1.5;
}
dialog.tq-basic-dialog::backdrop {
    background: rgba(15, 23, 42, 0.55);
}
/* Label | control. The label column takes its text's width, up to 16em, and
 * the control column the rest. With the generic 1fr 1fr, a wide control (the
 * rich request editor) took the whole dialog: the labels, free to break
 * anywhere, were left one or two letters wide and the editor ran past the
 * dialog's right edge (report 104, the Insert asset dialog). */
dialog.tq-basic-dialog > .tq-dialog-widgets {
    grid-template-columns: fit-content(16em) minmax(0, 1fr);
    gap: 10px 16px;
    align-items: center;
    margin-bottom: 20px;
}
/* The shared rows that are neither a label nor a control (the alt text's
 * Decorative box and hint, the note on why the AI artist is not offered) span
 * both columns. In one cell they pushed every later label out of line with
 * its control. */
dialog.tq-basic-dialog > .tq-dialog-widgets > .tq-alt-decorative,
dialog.tq-basic-dialog > .tq-dialog-widgets > .tq-ai-offer-note,
dialog.tq-basic-dialog > .tq-dialog-widgets > .tq-dialog-hint {
    grid-column: 1 / -1;
}
/* A control added with no label (a reject reason) takes the whole row, rather
 * than sitting indented behind an empty label cell. */
dialog.tq-basic-dialog > .tq-dialog-widgets > label:empty {
    display: none;
}
dialog.tq-basic-dialog > .tq-dialog-widgets > label:empty + * {
    grid-column: 1 / -1;
}
/* A tall control (the rich editor, a text area, a list) is labelled at its
 * top, where its first line is, not beside its middle. */
dialog.tq-basic-dialog > .tq-dialog-widgets > label:has(+ .tq-rich-note-host),
dialog.tq-basic-dialog > .tq-dialog-widgets > label:has(+ textarea),
dialog.tq-basic-dialog > .tq-dialog-widgets > label:has(+ select[multiple]),
dialog.tq-basic-dialog > .tq-dialog-widgets > label:has(+ [role="listbox"]),
dialog.tq-basic-dialog > .tq-dialog-widgets > label:has(+ .tq-reorderable-list),
dialog.tq-basic-dialog > .tq-dialog-widgets > label:has(+ .tq-ve-list) {
    align-self: start;
}
@media (max-width: 480px) {
    dialog.tq-basic-dialog > .tq-dialog-widgets {
        grid-template-columns: minmax(0, 1fr);
    }
}
dialog.tq-basic-dialog > .tq-dialog-widgets > input[type="checkbox"] {
    justify-self: start;
}
/* The grid's gap spaces the rows. The site-wide 15px under every input sat a
 * text field above the middle of its row, out of line with its label. */
dialog.tq-basic-dialog > .tq-dialog-widgets > input:not([type="checkbox"]):not([type="radio"]) {
    margin-bottom: 0;
}
/* Help text: one column, the text then its video button. */
dialog.tq-basic-dialog.tq-help-dialog > .tq-dialog-widgets {
    display: flex;
    flex-direction: column;
    align-items: stretch;
}
dialog.tq-basic-dialog.tq-help-dialog {
    width: min(90vw, 44rem);
}

/* The graphic editor's "New hotspot" dialog (HotspotDlg.js; cert set
 * 2026-10-01 #56): the shape choice, then the identifier with its label
 * ABOVE it (the label used to sit under the input). */
dialog.tq-basic-dialog.tq-hotspot-dialog > .tq-dialog-widgets {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 14px;
}
dialog.tq-hotspot-dialog fieldset {
    border: 1px solid var(--divider);
    border-radius: var(--radius-md);
    margin: 0;
    padding: 6px 12px 10px 12px;
    display: flex;
    flex-wrap: wrap;
    gap: 6px 18px;
    align-items: center;
}
dialog.tq-hotspot-dialog fieldset > legend {
    padding: 0 4px;
}
dialog.tq-hotspot-dialog .tq-hotspot-shape-option {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    color: var(--jcmaPurple);
    cursor: pointer;
}
dialog.tq-hotspot-dialog .tq-hotspot-identifier-row {
    display: flex;
    flex-direction: column;
    gap: 4px;
}

/* Cert-set bug 13: the external-scoring panel's maximum score field. */
div.tq-external-scoring-panel div.tq-external-max-score {
    margin: 0.75em 0;
    overflow-wrap: anywhere;
}
div.tq-external-scoring-panel div.tq-external-max-score label {
    display: block;
    font-weight: 600;
    margin-bottom: 0.25em;
}
div.tq-external-scoring-panel div.tq-external-max-score input[type="number"] {
    max-width: 8em;
    box-sizing: border-box;
}
div.tq-external-scoring-panel div.tq-external-max-score-hint {
    margin-top: 0.25em;
    font-size: 0.9em;
}
