/* CSS Variables
   Palette derived from the Coursetrix Pro logo (deep teal -> green) rather than
   a stock blue. Neutrals are tinted very slightly toward teal so they read as
   chosen rather than inherited. */
:root {
    --primary-color: #1a7f8e;
    --primary-hover: #146976;
    --brand-deep: #0f4c5c;
    --brand-green: #4f9d5b;
    --secondary-color: #5b7075;
    --secondary-hover: #445559;
    --success-color: #2f8f5b;
    --danger-color: #dc2626;
    --danger-hover: #b91c1c;
    --warning-color: #a9701a;
    --background: #edf2f1;
    --panel-bg: #ffffff;
    --surface-soft: #f6faf9;
    --surface-sunk: #e7eeed;
    --border-color: #dae5e3;
    --border-soft: #e8efee;
    --text-primary: #0e2a2f;
    --text-secondary: #4a6068;
    --text-muted: #7c939a;
    --accent-teal: #199eb3;
    --accent-teal-hover: #157e8f;
    /* State washes, reserved for outcome coverage, never decoration */
    --wash-brand: #e4efef;
    --wash-good: #e2f1e8;
    --wash-warn: #f7eedc;
}

/* Reset & Base */
* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

body {
    font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;
    background: var(--background);
    color: var(--text-primary);
    line-height: 1.6;
}

/* Layout */
.container {
    max-width: 1200px;
    margin: 0 auto;
    padding: 20px;
}

header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 24px;
    padding-bottom: 16px;
    border-bottom: 1px solid var(--border-color);
}

header h1 {
    font-size: 2.25rem;
    font-weight: 800;
    color: #1e3a8a;
}

.header-branding {
    display: flex;
    align-items: center;
}

.header-logo {
    height: 68px;
    width: auto;
    display: block;
    object-fit: contain;
    cursor: pointer;
    transition: opacity 0.2s ease;
}

.header-logo:hover {
    opacity: 0.8;
}

.header-actions {
    display: flex;
    align-items: center;
    gap: 8px;
}

.hidden {
    display: none !important;
}

.header-group {
    display: flex;
    align-items: center;
    gap: 8px;
}

.account-info {
    display: flex;
    align-items: center;
    gap: 8px;
}

/* Top-level views, exactly one visible at a time (see showView in app.js) */
.view {
    display: flex;
    flex-direction: column;
    gap: 24px;
}

/* Signed-out landing */
.auth-card {
    background: var(--panel-bg);
    border: 1px solid var(--border-color);
    border-radius: 12px;
    box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
    padding: 40px;
    max-width: 460px;
    margin: 48px auto;
    text-align: center;
}

.auth-card h2 {
    margin-bottom: 12px;
}

.auth-actions {
    display: flex;
    flex-direction: column;
    gap: 10px;
    margin: 24px 0 20px;
}

.auth-note {
    color: var(--text-muted);
    font-size: 0.85rem;
    margin: 0;
}

.auth-divider {
    display: flex;
    align-items: center;
    gap: 12px;
    margin: 20px 0;
    color: var(--text-muted);
    font-size: 0.8rem;
}

.auth-divider::before,
.auth-divider::after {
    content: "";
    flex: 1;
    height: 1px;
    background: var(--border-color);
}

.auth-email-form {
    display: flex;
    flex-direction: column;
    gap: 14px;
    text-align: left;
}

.auth-email-form .form-group {
    margin: 0;
}

.auth-submit {
    width: 100%;
}

.auth-error {
    margin: -4px 0 0;
    color: var(--danger-color);
    font-size: 0.85rem;
}

.auth-links {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    flex-wrap: wrap;
    margin: 16px 0 20px;
    font-size: 0.82rem;
    color: var(--text-secondary);
}

.auth-links a {
    color: var(--primary-color);
    text-decoration: none;
    font-weight: 600;
}

.auth-links a:hover {
    text-decoration: underline;
}

/* Autosave indicator in the editor header */
.save-status {
    color: var(--text-muted);
    font-size: 0.8rem;
    min-width: 110px;
    text-align: right;
}

.save-status.error {
    color: #b91c1c;
}

.account-email {
    color: var(--text-muted);
    font-size: 0.85rem;
    max-width: 180px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* ============================================
   DASHBOARD, courses grouped into term shelves
   ============================================ */

.dashboard-course-list {
    display: flex;
    flex-direction: column;
    gap: 28px;
}

/* --- term group --- */
.term-group {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.term-head {
    display: flex;
    align-items: center;
    gap: 12px;
}

.term-label {
    font-size: 0.8rem;
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--text-secondary);
    white-space: nowrap;
}

.term-rule {
    flex: 1;
    height: 1px;
    background: var(--border-color);
}

.term-count {
    font-size: 0.74rem;
    color: var(--text-muted);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.term-shelf {
    display: grid;
    gap: 14px;
    grid-template-columns: repeat(auto-fill, minmax(272px, 1fr));
}

/* --- course card --- */
.course-card {
    background: var(--panel-bg);
    border: 1px solid var(--border-color);
    border-radius: 12px;
    overflow: hidden;
    box-shadow: 0 1px 2px rgba(14, 42, 47, 0.06), 0 1px 3px rgba(14, 42, 47, 0.04);
    display: flex;
    flex-direction: column;
    transition: box-shadow 0.15s ease, transform 0.15s ease;
}

.course-card:hover {
    box-shadow: 0 2px 4px rgba(14, 42, 47, 0.05), 0 8px 20px rgba(14, 42, 47, 0.09);
    transform: translateY(-1px);
}

/* Coloured band. Variant is chosen deterministically from the course id so a
   course keeps the same colour as the list changes around it. */
.course-band {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 8px;
    padding: 13px 14px;
    color: #ffffff;
    background: linear-gradient(135deg, var(--brand-deep), var(--primary-color));
}

.course-band-1 { background: linear-gradient(135deg, var(--primary-color), var(--brand-green)); }
.course-band-2 { background: linear-gradient(135deg, #2c6b74, #55976a); }

.course-band-text {
    flex: 1;
    min-width: 0;
    background: none;
    border: none;
    padding: 0;
    margin: 0;
    font: inherit;
    color: inherit;
    text-align: left;
    cursor: pointer;
}

/* Archived courses can't be opened until unarchived, so their title is inert. */
.course-band-text.is-static {
    cursor: default;
}

.course-code {
    display: block;
    font-size: 0.72rem;
    font-weight: 700;
    letter-spacing: 0.06em;
    opacity: 0.85;
    text-transform: uppercase;
}

/* Clamped to two lines, and reserving both, so every band in a shelf is the
   same height whether the title wraps or not. */
.course-title {
    font-size: 0.95rem;
    font-weight: 650;
    line-height: 1.3;
    letter-spacing: -0.01em;
    min-height: 2.6em;
    overflow: hidden;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
}

.course-band .btn-kebab {
    color: rgba(255, 255, 255, 0.78);
    flex-shrink: 0;
}

.course-band .btn-kebab:hover {
    background: rgba(255, 255, 255, 0.16);
    color: #ffffff;
}

.course-body {
    padding: 12px 14px 14px;
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.course-dates {
    font-size: 0.78rem;
    color: var(--text-muted);
    font-variant-numeric: tabular-nums;
}

/* Module strip: one segment per module, so the term's shape reads at a glance */
.module-strip {
    display: flex;
    gap: 2px;
    height: 5px;
}

.module-strip i {
    flex: 1;
    display: block;
    background: var(--primary-color);
    opacity: 0.3;
    border-radius: 2px;
}

.module-strip i.filled {
    opacity: 0.85;
}

.course-stats {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    font-size: 0.79rem;
    color: var(--text-secondary);
    font-variant-numeric: tabular-nums;
}

.course-stats b {
    font-weight: 650;
    color: var(--text-primary);
}

/* Separator belongs to the item that follows it, so a wrap never leaves a
   dangling "·" at the end of a line. */
.course-stats > span + span::before {
    content: "·";
    margin-right: 10px;
    color: var(--border-color);
}

.course-foot {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    padding-top: 10px;
    border-top: 1px solid var(--border-soft);
}

.course-points {
    font-size: 0.78rem;
    color: var(--text-muted);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.course-points b {
    font-weight: 650;
    color: var(--text-secondary);
}

/* --- pills --- */
.pill {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    font-size: 0.7rem;
    font-weight: 650;
    padding: 2px 9px;
    border-radius: 999px;
    white-space: nowrap;
    align-self: flex-start;
}

.pill .dotmark {
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: currentColor;
}

.pill-good { background: var(--wash-good); color: var(--success-color); }
.pill-warn { background: var(--wash-warn); color: var(--warning-color); }

/* --- dashboard utility links (Archive) --- */
.dashboard-utility-link {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: 0.85rem;
    font-weight: 600;
    color: var(--text-secondary);
    text-decoration: none;
    padding: 9px 4px;
}

.dashboard-utility-link:hover { color: var(--primary-color); }

.archive-count {
    background: var(--surface-sunk);
    color: var(--text-muted);
    border-radius: 999px;
    padding: 1px 8px;
    font-size: 0.72rem;
    font-variant-numeric: tabular-nums;
}

/* Archived cards read as inert/read-only, same idea as .is-static on the title */
#archiveCourseList .course-card { opacity: 0.72; }
#archiveCourseList .course-card:hover { opacity: 1; }

/* --- demo tile (dashboard) --- */
.demo-tile {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    flex-wrap: wrap;
    margin-top: 28px;
    padding: 14px 18px;
    border: 1px dashed var(--border-color);
    border-radius: 12px;
    background: var(--surface-soft);
}

.demo-tile-info {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}

.demo-tile-desc {
    color: var(--text-muted);
    font-size: 0.82rem;
}

.demo-tile-actions {
    display: flex;
    gap: 8px;
    flex-shrink: 0;
}

/* --- demo preview banner (editor) --- */
.demo-preview-banner {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    flex-wrap: wrap;
    margin-bottom: 20px;
    padding: 12px 18px;
    border-radius: 10px;
    background: var(--wash-warn);
    color: var(--warning-color);
    font-size: 0.88rem;
    font-weight: 600;
}

/* --- kebab (shared) --- */
.btn-kebab {
    background: none;
    border: none;
    cursor: pointer;
    font-size: 1.2rem;
    line-height: 1;
    padding: 4px 9px;
    border-radius: 6px;
    color: var(--text-secondary);
}

.btn-kebab:hover {
    background: var(--surface-sunk);
    color: var(--text-primary);
}

.move-menu-item-danger { color: var(--danger-color); }

main {
    display: flex;
    flex-direction: column;
    gap: 24px;
}

/* ============================================================
   EDITOR SHELL, rail + one visible stage
   The editor used to be seven collapsible panels in one column. It is now a
   sticky rail of stages with exactly one stage rendered at a time. The order
   is backwards design (context -> outcomes -> materials -> evidence -> plan)
   and the rail exists to say so: it numbers the steps, reports each one's
   state, and gives reports and future exports somewhere to live that isn't
   the bottom of a stack. Step numbers are COMPUTED (see renderStageRail) , 
   never hardcode "Step 3 of 5" or the next stage addition means editing
   every label.
   ============================================================ */
.editor-shell {
    display: grid;
    grid-template-columns: 244px minmax(0, 1fr);
    gap: 20px;
    align-items: start;
}

.stage-rail {
    position: sticky;
    top: 16px;
    background: var(--panel-bg);
    border: 1px solid var(--border-color);
    border-radius: 12px;
    box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.06);
    padding: 12px 8px 8px;
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.rail-group-label {
    font-size: 0.64rem;
    font-weight: 700;
    letter-spacing: 0.11em;
    text-transform: uppercase;
    color: var(--text-muted);
    padding: 6px 10px 7px;
}

.rail-group-label + .rail-step { margin-top: 0; }

.rail-group-label:not(:first-child) {
    margin-top: 10px;
    padding-top: 13px;
    border-top: 1px solid var(--border-soft);
}

.rail-step {
    display: grid;
    grid-template-columns: 21px minmax(0, 1fr);
    gap: 10px;
    align-items: start;
    width: 100%;
    font: inherit;
    text-align: left;
    border: 0;
    background: none;
    cursor: pointer;
    padding: 8px 10px;
    border-radius: 8px;
    color: var(--text-primary);
    border-left: 2px solid transparent;
}

.rail-step:hover { background: var(--surface-soft); }
.rail-step:focus-visible { outline: 2px solid var(--primary-color); outline-offset: -2px; }

.rail-step[aria-selected="true"] {
    background: var(--wash-brand);
    border-left-color: var(--primary-color);
}

.rail-step-n {
    font-size: 0.74rem;
    font-weight: 700;
    width: 21px;
    height: 21px;
    border-radius: 100px;
    display: grid;
    place-items: center;
    background: var(--surface-sunk);
    color: var(--text-muted);
    font-variant-numeric: tabular-nums;
}

.rail-step.is-done .rail-step-n { background: var(--wash-good); color: var(--success-color); }
.rail-step[aria-selected="true"] .rail-step-n { background: var(--primary-color); color: #fff; }
.rail-step.is-plain .rail-step-n { background: none; font-size: 0.8rem; }

.rail-step-name {
    font-size: 0.85rem;
    font-weight: 600;
    display: block;
    line-height: 1.35;
}

.rail-step-caption {
    font-size: 0.66rem;
    font-weight: 700;
    letter-spacing: 0.07em;
    text-transform: uppercase;
    color: var(--primary-color);
    display: block;
    margin-top: 2px;
}

.rail-step-meta {
    font-size: 0.74rem;
    color: var(--text-muted);
    display: block;
    line-height: 1.35;
    margin-top: 1px;
}

.rail-step-meta.is-warn { color: var(--warning-color); font-weight: 600; }

.rail-dot {
    width: 7px;
    height: 7px;
    border-radius: 100px;
    background: var(--success-color);
    display: inline-block;
}
.rail-dot.is-warn { background: var(--warning-color); }

.rail-foot {
    margin-top: 12px;
    padding: 11px 12px 4px;
    border-top: 1px solid var(--border-soft);
    display: flex;
    flex-direction: column;
    gap: 5px;
}

.rail-foot-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    font-size: 0.74rem;
}

.rail-foot-row > span:first-child { color: var(--text-muted); }
.rail-foot-row b { font-variant-numeric: tabular-nums; font-weight: 700; }

.rail-meter {
    width: 44px;
    height: 5px;
    border-radius: 100px;
    background: var(--surface-sunk);
    overflow: hidden;
    flex: none;
}
.rail-meter i { display: block; height: 100%; border-radius: 100px; background: var(--success-color); }
.rail-meter.is-warn i { background: var(--warning-color); }

/* Stages */
.stage-canvas { min-width: 0; }

.stage {
    display: none;
    background: var(--panel-bg);
    border-radius: 12px;
    padding: 24px;
    box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
    border: 1px solid var(--border-color);
}

.stage.is-active { display: block; }

.stage-head {
    border-bottom: 1px solid var(--border-color);
    padding-bottom: 14px;
    margin-bottom: 18px;
}

.stage-eyebrow {
    font-size: 0.66rem;
    font-weight: 700;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--primary-color);
    margin-bottom: 3px;
}

.stage-head h2 {
    font-size: 1.35rem;
    font-weight: 600;
    margin-bottom: 0;
    color: var(--text-primary);
    letter-spacing: -0.01em;
}

.stage-head h2:focus { outline: none; }
.stage-head h2:focus-visible { outline: 2px solid var(--primary-color); outline-offset: 3px; border-radius: 4px; }

.stage-meta {
    font-size: 0.86rem;
    color: var(--text-muted);
    margin: 3px 0 0;
}

.stage-actions {
    display: flex;
    gap: 8px;
    flex-wrap: wrap;
    margin-top: 12px;
}

/* .btn-add is full-width by default, it used to sit alone under a panel's
   content. In a stage header it's one button in a row, like the rest. */
.stage-actions .btn-add {
    width: auto;
    margin-top: 0;
}

/* Prev / next along the bottom of a design stage, the rail is the map, these
   are the path through it. */
.stage-nav {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-top: 22px;
    padding-top: 16px;
    border-top: 1px solid var(--border-color);
}

.stage-nav .stage-nav-gap { flex: 1; }

@media (max-width: 900px) {
    .editor-shell { grid-template-columns: minmax(0, 1fr); }
    .stage-rail { position: static; }
}

.section-header {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    gap: 16px;
    margin-bottom: 16px;
}

.section-header h2 {
    margin-bottom: 4px;
}

.section-header .help-text {
    margin-bottom: 0;
}

.section-actions {
    display: flex;
    gap: 8px;
    flex-shrink: 0;
}

.help-text {
    font-size: 0.875rem;
    color: var(--text-muted);
    margin-bottom: 12px;
}

/* Forms */
.form-group {
    margin-bottom: 16px;
}

.form-group label {
    display: block;
    font-size: 0.875rem;
    font-weight: 500;
    margin-bottom: 6px;
    color: var(--text-secondary);
}

.form-row {
    display: flex;
    gap: 16px;
}

.form-row .form-group {
    flex: 1;
}

/* Course name should take the room; Term only needs enough for "Fall 2027". */
.form-row .form-group-grow {
    flex: 2.5;
}

/* Course code and number hold "ENG" and "101", they shouldn't claim an equal
   share of the row the way a bare .form-group would. */
.form-row .form-group-narrow {
    flex: 0 1 100px;
    min-width: 80px;
}

.field-hint {
    margin-top: 4px;
    font-size: 0.75rem;
}

/* ============================================
   CUSTOM SELECT, styled dropdown used by the term picker
   ============================================ */

.term-picker {
    display: flex;
    gap: 8px;
}

.cx-select {
    position: relative;
    flex: 1;
    min-width: 0;
}

.cx-select-year {
    flex: 0 0 96px;
}

.cx-select-btn {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    width: 100%;
    padding: 10px 12px;
    font: inherit;
    font-size: 0.95rem;
    color: var(--text-primary);
    background: var(--panel-bg);
    border: 1px solid var(--border-color);
    border-radius: 8px;
    cursor: pointer;
    text-align: left;
}

.cx-select-btn:hover { border-color: var(--text-muted); }

.cx-select.is-open .cx-select-btn {
    border-color: var(--primary-color);
    box-shadow: 0 0 0 3px rgba(26, 127, 142, 0.14);
}

.cx-select-btn.is-empty .cx-select-value { color: var(--text-muted); }

.cx-select-value {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.cx-select-caret {
    font-size: 0.7rem;
    color: var(--text-muted);
    flex-shrink: 0;
}

.cx-select-menu {
    display: none;
    position: absolute;
    top: calc(100% + 4px);
    left: 0;
    right: 0;
    z-index: 2500;
    background: var(--panel-bg);
    border: 1px solid var(--border-color);
    border-radius: 8px;
    box-shadow: 0 4px 16px rgba(14, 42, 47, 0.14);
    padding: 5px;
    max-height: 260px;
    overflow-y: auto;
}

.cx-select.is-open .cx-select-menu { display: block; }

.cx-option {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    width: 100%;
    padding: 8px 10px;
    border: none;
    background: none;
    border-radius: 6px;
    font: inherit;
    font-size: 0.9rem;
    color: var(--text-primary);
    cursor: pointer;
    text-align: left;
}

.cx-option:hover { background: var(--surface-sunk); }

.cx-option.is-selected {
    background: var(--wash-brand);
    color: var(--primary-hover);
    font-weight: 600;
}

.cx-option-remove {
    border: none;
    background: none;
    cursor: pointer;
    color: var(--text-muted);
    font-size: 1rem;
    line-height: 1;
    padding: 0 4px;
    border-radius: 4px;
    flex-shrink: 0;
}

.cx-option-remove:hover { color: var(--danger-color); background: var(--panel-bg); }

.cx-select-divider {
    height: 1px;
    background: var(--border-color);
    margin: 5px 2px;
}

.cx-option-add { color: var(--primary-color); font-weight: 600; }

.cx-add-form { padding: 4px; }

.cx-add-input {
    width: 100%;
    padding: 8px 10px;
    font: inherit;
    font-size: 0.9rem;
    border: 1px solid var(--primary-color);
    border-radius: 6px;
}

/* --- year picker (pageable grid) --- */
.cx-year-menu {
    left: auto;
    right: 0;
    width: 232px;
    padding: 8px;
    overflow: visible;
}

.cx-year-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 6px;
    margin-bottom: 6px;
}

.cx-year-range {
    font-size: 0.82rem;
    font-weight: 650;
    color: var(--text-secondary);
    font-variant-numeric: tabular-nums;
}

.cx-year-nav {
    border: none;
    background: none;
    cursor: pointer;
    color: var(--text-secondary);
    font-size: 1.1rem;
    line-height: 1;
    padding: 3px 9px;
    border-radius: 6px;
}

.cx-year-nav:hover {
    background: var(--surface-sunk);
    color: var(--text-primary);
}

.cx-year-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 4px;
}

.cx-year {
    border: 1px solid transparent;
    background: none;
    cursor: pointer;
    font: inherit;
    font-size: 0.88rem;
    font-variant-numeric: tabular-nums;
    color: var(--text-primary);
    padding: 8px 0;
    border-radius: 6px;
}

.cx-year:hover { background: var(--surface-sunk); }

/* Current calendar year is outlined; the chosen year is filled. */
.cx-year.is-today { border-color: var(--border-color); font-weight: 650; }

.cx-year.is-selected {
    background: var(--primary-color);
    border-color: var(--primary-color);
    color: #ffffff;
    font-weight: 650;
}

.cx-year.is-selected:hover { background: var(--primary-hover); }

/* Only rendered when the current year is off-page */
.cx-year-jump {
    width: 100%;
    margin-top: 6px;
    padding: 7px 0;
    border: none;
    border-top: 1px solid var(--border-color);
    background: none;
    cursor: pointer;
    font: inherit;
    font-size: 0.82rem;
    font-weight: 600;
    color: var(--primary-color);
    border-radius: 0 0 6px 6px;
}

.cx-year-jump:hover { background: var(--surface-sunk); }

@media (max-width: 640px) {
    .form-row {
        flex-direction: column;
    }
}

input[type="text"],
input[type="email"],
input[type="password"],
input[type="date"],
select,
textarea {
    width: 100%;
    padding: 10px 12px;
    border: 1px solid var(--border-color);
    border-radius: 6px;
    font-size: 0.9375rem;
    transition: border-color 0.2s, box-shadow 0.2s;
}

input[type="text"]:focus,
input[type="email"]:focus,
input[type="password"]:focus,
input[type="date"]:focus,
select:focus,
textarea:focus {
    outline: none;
    border-color: var(--primary-color);
    box-shadow: 0 0 0 3px rgba(26, 127, 142, 0.14);
}

textarea {
    resize: vertical;
    font-family: inherit;
    line-height: 1.4;
    min-height: 42px;
}

.date-hint {
    font-size: 0.8125rem;
    color: var(--text-secondary);
    margin-top: 4px;
    margin-bottom: 0;
}

.inline-form {
    display: flex;
    gap: 8px;
    margin-top: 12px;
}

.inline-form input {
    flex: 1;
    max-width: 200px;
}

.suggestions-list {
    position: fixed;
    background: #fff;
    border: 1px solid var(--border-color);
    border-radius: 6px;
    box-shadow: 0 4px 12px rgba(0,0,0,0.12);
    z-index: 1000;
    min-width: 180px;
    max-height: 260px;
    overflow-y: auto;
}


.suggestions-item {
    padding: 8px 12px;
    cursor: pointer;
    font-size: 0.9rem;
    color: var(--text-primary);
}

.suggestions-item:hover {
    background: var(--surface-sunk);
}

/* Already on the course, greyed out and inert rather than removable here;
   use the × on the tag itself to remove. */
.suggestions-item.is-added {
    color: var(--text-muted);
    cursor: default;
    pointer-events: none;
}

.suggestions-item.is-added:hover {
    background: none;
}

/* Buttons */
.btn {
    padding: 10px 16px;
    border: none;
    border-radius: 6px;
    font-size: 0.9375rem;
    font-weight: 500;
    cursor: pointer;
    transition: background-color 0.2s, transform 0.1s;
}

.btn:hover {
    transform: translateY(-1px);
}

.btn:active {
    transform: translateY(0);
}

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

.btn-primary:hover {
    background: var(--primary-hover);
}

.btn-secondary {
    background: white;
    color: var(--text-primary);
    border: 1px solid var(--border-color);
}

.btn-secondary:hover {
    background: #f9fafb;
    border-color: #d1d5db;
}

.btn-danger {
    background: var(--danger-color);
    color: white;
}

.btn-danger:hover {
    background: var(--danger-hover);
}

.btn-help {
    background: white;
    color: var(--primary-color);
    border: 1px solid var(--primary-color);
    border-radius: 50%;
    width: 34px;
    height: 34px;
    padding: 0;
    font-size: 1rem;
    font-weight: 700;
    line-height: 1;
    flex-shrink: 0;
}

.btn-help:hover {
    background: var(--primary-color);
    color: white;
}

/* Help modal steps */
.help-steps {
    display: flex;
    flex-direction: column;
    gap: 16px;
}

.help-step {
    display: flex;
    gap: 14px;
    align-items: flex-start;
}

.help-step-number {
    flex-shrink: 0;
    width: 28px;
    height: 28px;
    border-radius: 50%;
    background: var(--primary-color);
    color: white;
    font-size: 0.875rem;
    font-weight: 700;
    display: flex;
    align-items: center;
    justify-content: center;
    margin-top: 1px;
}

.help-step-body strong {
    display: block;
    margin-bottom: 2px;
    color: var(--text-primary);
}

.help-step-body p {
    font-size: 0.9rem;
    color: var(--text-secondary);
    margin: 0;
}

.help-tip {
    margin-top: 20px;
    background: #eff6ff;
    border-left: 3px solid var(--primary-color);
    border-radius: 0 6px 6px 0;
    padding: 12px 14px;
    font-size: 0.9rem;
}

.help-tip strong {
    display: block;
    margin-bottom: 3px;
    color: var(--primary-color);
}

.help-tip p {
    color: var(--text-secondary);
    margin: 0;
}

.btn-add {
    background: transparent;
    color: var(--primary-color);
    border: 2px dashed var(--primary-color);
    width: 100%;
    margin-top: 12px;
}

.btn-add:hover {
    background: rgba(26, 127, 142, 0.07);
}

.btn-small {
    padding: 8px 12px;
    font-size: 0.875rem;
}

.btn-icon {
    padding: 6px 10px;
    background: transparent;
    color: var(--text-secondary);
}

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

.btn-icon.danger:hover {
    color: var(--danger-color);
}

/* CLLO List */
.item-list {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.cllo-item {
    display: flex;
    align-items: flex-start;
    gap: 12px;
    padding: 12px;
    background: var(--background);
    border-radius: 8px;
    border: 1px solid var(--border-color);
}

.cllo-item .drag-handle {
    cursor: grab;
    padding-top: 9px;
}

.cllo-item .drag-handle:active {
    cursor: grabbing;
}

.cllo-number {
    font-weight: 600;
    color: var(--primary-color);
    min-width: 60px;
    padding-top: 9px;
}

.cllo-body {
    flex: 1;
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.cllo-description {
    width: 100%;
    padding: 8px;
    border: 1px solid transparent;
    border-radius: 4px;
    background: transparent;
    font-size: 0.9375rem;
    box-sizing: border-box;
    font-family: inherit;
    line-height: 1.4;
    resize: none;
    overflow: hidden;
    min-height: 36px;
}

.cllo-description:focus {
    border-color: var(--border-color);
    background: white;
    outline: none;
}

.cllo-pllo-section {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
    padding: 0 8px;
}

.cllo-pllo-label {
    font-size: 0.8125rem;
    color: var(--text-secondary);
    font-weight: 500;
    white-space: nowrap;
}

.cllo-pllo-checkboxes {
    display: flex;
    flex-wrap: wrap;
    gap: 4px 12px;
}

.cllo-pllo-checkbox {
    display: flex;
    align-items: center;
    gap: 4px;
    font-size: 0.8125rem;
    color: var(--text-primary);
    cursor: pointer;
}

.cllo-pllo-checkbox input {
    cursor: pointer;
}

.cllo-actions {
    display: flex;
    gap: 4px;
    padding-top: 4px;
}

/* Alignment Map */
.alignment-assignments {
    line-height: 1.5;
}

.alignment-group {
    display: block;
}

.alignment-group + .alignment-group {
    margin-top: 4px;
}

.alignment-row-uncovered td {
    background-color: #fafafa;
    color: var(--text-secondary);
}

.alignment-not-covered {
    font-style: italic;
    color: var(--text-muted) !important;
}

.alignment-not-covered-inline {
    font-style: italic;
    color: var(--text-muted);
}

/* Summary Table */
.summary-table {
    width: 100%;
    border-collapse: collapse;
    margin-top: 16px;
    font-size: 0.875rem;
}

.summary-table th,
.summary-table td {
    padding: 8px 12px;
    border: 1px solid var(--border-color);
    text-align: left;
}

.summary-table th {
    background: var(--background);
    font-weight: 600;
}

.summary-ec-row td {
    font-style: italic;
    color: var(--text-secondary);
    background: var(--background);
}

.summary-total-row td {
    font-weight: 600;
    border-top: 2px solid var(--border-color);
    background: var(--background);
}

.weight-total-warn td {
    color: #b91c1c;
}

.grading-mode-toggle {
    display: flex;
    align-items: center;
    gap: 8px;
}

.grading-mode-label {
    font-size: 13px;
    font-weight: 600;
    color: var(--text-secondary);
}

.grading-mode-toggle .btn.active {
    background: var(--primary-color);
    color: #fff;
    border-color: var(--primary-color);
}

.weight-input {
    width: 70px;
    padding: 2px 6px;
    border: 1px solid var(--border-color);
    border-radius: 4px;
    font-size: 13px;
    text-align: right;
}

/* Assignment Type Tags */
.tag-list {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

.tag {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 6px 12px;
    background: var(--background);
    border: 1px solid var(--border-color);
    border-radius: 20px;
    font-size: 0.875rem;
}

.tag .rename-tag {
    cursor: pointer;
    color: var(--text-muted);
    font-size: 0.8rem;
    line-height: 1;
    padding: 0 1px;
}

.rename-tag:hover {
    color: var(--primary-color);
}

.tag.is-renaming {
    padding: 2px 6px;
}

.tag-rename-input {
    border: none;
    background: transparent;
    font-family: inherit;
    font-size: 0.875rem;
    color: var(--text-primary);
    padding: 4px 6px;
    min-width: 120px;
    outline: 1px solid var(--primary-color);
    border-radius: 12px;
}

.remove-tag {
    cursor: pointer;
    color: var(--text-muted);
    font-size: 1rem;
    line-height: 1;
}

.tag .remove-tag:hover {
    color: var(--danger-color);
}

.tag .reorder-tag {
    cursor: pointer;
    color: var(--accent-teal);
    font-size: 0.65rem;
    line-height: 1;
}

.tag .reorder-tag:hover {
    color: var(--accent-teal-hover);
}

.tag .reorder-tag.disabled {
    visibility: hidden;
    cursor: default;
    pointer-events: none;
}

/* Module List */
.module-list {
    display: flex;
    flex-direction: column;
    gap: 16px;
}

.module-item {
    background: var(--background);
    border: 1px solid var(--border-color);
    border-radius: 8px;
    overflow: hidden;
}

.module-header {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 16px;
    background: white;
    border-bottom: 1px solid var(--border-color);
    cursor: grab;
}

.module-header:active {
    cursor: grabbing;
}

/* Sequence, not a name. Derived from array position at render time (see
   renderModules()), same rule getClloNumber() already follows, so reordering
   modules renumbers this with no extra bookkeeping. Deliberately not part of
   module.name: a name like "Week 5" goes stale the moment the schedule is
   reordered or the term dates change, this badge never can. */
.module-number {
    flex: none;
    width: 22px;
    height: 22px;
    border-radius: 100px;
    background: var(--wash-brand);
    color: var(--primary-color);
    font-size: 0.78rem;
    font-weight: 700;
    display: flex;
    align-items: center;
    justify-content: center;
    font-variant-numeric: tabular-nums;
}

.collapse-toggle {
    background: none;
    border: none;
    cursor: pointer;
    padding: 4px;
    font-size: 1rem;
    color: var(--text-secondary);
    transition: transform 0.2s;
    line-height: 1;
}

.collapse-toggle:hover {
    color: var(--text-primary);
}

.module-item.collapsed .collapse-toggle {
    transform: rotate(-90deg);
}

.module-item.collapsed .module-header {
    border-bottom: none;
}

.module-content {
    overflow: hidden;
    transition: max-height 0.3s ease, padding 0.3s ease;
    /* Uncapped when open: a fixed max-height silently clips a long module.
       The open/close animation sets an explicit pixel height from JS
       (animateCollapse) and clears it once open. */
    max-height: none;
}

.module-item.collapsed .module-content {
    max-height: 0;
    padding-top: 0;
    padding-bottom: 0;
}

.drag-handle {
    color: var(--text-muted);
    font-size: 1.25rem;
}

.module-info {
    flex: 1;
}

.module-title {
    font-weight: 600;
    font-size: 1rem;
}

.module-dates {
    font-size: 0.875rem;
    color: var(--text-secondary);
    display: flex;
    align-items: center;
    gap: 6px;
}

.date-flag {
    display: inline-block;
    width: 8px;
    height: 8px;
    margin-left: 6px;
    border-radius: 50%;
    background: #f59e0b;
    flex-shrink: 0;
    cursor: pointer;
}

.module-dates .date-flag {
    margin-left: 0;
}

/* Static sample in the Schedule Builder legend, same dot, not clickable */
.date-flag.is-legend {
    margin-left: 0;
    margin-right: 5px;
    cursor: default;
}

.schedule-legend {
    display: flex;
    align-items: center;
    margin-top: 4px;
}

.module-topic {
    font-size: 0.875rem;
    color: var(--text-muted);
    font-style: italic;
}

.assignment-count {
    font-size: 0.8125rem;
    color: var(--text-muted);
    margin-left: auto;
}

.module-actions {
    display: flex;
    gap: 4px;
}

.module-content {
    padding: 12px 16px;
}

.assignment-list {
    display: flex;
    flex-direction: column;
    gap: 8px;
    min-height: 40px;
}

.assignment-item {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 10px 12px;
    background: white;
    border: 1px solid var(--border-color);
    border-radius: 6px;
    cursor: grab;
}

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

.assignment-item .drag-handle {
    font-size: 1rem;
}

.assignment-info {
    flex: 1;
}

.assignment-name {
    font-weight: 500;
}

.assignment-meta {
    font-size: 0.8125rem;
    color: var(--text-secondary);
}

.assignment-type {
    background: var(--primary-color);
    color: white;
    padding: 2px 8px;
    border-radius: 4px;
    font-size: 0.75rem;
    margin-right: 8px;
}

    .assignment-points {
        background: var(--border-color);
        color: var(--text-secondary);
        padding: 2px 8px;
        border-radius: 4px;
        font-size: 0.75rem;
        margin-right: 8px;
    }

.assignment-ec {
    background: #fef3c7;
    color: #92400e;
    padding: 2px 8px;
    border-radius: 4px;
    font-size: 0.75rem;
    margin-right: 8px;
}

.assignment-cllos {
    color: var(--text-muted);
}

.assignment-due {
    font-size: 0.8125rem;
    color: var(--text-secondary);
    min-width: 80px;
    text-align: right;
}

.assignment-actions {
    display: flex;
    gap: 4px;
}

.btn-add-assignment {
    margin-top: 8px;
    padding: 8px 12px;
    background: transparent;
    border: 1px dashed var(--border-color);
    border-radius: 6px;
    color: var(--text-secondary);
    cursor: pointer;
    width: 100%;
    font-size: 0.875rem;
}

.btn-add-assignment:hover {
    border-color: var(--primary-color);
    color: var(--primary-color);
    background: rgba(26, 127, 142, 0.07);
}

/* Preview Table */
.export-actions {
    display: flex;
    gap: 8px;
    margin-bottom: 16px;
}

.table-preview {
    overflow-x: auto;
}

.table-preview table {
    width: 100%;
    border-collapse: collapse;
    font-size: 0.9375rem;
}

.table-preview th,
.table-preview td {
    padding: 12px;
    text-align: left;
    border: 1px solid var(--border-color);
}

.table-preview th {
    background: var(--background);
    font-weight: 600;
}

.table-preview tr:hover td {
    background: rgba(26, 127, 142, 0.03);
}

/* ============================================
   COURSE SCHEDULE REPORT, panel-per-module print layout
   (structure from coursetrix_panel_layout.html / Coursetrix Campus's CCSG
   schedule cards, recolored to Coursetrix Pro's own teal/green brand
   palette rather than CCSG's warm brown). Tokens live at :root (not scoped
   to #tablePreview) so the print view, a separate DOM subtree built for
   window.print(), can share the exact same classes and colors instead of
   duplicating them; the report- prefix already keeps the class names from
   colliding with the app's own .panel styling.
   ============================================ */

:root {
    --report-ink: var(--text-primary);
    --report-paper: var(--panel-bg);
    --report-rule: var(--border-soft);
    --report-rule-strong: var(--border-color);
    --report-accent: var(--primary-color);
    /* One step darker than --report-accent, so a SECTION heading outranks a
       module heading without introducing a second visual device. Aliased like
       the rest, so a palette change still cascades. */
    --report-accent-deep: var(--brand-deep);
    --report-accent-soft: var(--wash-brand);
    --report-muted: var(--text-muted);
}

.report-panels {
    font-family: 'Iowan Old Style', Georgia, serif;
    color: var(--report-ink);
}

.report-module {
    border: 1px solid var(--report-rule-strong);
    background: var(--report-paper);
    margin-bottom: 16px;
}

/* Dates / Module Name / Topic each get their own line, a fixed side-by-side
   row (the original coursetrix_panel_layout.html mockup's layout) breaks
   down once any one field runs long; stacking, like CCSG's own sched-card
   head, stays readable regardless of length. */
.report-module-head {
    padding: 12px 18px;
    background: var(--report-accent-soft);
    border-bottom: 1px solid var(--report-rule-strong);
}

.report-module-dates {
    display: block;
    font-family: 'Helvetica Neue', Arial, sans-serif;
    font-size: 0.72rem;
    font-weight: 700;
    letter-spacing: 0.03em;
    color: var(--report-muted);
}

.report-module-name {
    margin: 3px 0 0;
    font-family: 'Iowan Old Style', Georgia, serif;
    font-size: 1.1rem;
    font-weight: 700;
    color: var(--report-accent);
}

.report-module-topic {
    margin: 3px 0 0;
    font-family: 'Iowan Old Style', Georgia, serif;
    font-size: 0.92rem;
    font-style: italic;
    color: var(--report-ink);
}

.report-assignments {
    padding: 14px 18px 14px 38px;
}

.report-assignment-list {
    display: flex;
    flex-direction: column;
    gap: 9px;
}

.report-assignment-item {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    align-items: baseline;
    gap: 6px 14px;
    padding-bottom: 9px;
    border-bottom: 1px dashed var(--report-rule);
}

.report-assignment-item:last-child {
    border-bottom: none;
    padding-bottom: 0;
}

.report-assignment-empty {
    color: var(--report-muted);
    font-style: italic;
    justify-content: flex-start;
}

.report-assignment-name {
    font-weight: 600;
    min-width: 0;
}

.report-assignment-meta {
    font-family: 'Helvetica Neue', Arial, sans-serif;
    font-size: 0.8rem;
    color: var(--report-muted);
    white-space: nowrap;
}

/* Shown only when the condensed instructions are NOT being printed, see
   assignmentMeta() in app.js. Teal, from the report's own accent token, so a
   palette change carries here and so it never reads as a coverage state. */
.report-assignment-instr {
    display: inline-block;
    margin-left: 6px;
    padding: 0 7px;
    border: 1px solid var(--report-accent);
    border-radius: 999px;
    color: var(--report-accent);
    font-size: 0.72rem;
    line-height: 1.5;
    white-space: nowrap;
}

.report-assignment-due {
    color: var(--report-accent);
    font-weight: 600;
}

.report-totals {
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-end;
    gap: 6px 20px;
    font-family: 'Helvetica Neue', Arial, sans-serif;
    font-size: 0.82rem;
    font-weight: 600;
    color: var(--report-ink);
    padding: 10px 4px;
}

.report-totals-ec {
    font-weight: 400;
    font-style: italic;
    color: var(--report-muted);
}

.report-footer {
    margin-top: 12px;
    padding-top: 14px;
    border-top: 1px solid var(--report-rule);
    font-family: 'Helvetica Neue', Arial, sans-serif;
    font-size: 0.72rem;
    color: var(--report-muted);
    text-align: right;
}

/* ============================================
   PDF / PRINT VIEW, window.print()-based export, same pattern Coursetrix
   Campus's CCSG syllabus generator uses ("Print / Save PDF" on real styled
   HTML) rather than hand-drawing a PDF with jsPDF. The Course Schedule
   section below reuses #tablePreview's already-rendered .report-panels
   markup directly (see buildPdfPrintHtml() in app.js), so it can never
   visually drift from the on-screen preview. Hidden outside of printing , 
   see @media print, which hides everything else in <body> instead.
   ============================================ */

.pdf-print-view {
    display: none;
}

/* The front sections (header, outcomes, type summary) and the Course Schedule
   used to be two different documents stapled together: flat sans-serif sections
   with underlined titles, then serif bordered panels. They now share one
   vocabulary, the schedule's, because that is the half that was designed.
   Everything below draws from the same --report-* tokens the panels do, so a
   palette change still cascades to both. */
.pdf-print-view,
#pdfPrintView {
    font-family: 'Iowan Old Style', Georgia, serif;
    color: var(--report-ink);
}

.pdf-print-header {
    margin-bottom: 18px;
    padding-bottom: 12px;
    border-bottom: 2px solid var(--report-accent-deep);
}

.pdf-print-course-name {
    margin: 0;
    font-size: 1.85rem;
    font-weight: 700;
    letter-spacing: -0.01em;
    color: var(--report-accent-deep);
}

/* Same treatment as a module head's date line, small, bold, letterspaced
   Helvetica against the serif, so the two read as the same kind of label. */
.pdf-print-dates {
    margin: 5px 0 0;
    font-family: 'Helvetica Neue', Arial, sans-serif;
    font-size: 0.72rem;
    font-weight: 700;
    letter-spacing: 0.03em;
    color: var(--report-muted);
}

/* A section is a panel, exactly like .report-module: bordered, paper ground,
   tinted head with a serif accent title. */
.pdf-print-section {
    margin-bottom: 16px;
    border: 1px solid var(--report-rule-strong);
    background: var(--report-paper);
}

.pdf-print-section-title {
    margin: 0;
    padding: 13px 18px;
    background: var(--report-accent-soft);
    border-bottom: 1px solid var(--report-rule-strong);
    font-size: 1.22rem;
    font-weight: 700;
    letter-spacing: -0.005em;
    color: var(--report-accent-deep);
}

.pdf-print-section-body {
    padding: 14px 18px;
}

.pdf-print-program-title {
    margin: 0 0 10px;
    font-style: italic;
    color: var(--report-ink);
}

.pdf-print-outcome-list {
    margin: 0;
    padding-left: 20px;
}

.pdf-print-outcome-list li {
    margin-bottom: 8px;
    line-height: 1.5;
}

.pdf-print-outcome-list li:last-child {
    margin-bottom: 0;
}

.pdf-print-outcome-meta {
    font-family: 'Helvetica Neue', Arial, sans-serif;
    font-size: 0.75rem;
    font-weight: 600;
    color: var(--report-accent);
}

/* Dashed row rules and a Helvetica label row, the assignment list's language,
   not a gridded spreadsheet table. */
.pdf-print-summary-table {
    width: 100%;
    border-collapse: collapse;
}

.pdf-print-summary-table th,
.pdf-print-summary-table td {
    padding: 7px 0;
    text-align: left;
    border-bottom: 1px dashed var(--report-rule);
}

.pdf-print-summary-table th {
    font-family: 'Helvetica Neue', Arial, sans-serif;
    font-size: 0.72rem;
    font-weight: 700;
    letter-spacing: 0.03em;
    color: var(--report-muted);
    border-bottom: 1px solid var(--report-rule-strong);
}

.pdf-print-summary-table th:last-child,
.pdf-print-summary-table td:last-child {
    text-align: right;
    font-variant-numeric: tabular-nums;
}

.pdf-print-summary-total td {
    font-weight: 700;
    color: var(--report-accent);
    border-bottom: none;
    border-top: 1px solid var(--report-rule-strong);
}

/* The schedule's children are already panels, so its heading is a head bar on
   its own rather than a box wrapped around more boxes. */
.pdf-print-schedule > .pdf-print-section-title {
    border: 1px solid var(--report-rule-strong);
    margin-bottom: 16px;
}

/* ---- one assignment's instructions as a handout ---------------------------
   Injected into #pdfPrintView by printInstructions(), so it inherits the same
   @media print rules that hide the rest of <body>. The markup is the 'export'
   variant, which carries NO app classes on purpose, so everything here is
   styled by element from the container down. Colours come from the --report-*
   tokens, so a palette change reaches this the same as the schedule report. */
.instr-print {
    font-family: 'Helvetica Neue', Arial, sans-serif;
    color: var(--report-ink);
    max-width: 7.2in;
}

.instr-print-head {
    border-bottom: 2px solid var(--report-accent);
    padding-bottom: 10px;
    margin-bottom: 18px;
}

.instr-print-course {
    font-size: 0.72rem;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--report-muted);
    margin: 0 0 4px;
}

.instr-print h1 {
    font-family: Georgia, 'Times New Roman', serif;
    font-size: 1.5rem;
    color: var(--report-accent-deep);
    margin: 0;
}

.instr-print-facts {
    font-size: 0.82rem;
    color: var(--report-muted);
    margin: 6px 0 0;
}

/* The export variant emits h4 + p/ul/ol and nothing else. */
.instr-print-body h4 {
    font-size: 0.74rem;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--report-accent);
    margin: 18px 0 6px;
    padding-bottom: 3px;
    border-bottom: 1px dashed var(--report-rule);
}

.instr-print-body p,
.instr-print-body li {
    font-size: 0.92rem;
    line-height: 1.55;
    margin: 0 0 6px;
}

.instr-print-body ul,
.instr-print-body ol {
    margin: 0 0 10px;
    padding-left: 1.3em;
}

/* A heading stranded at the foot of a page with its list overleaf is the one
   break that actually reads as broken. */
.instr-print-body h4 {
    break-after: avoid;
    page-break-after: avoid;
}

.instr-print-body li {
    break-inside: avoid;
    page-break-inside: avoid;
}

@media print {
    /* Preserve panel/table background colors instead of the browser
       optimizing them away to save ink (only takes effect once the print
       dialog's own "background graphics" is on, same caveat CCSG's print
       styles carry, not something CSS alone can force). */
    * {
        -webkit-print-color-adjust: exact !important;
        print-color-adjust: exact !important;
    }

    body {
        background: #fff !important;
    }

    body > *:not(#pdfPrintView) {
        display: none !important;
    }

    #pdfPrintView {
        display: block !important;
    }

    @page {
        size: letter portrait;
        margin: 0.5in 0.6in;
    }

    /* Never split a module panel or a summary-table row across a page
       break, same rule CCSG uses on its schedule cards. */
    .report-module,
    .report-assignment-item,
    .pdf-print-summary-table tr {
        break-inside: avoid;
        page-break-inside: avoid;
    }

    .pdf-print-section-title,
    .pdf-print-header {
        break-after: avoid;
        page-break-after: avoid;
    }

    /* An outcome is one sentence; splitting it across a page break is the one
       thing that makes this list hard to read. The SECTION stays breakable , 
       a long outcome list has to be allowed to run over. */
    .pdf-print-outcome-list li {
        break-inside: avoid;
        page-break-inside: avoid;
    }
}

/* Modal */
.modal {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background: rgba(0, 0, 0, 0.5);
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 1000;
}

.modal.hidden {
    display: none;
}

.modal-content {
    background: white;
    padding: 24px;
    border-radius: 12px;
    width: 90%;
    max-width: 500px;
    max-height: 90vh;
    overflow-y: auto;
}

.modal-content-wide {
    max-width: 640px;
}

.modal-content h3 {
    margin-bottom: 20px;
    font-size: 1.25rem;
}

.modal-actions {
    display: flex;
    justify-content: flex-end;
    gap: 8px;
    margin-top: 24px;
}

/* Checkbox Group */
.checkbox-group {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.checkbox-item {
    display: flex;
    align-items: flex-start;
    gap: 8px;
}

.checkbox-item input[type="checkbox"] {
    margin-top: 4px;
}

.checkbox-item label {
    font-size: 0.9375rem;
    cursor: pointer;
}

/* Sortable Ghost */
.sortable-ghost {
    opacity: 0.4;
}

.sortable-chosen {
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}

/* Empty State */
.empty-state {
    text-align: center;
    padding: 24px;
    color: var(--text-muted);
    font-style: italic;
}

/* Toast Notification */
.toast {
    position: fixed;
    bottom: 24px;
    right: 24px;
    background: var(--text-primary);
    color: white;
    padding: 12px 20px;
    border-radius: 8px;
    font-size: 0.9375rem;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
    z-index: 2000;
    animation: slideIn 0.3s ease;
}

.toast.success {
    background: var(--success-color);
}

.confirm-overlay {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.4);
    z-index: 4000;
    display: flex;
    align-items: center;
    justify-content: center;
}

.confirm-dialog {
    background: white;
    border-radius: 10px;
    padding: 24px;
    max-width: 360px;
    width: 90%;
    box-shadow: 0 8px 32px rgba(0, 0, 0, 0.2);
}

.confirm-message {
    margin: 0 0 20px;
    color: var(--text-primary);
    line-height: 1.5;
}

.confirm-actions {
    display: flex;
    gap: 10px;
    justify-content: flex-end;
}

.move-menu {
    position: fixed;
    background: white;
    border: 1px solid var(--border-color);
    border-radius: 8px;
    box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);
    z-index: 3000;
    min-width: 200px;
    max-width: 280px;
    padding: 6px 0;
    font-size: 0.875rem;
}

.move-menu-label {
    padding: 6px 14px 4px;
    font-size: 0.75rem;
    font-weight: 600;
    color: var(--text-secondary);
    text-transform: uppercase;
    letter-spacing: 0.04em;
}

.move-menu-item {
    display: block;
    width: 100%;
    text-align: left;
    padding: 8px 14px;
    background: none;
    border: none;
    cursor: pointer;
    color: var(--text-primary);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.move-menu-item:hover {
    background: var(--background-secondary);
}

@keyframes slideIn {
    from {
        transform: translateY(20px);
        opacity: 0;
    }
    to {
        transform: translateY(0);
        opacity: 1;
    }
}

/* Footer */
.app-footer {
    margin-top: 40px;
    padding: 24px;
    text-align: center;
    border-top: 1px solid var(--border-color);
    color: var(--text-secondary);
    font-size: 0.875rem;
}

.app-footer a {
    color: var(--primary-color);
    text-decoration: none;
}

.app-footer a:hover {
    text-decoration: underline;
}

.footer-note {
    margin-top: 4px;
    color: var(--text-muted);
    font-size: 0.8125rem;
}

/* Small, muted secondary action, deliberately lower visual weight than the
   real buttons above it (e.g. importing a course, once-off and easy to miss
   on purpose). */
.dashboard-footnote {
    margin-top: 24px;
    text-align: center;
}

/* Month-to-date AI spend. Teal and neutrals only: green and amber are
   reserved for CLLO coverage and date flags app-wide, and a green usage bar
   would read as a coverage state to anyone who has used the dashboard. The
   spent state uses the danger colour, which carries no such meaning. */
.ai-usage-note {
    display: inline-flex;
    flex-direction: column;
    align-items: center;
    gap: 5px;
    margin-bottom: 12px;
    color: var(--text-muted);
    font-size: 0.75rem;
}

.ai-usage-bar {
    display: block;
    width: 180px;
    height: 3px;
    border-radius: 999px;
    background: var(--border-soft);
    overflow: hidden;
}

.ai-usage-bar i {
    display: block;
    height: 100%;
    background: var(--primary-color);
}

/* Running low, distinct from spent. No amber: green and amber mean coverage and
   date flags app-wide, which is why this bar is teal rather than green in the
   first place. The emphasis comes from dropping the muted colour, and the
   wording carries the rest. */
.ai-usage-note.is-low { color: var(--text-primary); font-weight: 600; }
.ai-usage-note.is-spent { color: var(--danger-color); }
.ai-usage-note.is-spent .ai-usage-bar i { background: var(--danger-color); }

.btn-footnote {
    padding: 4px 12px;
    border: 1px solid var(--border-color);
    border-radius: 14px;
    background: none;
    color: var(--text-muted);
    font-size: 0.75rem;
    cursor: pointer;
}

.btn-footnote:hover {
    color: var(--text-secondary);
    border-color: var(--text-muted);
}

/* About Modal */
.about-creator {
    margin-top: 16px;
    padding: 12px 16px;
    background: var(--background);
    border-radius: 8px;
    border: 1px solid var(--border-color);
}

.about-license {
    margin-top: 16px;
    padding: 12px 16px;
    background: #fffbeb;
    border-radius: 8px;
    border: 1px solid #fde68a;
    font-size: 0.875rem;
    color: #78350f;
}

.about-license a {
    color: #92400e;
}

/* What's New Modal */
.whats-new-version {
    font-size: 0.8125rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--primary-color);
    margin-bottom: 10px;
}

.feature-list {
    margin: 0 0 4px 0;
    padding-left: 20px;
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.feature-list li {
    font-size: 0.9375rem;
    color: var(--text-primary);
    line-height: 1.4;
}

/* Responsive */
@media (max-width: 768px) {
    .container {
        padding: 12px;
    }

    header {
        flex-direction: column;
        gap: 12px;
        text-align: center;
    }

    .form-row {
        flex-direction: column;
    }

    .export-actions {
        flex-direction: column;
    }

    .export-actions .btn {
        width: 100%;
    }
}

/* Module dates outside the course date range (e.g. after a semester date
   change where the offered redistribution was declined) */
.dates-range-notice {
    font-size: 13px;
    color: #92400e;
    background: #fef3c7;
    border: 1px solid #fcd34d;
    border-radius: 6px;
    padding: 8px 12px;
    margin-bottom: 12px;
}

/* Optional per-type description in the Assignment Type Summary table */
.type-desc-input {
    width: 100%;
    padding: 5px 8px;
    font-size: 12.5px;
    border: 1px solid #ccc;
    border-radius: 4px;
    box-sizing: border-box;
}
/* AI Assist, chat-style modal shared by all AI-assisted features (CLLOs first) */
.cllo-add-row {
    display: flex;
    gap: 10px;
    margin-top: 12px;
}

.cllo-add-row .btn-add {
    width: auto;
    flex: 1;
    margin-top: 0;
}

.btn-ai {
    background: transparent;
    color: var(--primary-color);
    border: 2px dashed var(--primary-color);
}

/* Splits the CLLO row evenly with + Add CLLO. Scoped there deliberately, as a
   bare .btn-ai rule it also stretched the dashboard's Quick Start button. */
.cllo-add-row .btn-ai {
    flex: 1;
}

.btn-ai:hover {
    background: rgba(26, 127, 142, 0.07);
}

.modal-content-chat {
    max-width: 620px;
    height: 80vh;
    display: flex;
    flex-direction: column;
}

.ai-thread {
    flex: 1;
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    gap: 12px;
    padding: 4px 2px;
    margin-bottom: 12px;
}

.ai-bubble {
    max-width: 85%;
    padding: 10px 14px;
    border-radius: 12px;
    font-size: 0.9rem;
    line-height: 1.45;
    white-space: pre-wrap;
}

.ai-bubble-ai {
    align-self: flex-start;
    background: var(--wash-brand);
    color: var(--text-primary);
    border-bottom-left-radius: 2px;
}

.ai-bubble-user {
    align-self: flex-end;
    background: var(--primary-color);
    color: white;
    border-bottom-right-radius: 2px;
}

.ai-bubble-error {
    align-self: flex-start;
    background: #fdecea;
    color: #7a1f14;
    border-bottom-left-radius: 2px;
}

.ai-candidates {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin-top: 6px;
}

.ai-candidate {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    background: white;
    border: 1px solid var(--border-color);
    border-radius: 8px;
    padding: 8px 10px;
}

.ai-candidate input[type="checkbox"] {
    margin-top: 8px;
    flex-shrink: 0;
}

.ai-candidate-text {
    flex: 1;
    border: none;
    resize: vertical;
    font-family: inherit;
    font-size: 0.875rem;
    color: var(--text-primary);
    background: transparent;
    min-height: 40px;
}

.ai-candidate-text:focus {
    outline: 1px solid var(--primary-color);
    border-radius: 4px;
}

.ai-composer {
    display: flex;
    gap: 8px;
    align-items: flex-end;
    border-top: 1px solid var(--border-color);
    padding-top: 12px;
}

.ai-composer textarea {
    flex: 1;
    padding: 8px 10px;
    border: 1px solid var(--border-color);
    border-radius: 6px;
    font-family: inherit;
    font-size: 0.9rem;
    resize: none;
}

.ai-commit-bar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-top: 10px;
}

.ai-commit-bar.hidden {
    display: none;
}

.ai-selected-count {
    font-size: 0.85rem;
    color: var(--text-secondary);
}

.ai-thinking {
    align-self: flex-start;
    display: flex;
    align-items: center;
    gap: 8px;
    color: var(--text-secondary);
    font-size: 0.85rem;
    font-style: italic;
}

.ai-dots {
    display: inline-flex;
    gap: 4px;
    flex-shrink: 0;
}

.ai-dots i {
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--primary-color);
    animation: aiDotPulse 1.2s infinite ease-in-out;
}

.ai-dots i:nth-child(2) { animation-delay: 0.16s; }
.ai-dots i:nth-child(3) { animation-delay: 0.32s; }

@keyframes aiDotPulse {
    0%, 70%, 100% { opacity: 0.25; transform: translateY(0); }
    35%           { opacity: 1;    transform: translateY(-3px); }
}

/* The elapsed counter only appears once a wait stops feeling instant, so it
   reads as reassurance rather than a stopwatch on every call. */
.ai-elapsed {
    font-style: normal;
    font-variant-numeric: tabular-nums;
    font-size: 0.75rem;
    color: var(--text-muted);
}

.ai-elapsed:empty {
    display: none;
}

/* Motion is decoration here, the label and counter already carry the
   meaning, so drop the animation entirely rather than substituting a
   gentler one. */
@media (prefers-reduced-motion: reduce) {
    .ai-dots i {
        animation: none;
        opacity: 0.55;
        transform: none;
    }
}

.btn-icon-ai {
    color: var(--primary-color);
}

/* Section Assist, a reviewable changelist. Each card shows what the item is
   now and what it would become, so a delete or a reword is legible at a glance
   rather than being an opaque "trust me". */
.sa-op {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    background: white;
    border: 1px solid var(--border-color);
    border-radius: 8px;
    padding: 10px 12px;
}

.sa-op.is-blocked {
    background: var(--panel-bg);
    border-style: dashed;
    opacity: 0.85;
}

.sa-op input[type="checkbox"] {
    margin-top: 3px;
    flex-shrink: 0;
}

.sa-op-body {
    flex: 1;
    min-width: 0;
}

.sa-label {
    font-size: 0.8125rem;
    font-weight: 600;
    color: var(--primary-color);
    margin-bottom: 6px;
}

.sa-before,
.sa-after {
    display: flex;
    align-items: flex-start;
    gap: 8px;
    font-size: 0.875rem;
    line-height: 1.45;
    margin-bottom: 4px;
}

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

.sa-before span:last-child {
    text-decoration: line-through;
    text-decoration-color: var(--text-muted);
}

/* Nothing is struck through when the item is only being reworded into
   something new rather than removed outright. */
.sa-op:has(.sa-after) .sa-before span:last-child {
    text-decoration: none;
}

.sa-after textarea {
    flex: 1;
    border: none;
    background: transparent;
    resize: vertical;
    font-family: inherit;
    font-size: 0.875rem;
    line-height: 1.45;
    color: var(--text-primary);
    padding: 0;
    min-height: 38px;
}

.sa-after textarea:focus {
    outline: 1px solid var(--primary-color);
    border-radius: 4px;
}

.sa-tag {
    flex-shrink: 0;
    font-size: 0.6875rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    font-weight: 600;
    color: var(--text-muted);
    padding-top: 2px;
    width: 30px;
}

.sa-tag-new {
    color: var(--primary-color);
}

.sa-detail,
.sa-note {
    font-size: 0.8rem;
    color: var(--text-secondary);
    margin-top: 2px;
}

.sa-note {
    font-style: italic;
}

.sa-blocked {
    font-size: 0.8rem;
    color: #7a1f14;
    background: #fdecea;
    border-radius: 6px;
    padding: 5px 8px;
    margin-top: 6px;
}

/* Quick Start, reuses .ai-thread/.ai-bubble/.ai-candidates/.ai-commit-bar;
   these are just the extra bits its stages need beyond the CLLO assist. */
.qs-stage-label {
    font-size: 0.75rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--primary-color);
    margin-bottom: 8px;
}

.ai-candidate-type input[type="text"] {
    flex: 1;
    border: none;
    background: transparent;
    font-size: 0.875rem;
    color: var(--text-primary);
    padding: 4px 2px;
}

.ai-candidate-type input[type="text"]:focus {
    outline: 1px solid var(--primary-color);
    border-radius: 4px;
}

/* A catalog course description runs 60-120 words, so it gets paragraph room
   rather than the one-line height a stray form field would default to. */
.course-description-input {
    min-height: 130px;
    line-height: 1.55;
    resize: vertical;
}

/* Stage 1's single draft paragraph, no checkbox, so the textarea takes the
   whole card and gets room to breathe. */
.qs-description-card .ai-candidate-text {
    min-height: 120px;
    line-height: 1.5;
}

/* Stage 4's module-count prompt: a plain number, pre-filled from the course's
   real date range (see describeQsCourseLength). */
.qs-count-card {
    align-items: center;
    gap: 12px;
}

.qs-count-card label {
    font-size: 0.875rem;
    font-weight: 600;
    color: var(--text-primary);
}

.qs-count-card input[type="number"] {
    width: 90px;
    padding: 6px 8px;
    border: 1px solid var(--border-color);
    border-radius: 6px;
    font-family: inherit;
    font-size: 0.9375rem;
}

.qs-count-hint {
    font-size: 0.8rem;
    color: var(--text-secondary);
}

/* Grading step: mode toggle, then either a point target or a weight per
   confirmed assignment type. No AI call, this is the user's own decision. */
.qs-grading-card {
    flex-direction: column;
    align-items: stretch;
    gap: 12px;
}

.qs-grading-modes {
    display: flex;
    gap: 4px;
    background: var(--surface-sunk);
    border-radius: 8px;
    padding: 4px;
}

.qs-grading-mode {
    flex: 1;
    border: none;
    background: transparent;
    border-radius: 6px;
    padding: 7px 10px;
    font-family: inherit;
    font-size: 0.875rem;
    font-weight: 600;
    color: var(--text-secondary);
    cursor: pointer;
}

.qs-grading-mode:hover { color: var(--text-primary); }

.qs-grading-mode.is-active {
    background: var(--panel-bg);
    color: var(--primary-color);
    box-shadow: 0 1px 2px rgba(14, 42, 47, 0.12);
}

.qs-grading-target {
    display: flex;
    align-items: center;
    gap: 10px;
    font-size: 0.875rem;
    font-weight: 600;
    color: var(--text-primary);
}

.qs-grading-target input {
    width: 110px;
    padding: 6px 8px;
    border: 1px solid var(--border-color);
    border-radius: 6px;
    font-family: inherit;
    font-size: 0.9375rem;
}

.qs-grading-hint {
    margin: 0;
    font-size: 0.8rem;
    color: var(--text-secondary);
}

.qs-weight-rows {
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.qs-weight-row {
    display: flex;
    align-items: center;
    gap: 10px;
    font-size: 0.875rem;
}

.qs-weight-name {
    flex: 1;
    min-width: 0;
    color: var(--text-primary);
    overflow-wrap: anywhere;
}

.qs-weight-row input {
    width: 82px;
    padding: 5px 8px;
    border: 1px solid var(--border-color);
    border-radius: 6px;
    font-family: inherit;
    font-size: 0.9375rem;
    text-align: right;
}

.qs-weight-total {
    margin: 0;
    font-size: 0.85rem;
    font-weight: 600;
    color: var(--primary-color);
}

/* Off-100 is a validation state, not outcome coverage, danger red, never the
   amber reserved for CLLO/date semantics. */
.qs-weight-total.is-off { color: var(--danger-color); }

.qs-module-card {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    background: white;
    border: 1px solid var(--border-color);
    border-radius: 8px;
    padding: 10px 12px;
}

.qs-module-card input[type="checkbox"] {
    margin-top: 4px;
    flex-shrink: 0;
}

.qs-module-body {
    flex: 1;
    min-width: 0;
}

.qs-module-name,
.qs-module-topic {
    width: 100%;
    border: none;
    background: transparent;
    font-family: inherit;
    padding: 3px 2px;
}

.qs-module-name {
    font-weight: 600;
    font-size: 0.9375rem;
    color: var(--text-primary);
}

.qs-module-topic {
    font-size: 0.85rem;
    color: var(--text-secondary);
}

.qs-module-name:focus,
.qs-module-topic:focus {
    outline: 1px solid var(--primary-color);
    border-radius: 4px;
}

.qs-assignment-list {
    margin: 6px 0 0;
    padding-left: 18px;
    font-size: 0.8rem;
    color: var(--text-secondary);
}

.qs-assignment-list li {
    margin-bottom: 2px;
}

/* Quick Start entry modes, describe the course, or upload a syllabus. Two
   doors into the same staged pipeline, so they're tabs on one modal rather
   than two buttons on the dashboard. */
.qs-mode-tabs {
    display: flex;
    gap: 4px;
    background: var(--surface-sunk);
    border-radius: 8px;
    padding: 4px;
    margin-bottom: 14px;
}

.qs-mode-tab {
    flex: 1;
    border: none;
    background: transparent;
    border-radius: 6px;
    padding: 8px 10px;
    font-family: inherit;
    font-size: 0.875rem;
    font-weight: 600;
    color: var(--text-secondary);
    cursor: pointer;
}

.qs-mode-tab:hover {
    color: var(--text-primary);
}

.qs-mode-tab.is-active {
    background: var(--panel-bg);
    color: var(--primary-color);
    box-shadow: 0 1px 2px rgba(14, 42, 47, 0.12);
}

.qs-source-picker {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
    margin-bottom: 14px;
}

.qs-source-name {
    font-size: 0.85rem;
    color: var(--text-muted);
    min-width: 0;
    overflow-wrap: anywhere;
}

.qs-source-name.has-file {
    color: var(--text-primary);
    font-weight: 600;
}

/* Stage 0 of an import: the extraction report, plus the course identity and
   dates read out of the syllabus. Editable here because this step is also
   where the course is created. */
.qs-import-card {
    flex-direction: column;
    gap: 14px;
}

.qs-import-fields {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    width: 100%;
}

.qs-import-fields label {
    display: flex;
    flex-direction: column;
    gap: 4px;
    font-size: 0.75rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--text-secondary);
}

.qs-import-fields input {
    border: 1px solid var(--border-color);
    border-radius: 6px;
    padding: 6px 8px;
    font-family: inherit;
    font-size: 0.9375rem;
    color: var(--text-primary);
    text-transform: none;
    letter-spacing: normal;
    font-weight: 400;
}

.qs-import-fields input:focus {
    outline: 1px solid var(--primary-color);
}

.qs-import-field-narrow {
    width: 88px;
    flex-shrink: 0;
}

.qs-import-field-grow {
    flex: 1;
    min-width: 180px;
}

/* The import report. Deliberately teal and neutral only: green and amber mean
   CLLO coverage and date flags everywhere else in the app, and reusing them
   here as decoration would make "left behind" read as a coverage failure. */
.syllabus-report {
    width: 100%;
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.syllabus-report-section {
    border-left: 3px solid var(--border-color);
    padding-left: 12px;
}

.syllabus-report-section h4 {
    margin: 0 0 6px;
    font-size: 0.75rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--text-secondary);
}

.syllabus-report-section ul {
    margin: 0;
    padding-left: 18px;
    font-size: 0.85rem;
    line-height: 1.5;
    color: var(--text-secondary);
}

.syllabus-report-section li {
    margin-bottom: 4px;
}

.syllabus-report-section li strong {
    color: var(--text-primary);
}

.syllabus-report-section.is-captured {
    border-left-color: var(--primary-color);
}

.syllabus-report-section.is-captured h4 {
    color: var(--primary-color);
}

.syllabus-report-section.is-ambiguous {
    border-left-color: var(--brand-deep);
}

.syllabus-report-section.is-ambiguous h4 {
    color: var(--brand-deep);
}

.syllabus-report-section.is-omitted {
    border-left-color: var(--border-color);
    background: var(--surface-soft);
    padding: 8px 12px;
    border-radius: 0 6px 6px 0;
}

.syllabus-report-foot {
    margin: 0;
    font-size: 0.8rem;
    color: var(--text-muted);
}

#syllabusReportBody {
    max-height: 55vh;
    overflow-y: auto;
}

/* Course Basics footer note, present only on an imported course, and quiet
   enough not to read as another field. */
.syllabus-import-note {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
    margin-top: 4px;
    padding-top: 12px;
    border-top: 1px solid var(--border-soft);
    font-size: 0.8rem;
    color: var(--text-muted);
}

.th-optional {
    font-weight: 400;
    font-size: 11px;
    color: #777;
}

/* ============================================================
   INSTRUCTIONAL RESOURCES
   Course-level records; modules reference them by id. "Free / OER" is
   deliberately teal, NOT green, green and amber mean outcome coverage and
   date flags everywhere else, and a green "free" badge would read as a
   coverage state to anyone who has used the dashboard.
   ============================================================ */
.resource-group { margin-bottom: 20px; }
.resource-group:last-child { margin-bottom: 0; }

.resource-group-head {
    font-size: 0.66rem;
    font-weight: 700;
    letter-spacing: 0.09em;
    text-transform: uppercase;
    color: var(--text-muted);
    margin-bottom: 8px;
}

.resource-item {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    gap: 4px 14px;
    align-items: start;
    background: var(--panel-bg);
    border: 1px solid var(--border-color);
    border-radius: 9px;
    padding: 11px 14px;
    margin-bottom: 8px;
}

.resource-item:hover { border-color: var(--text-muted); }

.resource-title { font-size: 0.92rem; font-weight: 600; }
.resource-title a { color: inherit; text-decoration: none; border-bottom: 1px solid var(--border-color); }
.resource-title a:hover { color: var(--primary-color); border-bottom-color: var(--primary-color); }
.resource-by { font-size: 0.82rem; color: var(--text-secondary); margin-top: 1px; }
.resource-note {
    grid-column: 1 / -1;
    font-size: 0.79rem;
    color: var(--text-muted);
    margin-top: 4px;
}
.resource-note .resource-modules { color: var(--primary-color); font-weight: 600; }

.resource-right { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; justify-content: flex-end; }

.resource-mark {
    font-size: 0.66rem;
    font-weight: 700;
    letter-spacing: 0.04em;
    border-radius: 100px;
    padding: 2px 9px;
    white-space: nowrap;
}
.mark-required { background: var(--wash-brand); color: var(--brand-deep); }
.mark-optional { background: var(--surface-sunk); color: var(--text-muted); }
.mark-free {
    background: var(--panel-bg);
    color: var(--primary-color);
    border: 1px solid var(--primary-color);
}

.resource-orphan-note {
    margin-top: 14px;
    padding: 10px 14px;
    background: var(--surface-soft);
    border: 1px solid var(--border-soft);
    border-radius: 8px;
    font-size: 0.82rem;
    color: var(--text-muted);
}

/* ---- AI resource suggestions ---- */
.modal-wide .modal-content, .modal-content.modal-wide { max-width: 720px; }

.ai-res-status { margin-bottom: 12px; }

.ai-res-warn {
    display: flex;
    gap: 10px;
    align-items: flex-start;
    background: var(--wash-warn);
    border-radius: 8px;
    padding: 11px 14px;
    font-size: 0.83rem;
    color: var(--text-primary);
    margin-bottom: 14px;
}
.ai-res-warn b { color: var(--warning-color); }

.ai-res-card {
    display: grid;
    grid-template-columns: 20px minmax(0, 1fr) auto;
    gap: 4px 12px;
    align-items: start;
    border: 1px solid var(--border-color);
    border-radius: 9px;
    padding: 11px 13px;
    margin-bottom: 8px;
}

.ai-res-card input[type="checkbox"] {
    width: 15px;
    height: 15px;
    margin: 3px 0 0;
    accent-color: var(--primary-color);
}

.ai-res-title { font-size: 0.92rem; font-weight: 600; }
.ai-res-by { font-size: 0.82rem; color: var(--text-secondary); margin-top: 1px; }
.ai-res-why {
    grid-column: 2 / -1;
    font-size: 0.81rem;
    color: var(--text-muted);
    margin-top: 5px;
}
.ai-res-why b { color: var(--brand-deep); font-weight: 700; }

/* A suggestion that names no specific work is a FEATURE, not a failure, it is
   what the model returns instead of inventing a title to fill a field. */
.ai-res-generic {
    grid-column: 2 / -1;
    margin-top: 8px;
    padding: 9px 12px;
    background: var(--surface-soft);
    border: 1px dashed var(--border-color);
    border-radius: 7px;
    font-size: 0.79rem;
    color: var(--text-secondary);
}
.ai-res-generic b { color: var(--text-primary); }

.ai-res-count {
    font-size: 0.83rem;
    font-weight: 600;
    color: var(--text-secondary);
    margin-right: auto;
}

.ai-res-empty { padding: 20px 0; text-align: center; color: var(--text-muted); font-size: 0.9rem; }

/* Module's resources in the Course Schedule Report (and its PDF, which reuses
   this same markup, see buildPdfPrintHtml). */
.report-module-resources {
    margin: 4px 0 0;
    font-family: 'Helvetica Neue', Arial, sans-serif;
    font-size: 0.78rem;
    color: var(--report-ink);
}
.report-module-resources strong { color: var(--report-accent); }

/* "Find this" is an <a> so it opens a real search the user initiates, the app
   never fabricates a direct link. It still has to read as a button. */
a.btn {
    text-decoration: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}

/* A long suggestion list must scroll inside the modal rather than run off the
   bottom of a laptop screen. */
#aiResourceModal .modal-content {
    max-height: 88vh;
    display: flex;
    flex-direction: column;
}
#aiResourceModal #aiResourceBody {
    overflow-y: auto;
    min-height: 0;
}

/* Weight total that doesn't add to 100%, amber is correct here, it's the same
   "this blocks you" meaning the Assignment Types Summary total row carries. */
.rail-foot-warn { color: var(--warning-color); }

/* No disabled styling existed anywhere in the app. It was masked on the Section
   Assist commit bar by the button's own label carrying the state ("Apply 0
   Changes"); now that the label is always "Accept Changes", nothing else says
   the button is inert. Applies app-wide, which every other disabled control
   here wanted too. */
.btn:disabled,
.btn[disabled] {
    opacity: 0.45;
    cursor: not-allowed;
    box-shadow: none;
}

.btn:disabled:hover,
.btn[disabled]:hover {
    filter: none;
}

/* ============================================
   ASSIGNMENT INSTRUCTIONS
   ============================================ */

/* The Instructions button sits left, away from Cancel/Save, it opens another
   surface rather than resolving this one. */
.modal-actions-gap {
    flex: 1;
}

.stage-toggle {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    font-size: 13px;
    color: var(--text-secondary);
    cursor: pointer;
    user-select: none;
}

.stage-toggle input {
    width: auto;
    margin: 0;
    cursor: pointer;
}

/* ---- the full-canvas sheet ---- */

/* An overlay over the editor, not a fourth top-level view, one assignment's
   instructions are not a view of the app, and showView() decides what's visible
   from auth state alone. */
.instr-sheet {
    position: fixed;
    inset: 0;
    z-index: 900;
    background: var(--background);
    overflow-y: auto;
}

.instr-sheet.hidden {
    display: none;
}

.instr-sheet-inner {
    max-width: 1120px;
    margin: 0 auto;
    padding: 24px 20px 80px;
}

.instr-sheet-head {
    display: flex;
    flex-wrap: wrap;
    gap: 16px;
    align-items: flex-start;
    justify-content: space-between;
    padding-bottom: 18px;
    margin-bottom: 20px;
    border-bottom: 1px solid var(--border-color);
}

.instr-head-main {
    min-width: 0;
    flex: 1 1 320px;
}

.instr-eyebrow {
    font-size: 11px;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    font-weight: 600;
    color: var(--primary-color);
    margin: 0 0 4px;
}

.instr-sheet-head h2 {
    font-size: 24px;
    margin: 0 0 10px;
    color: var(--text-primary);
    line-height: 1.25;
}

.instr-head-actions {
    display: flex;
    gap: 8px;
    flex-wrap: wrap;
    align-items: center;
}

/* Rendered from the schema. Chips rather than sentences on purpose: the
   instructions reference these values, and a chip reads as a stored field in a
   way a sentence does not. */
.instr-meta {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    list-style: none;
    padding: 0;
    margin: 0;
}

.instr-meta li {
    font-size: 12px;
    background: var(--wash-brand);
    color: var(--text-secondary);
    border: 1px solid var(--border-soft);
    border-radius: 999px;
    padding: 3px 10px;
}

.instr-meta li b {
    color: var(--text-primary);
    font-weight: 600;
}

/* The two AI paths, grouped so the difference between them is visible and the
   note field is visibly attached to the one that reads it. */
.instr-ai {
    display: flex;
    flex-direction: column;
    background: var(--surface-soft);
    border: 1px solid var(--border-soft);
    border-radius: 8px;
    margin-bottom: 20px;
    overflow: hidden;
}

.instr-ai-row {
    display: flex;
    gap: 14px;
    align-items: flex-start;
    padding: 14px 16px;
}

.instr-ai-row:not(.hidden) + .instr-ai-row:not(.hidden) {
    border-top: 1px solid var(--border-soft);
}

/* One column width for both rows, so the explanations line up rather than
   stepping in and out with each button's label length. */
.instr-ai-row > .btn {
    flex: none;
    white-space: nowrap;
    min-width: 152px;
}

.instr-ai-side {
    display: flex;
    flex-direction: column;
    gap: 6px;
    min-width: 0;
    flex: 1;
}

.instr-ai-help {
    margin: 0;
    font-size: 13px;
    line-height: 1.5;
    color: var(--text-secondary);
    max-width: 68ch;
}

.instr-ai-side label {
    font-size: 12px;
    font-weight: 600;
    color: var(--text-secondary);
}

.instr-ai-side label span {
    font-weight: normal;
    color: var(--text-muted);
}

.instr-ai-side input[type="text"] {
    background: var(--panel-bg);
}

@media (max-width: 640px) {
    .instr-ai-row {
        flex-direction: column;
        gap: 10px;
    }
}

.instr-status:not(:empty) {
    margin-bottom: 16px;
}

/* ---- the brief + spec panel layout ---- */

.instr-cols {
    display: grid;
    grid-template-columns: 1fr;
    gap: 20px;
    align-items: start;
}

@media (min-width: 860px) {
    .instr-cols {
        grid-template-columns: 1.55fr 1fr;
    }
}

.instr-main,
.instr-spec {
    display: flex;
    flex-direction: column;
    gap: 18px;
    min-width: 0;
}

/* The panel is what a student re-checks before submitting, sunk rather than
   raised, so it reads as a reference beside the brief and not as a second
   document competing with it. */
.instr-spec {
    background: var(--surface-soft);
    border: 1px solid var(--border-soft);
    border-radius: 8px;
    padding: 16px 18px;
}

.instr-doc {
    background: var(--panel-bg);
    border: 1px solid var(--border-color);
    border-radius: 8px;
    padding: 22px 24px 26px;
}

.instr-sec-h {
    font-size: 11px;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    font-weight: 700;
    color: var(--primary-color);
    margin: 0 0 7px;
}

.instr-prose {
    margin: 0;
    color: var(--text-secondary);
    line-height: 1.6;
}

.instr-list {
    margin: 0;
    padding-left: 20px;
    color: var(--text-secondary);
}

.instr-list li {
    margin-bottom: 6px;
    line-height: 1.55;
}

.instr-list li:last-child {
    margin-bottom: 0;
}

.instr-sec {
    margin-bottom: 18px;
}

.instr-sec:last-child {
    margin-bottom: 0;
}

/* Derived from clloIds, never written, tinted so it reads as a record the app
   is showing rather than prose someone typed. Teal, not green: green and amber
   mean outcome coverage and date flags app-wide. */
.instr-derived {
    background: var(--wash-brand);
    border-left: 3px solid var(--primary-color);
    border-radius: 0 6px 6px 0;
    padding: 11px 13px;
}

.instr-derived ul {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 7px;
}

.instr-derived li {
    display: flex;
    gap: 9px;
    font-size: 14px;
    color: var(--text-secondary);
    line-height: 1.5;
}

.instr-derived-num {
    font-size: 11px;
    font-weight: 700;
    color: var(--primary-color);
    white-space: nowrap;
    padding-top: 2px;
}

.instr-derived-tag {
    font-size: 10.5px;
    color: var(--text-muted);
    font-weight: normal;
    text-transform: none;
    letter-spacing: 0;
}

/* ---- the editors ---- */

.instr-edit-sec {
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.instr-cols-edit .instr-main > .instr-edit-sec,
.instr-cols-edit .instr-spec > .instr-edit-sec {
    background: var(--panel-bg);
    border: 1px solid var(--border-color);
    border-radius: 8px;
    padding: 14px 16px;
}

.instr-cols-edit .instr-spec > .instr-edit-sec {
    border-color: var(--border-soft);
}

.instr-edit-sec.is-derived {
    background: var(--surface-soft);
}

.instr-edit-head {
    display: flex;
    align-items: center;
    gap: 8px;
}

.instr-edit-head .instr-sec-h {
    margin: 0;
}

.instr-edit-gap {
    flex: 1;
}

/* An edited section is marked because the mark is what protects it: a
   regenerate skips it unless the user says otherwise. */
.instr-edited-mark {
    font-size: 10px;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    font-weight: 600;
    color: var(--text-secondary);
    background: var(--surface-sunk);
    border-radius: 999px;
    padding: 2px 8px;
}

.instr-input {
    width: 100%;
    font-family: inherit;
    font-size: 14px;
    line-height: 1.55;
    color: var(--text-primary);
    background: var(--panel-bg);
    border: 1px solid var(--border-color);
    border-radius: 6px;
    padding: 9px 11px;
    resize: none;
    overflow: hidden;
}

.instr-input:focus {
    outline: none;
    border-color: var(--primary-color);
    box-shadow: 0 0 0 3px var(--wash-brand);
}

.instr-hint {
    margin: 0;
    font-size: 12px;
    color: var(--text-muted);
    line-height: 1.45;
}

/* An assignment that already has instructions, the same teal the AI controls
   use, so the row reads as "there is more here" at a glance. */
.assignment-actions .btn-icon.has-instructions {
    color: var(--primary-color);
    position: relative;
}

/* Colour alone was carrying this, on one of four identical icon buttons, so it
   was easy to miss when scanning a module and invisible to anyone who does not
   separate the two shades. The dot adds a second, non-colour cue. The button's
   own title attribute already differs, which is what carries it to a screen
   reader. */
.assignment-actions .btn-icon.has-instructions::after {
    content: '';
    position: absolute;
    top: 3px;
    right: 3px;
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--primary-color);
}

/* ---- the condensed form, in the Course Schedule Report and its PDF ---- */

.report-instructions {
    /* .report-assignment-item is a wrapping flex row (name left, meta right);
       the instructions are a third child that must take the whole next line
       rather than squeezing in beside them. */
    flex: 0 0 100%;
    margin-top: 8px;
    padding: 8px 10px;
    background: var(--report-accent-soft);
    border-radius: 5px;
}

.report-instr-label {
    display: block;
    font-size: 10px;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    font-weight: 700;
    color: var(--report-accent);
    margin-bottom: 5px;
}

.report-instr-steps {
    margin: 0;
    padding-left: 18px;
    font-size: 12.5px;
    color: var(--report-ink);
}

.report-instr-steps li {
    margin-bottom: 3px;
    line-height: 1.45;
}

.report-instr-reqs {
    margin: 6px 0 0;
    font-size: 12px;
    color: var(--report-muted);
    line-height: 1.45;
}

.report-instr-reqs span {
    font-weight: 600;
    color: var(--report-ink);
}

/* Says what Regenerate will leave alone, before it runs rather than after. */
.instr-protected {
    margin: 0;
    font-size: 12.5px;
    color: var(--text-secondary);
    background: var(--surface-soft);
    border-left: 3px solid var(--border-color);
    border-radius: 0 5px 5px 0;
    padding: 8px 12px;
}

/* Beta access screen (admin only). */
.admin-panel {
    background: var(--panel-bg);
    border: 1px solid var(--border-color);
    border-radius: 12px;
    padding: 20px 22px;
    max-width: 560px;
}

.allowlist-add { display: flex; gap: 8px; margin-bottom: 4px; }
.allowlist-add input { flex: 1; }

.allowlist-list { margin-top: 14px; }

.allowlist-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 9px 0;
    border-bottom: 1px solid var(--border-soft);
}
.allowlist-row:last-child { border-bottom: 0; }
.allowlist-email { font-size: 0.9rem; }

/* Admin dashboard: roster, access, per-user limits, real spend. */
.admin-panel { max-width: 900px; }

.admin-summary {
    display: flex;
    gap: 22px;
    flex-wrap: wrap;
    margin: 18px 0 14px;
    padding-bottom: 14px;
    border-bottom: 1px solid var(--border-color);
}
.admin-stat { display: flex; flex-direction: column; gap: 2px; }
.admin-stat b { font-size: 1.3rem; font-weight: 700; font-variant-numeric: tabular-nums; }
.admin-stat span {
    font-size: 0.68rem;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--text-muted);
}

.admin-table-wrap { overflow-x: auto; }
.admin-table { width: 100%; border-collapse: collapse; font-size: 0.86rem; min-width: 620px; }
.admin-table th {
    text-align: left;
    font-size: 0.66rem;
    font-weight: 700;
    letter-spacing: 0.07em;
    text-transform: uppercase;
    color: var(--text-muted);
    padding: 0 10px 8px;
    border-bottom: 1px solid var(--border-color);
}
.admin-table td { padding: 10px; border-bottom: 1px solid var(--border-soft); vertical-align: middle; }
.admin-table tr:last-child td { border-bottom: 0; }
.admin-table .num { text-align: right; font-variant-numeric: tabular-nums; }
.admin-email { font-weight: 600; }
.admin-email small { display: block; font-weight: 400; color: var(--text-muted); font-size: 0.76rem; }

.admin-limit-input {
    width: 74px;
    padding: 5px 8px;
    font-size: 0.84rem;
    text-align: right;
    border: 1px solid var(--border-color);
    border-radius: 6px;
    background: var(--panel-bg);
    color: var(--text-primary);
    font-variant-numeric: tabular-nums;
}
.admin-limit-input:disabled { opacity: 0.4; }

/* Spend bar. Teal and neutrals only: green and amber mean outcome coverage and
   date flags app-wide, and the danger colour is reserved for a spent account. */
.admin-bar {
    width: 90px;
    height: 5px;
    border-radius: 100px;
    background: var(--surface-sunk);
    overflow: hidden;
    margin: 4px 0 0 auto;
}
.admin-bar i { display: block; height: 100%; background: var(--primary-color); border-radius: 100px; }
.admin-bar.is-spent i { background: var(--danger-color); }

.admin-access-btn { white-space: nowrap; }
.admin-foot { margin-top: 16px; }

/* An AI control the account isn't invited to use. Muted rather than hidden, so
   a beta tester can see the feature exists and ask for access. */
.btn-ai:disabled,
.btn-icon-ai:disabled {
    opacity: 0.4;
    cursor: not-allowed;
    border-style: dashed;
}
.btn-ai:disabled:hover,
.btn-icon-ai:disabled:hover {
    background: transparent;
    border-color: var(--border-color);
    color: var(--text-muted);
}
[data-ai-control]:disabled { opacity: 0.4; cursor: not-allowed; }

/* An AI control that's clickable but points at the beta-access dialog rather
   than the real feature. Distinct from .btn-ai:disabled above: this one is
   NOT disabled, so it stays keyboard/screen-reader reachable. */
.btn-ai.is-ai-locked,
.btn-icon-ai.is-ai-locked,
[data-ai-control].is-ai-locked {
    opacity: 0.55;
    border-style: dashed;
}
.btn-ai.is-ai-locked:hover,
.btn-icon-ai.is-ai-locked:hover,
[data-ai-control].is-ai-locked:hover {
    opacity: 0.85;
}

/* Same quiet footnote treatment as "Import a course", so a rarely-used
   destructive action doesn't stand out and invite an accidental click.
   The confirm dialog is what carries the actual warning; only the hover
   tint hints at what it does. */
.btn-footnote-danger:hover {
    color: var(--danger-color);
    border-color: var(--danger-color);
}

/* Pending course-share invitations on the dashboard. Distinct from the
   course grid below it: this is something to act on, not browse. */
.pending-shares {
    margin-bottom: 20px;
}

.pending-shares-head {
    font-size: 0.8rem;
    font-weight: 600;
    letter-spacing: 0.03em;
    text-transform: uppercase;
    color: var(--text-muted);
    margin: 0 0 8px;
}

.pending-share-card {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    background: var(--wash-brand);
    border: 1px solid var(--primary-color);
    border-radius: 10px;
    padding: 12px 16px;
    margin-bottom: 8px;
}

.pending-share-from {
    color: var(--text-muted);
    font-size: 0.85rem;
    margin-left: 8px;
}

.pending-share-actions {
    display: flex;
    gap: 8px;
    flex-shrink: 0;
}
