/* Jazzmin replaces Django's own admin base template/theme, so the CSS
   variables Django's static/admin/css/autocomplete.css relies on for the
   select2 autocomplete widget (border, background, text colors) are never
   defined anywhere in Jazzmin pages. That leaves every `autocomplete_fields`
   widget (e.g. FAQ/PhotoGalleryImage "category") transparent and borderless.
   Values below are Django's own light-theme defaults from admin/css/base.css. */
:root {
    --body-fg: #333;
    --body-bg: #fff;
    --body-quiet-color: #666;
    --border-color: #ccc;
    --darkened-bg: #f8f8f8;
}

/* jazzmin/css/main.css ships in venv without its "modal tweaks" block (its
   own main.css.backup alongside it still has them), so the related-object
   add/change/delete popups (an <iframe class="related-iframe"> in a
   .modal-wide) render with no explicit size — a cramped, mostly-empty modal.
   Restoring the sizing here since the vendor file itself isn't project-owned. */
.modal.modal-wide .modal-dialog {
    width: 50%;
    max-width: inherit;
}

.modal-wide .modal-body {
    overflow-y: auto;
}

iframe.related-iframe {
    width: 100%;
    height: 450px;
}

/* Jazzmin admin overrides.
   Django's bare text/url/slug inputs render at the browser's default
   ~20-character width regardless of the column they sit in, so change-form
   fields look squeezed into a narrow box even though their grid column is
   wide. Stretch them (and selects/textareas) to fill that column. */
.change-form .vTextField,
.change-form .vLargeTextField,
.change-form .vURLField,
.change-form select:not([multiple]),
.change-form textarea {
    width: 100%;
    max-width: 100%;
}

/* CKEditor 5 fields (e.g. Pages "Body"): the label/field row is a Bootstrap
   grid with the label at col-sm-3 and the field at col-sm-9, so the editor
   only ever gets 75% of the fieldset width. Stack the label above the
   editor instead so the editor can use the full width. */
.change-form .form-group .row:has(.ck-editor-container) > label.col-sm-3,
.change-form .form-group .row:has(.ck-editor-container) > .col-sm-9 {
    flex: 0 0 100%;
    max-width: 100%;
}

/* Fallback keyed on the field name for browsers without :has() support. */
.change-form .form-group.field-body > .row > label.col-sm-3,
.change-form .form-group.field-body > .row > .col-sm-9 {
    flex: 0 0 100%;
    max-width: 100%;
}

/* The submit/actions sidebar only ever holds a few buttons, so give the
   fieldset column more of the page and shrink the sidebar to match. */
@media (min-width: 992px) {
    .change-form #content-main > form > .row > .col-lg-9 {
        flex: 0 0 82%;
        max-width: 82%;
    }

    .change-form #content-main > form > .row > .col-lg-3 {
        flex: 0 0 18%;
        max-width: 18%;
    }
}

/* ====================================================================
   DFA Style Guide v5 theme
   Tokens copied from https://styleguide.dataforall.org/v5/about.html
   (assets/css/dfa_style.css :root block) — kept as the single source of
   truth so a guide update just means re-copying the six hex values below.
   ==================================================================== */
:root {
    --dfa-primary: #983365;
    --dfa-secondary: #6B1B43;
    --dfa-text: #333333;
    --dfa-text-secondary: #888888;
    --dfa-border: #EAEAEA;
    --dfa-border-secondary: #f1f1f1;
    --dfa-hover-bg: #F2EBEE;
    --dfa-success: #5CB85C;
    --dfa-warning: #EF9F38;
    --dfa-error: #B84242;
    --dfa-info: #2F79C3;
    --dfa-font: 'Helvetica Neue', Arial, sans-serif;
}

body,
.wrapper,
.card,
.modal-content {
    font-family: var(--dfa-font);
    color: var(--dfa-text);
}

/* ---- Top header bar (DFA: solid primary background, white text) ----
   Jazzmin 3.x renders this as <nav class="app-header ... bg-body navbar-primary ...">,
   not the AdminLTE-3-era ".main-header" this project's CSS originally targeted —
   ".bg-body" (Bootstrap 5 utility, white) was winning the cascade over
   ".navbar-primary" and left the whole band white with invisible white-on-white
   icons/user menu. Target the real element instead. */
.app-header.navbar-primary {
    background-color: var(--dfa-primary) !important;
}

.app-header .nav-link {
    color: rgba(255, 255, 255, 0.9);
}

.app-header .nav-link:hover,
.app-header .nav-link:focus {
    color: #ffffff;
}

.app-header .dropdown-menu {
    color: var(--dfa-text);
}

/* Username label injected next to the top navbar's user icon by
   admin_actions.js — Jazzmin's own markup only puts the username in that
   icon's title tooltip, not as visible text. */
.dfa-navbar-username {
    margin-left: 6px;
    font-size: .85rem;
    color: rgba(255, 255, 255, 0.9);
    vertical-align: middle;
}

@media (max-width: 575.98px) {
    .dfa-navbar-username {
        display: none;
    }
}

/* ---- Sidebar brand strip (logo area, DFA: white, bordered) ---- */
.brand-link {
    background-color: #ffffff !important;
    border-bottom: 1px solid var(--dfa-border) !important;
}

.brand-link .brand-text {
    color: var(--dfa-primary) !important;
    font-weight: 600;
}

.brand-image {
    max-height: 33px !important;
}

/* ---- Sidebar body (DFA: white background, bordered, bold nav text) ----
   Same Jazzmin 3.x rename as the header above: the sidebar element is
   <aside class="app-sidebar ..." data-bs-theme="dark">, not ".main-sidebar",
   and its nav list is <ul class="nav sidebar-menu">, not ".nav-sidebar" —
   so none of this actually matched and the sidebar fell back to Bootstrap's
   dark-mode default background/text instead of the DFA white sidebar. */
.app-sidebar {
    /* Bootstrap's own ".bg-body-secondary" utility (also on this element) ships
       !important, so a plain background-color here loses the cascade tie. */
    background-color: #ffffff !important;
    border-right: 1px solid var(--dfa-border);
}

/* Sidebar's own username block (avatar + "indranisbhaduri" above Dashboard) —
   now shown in the top navbar instead (see .dfa-navbar-username), so drop
   the duplicate here rather than showing the same name in two places.
   The element also carries Bootstrap's ".d-flex" utility, which ships
   "display: flex !important" — a plain display:none here loses that
   cascade tie, so it needs !important too. */
.app-sidebar .user-panel {
    display: none !important;
}

/* ---- Sidebar version label, pinned bottom-left of the nav panel ----
   AdminLTE sizes .sidebar-wrapper at calc(100vh - header height), so the aside
   is already full height with no room left under the menu. Making the aside a
   flex column lets the wrapper take whatever space is left and pins the last
   child to the bottom.

   That last child is normally .sidebar-version — a real <a> linking to the
   version log page, injected into the aside by the sidebar block in
   templates/admin/base_site.html (Jazzmin's sidebar markup has no block or
   include to hang an element off, and .app-wrapper is a CSS grid with named
   areas, so a <div> appended after the aside would land as an unplaced grid
   item). Without JS no anchor is created, and the ::after pseudo-element below
   still renders the version as plain text from the custom properties that same
   template sets. .has-version-link — added by that script — is what keeps the
   two from showing at once. */
.app-sidebar {
    display: flex;
    flex-direction: column;
}

.app-sidebar .sidebar-brand {
    flex: 0 0 auto;
}

/* Two classes' worth of specificity, to outrank AdminLTE's several
   media-query copies of ".sidebar-wrapper { height: calc(100vh - ...) }". */
.app-sidebar .sidebar-wrapper {
    flex: 1 1 auto;
    height: auto;
    min-height: 0;
}

.app-sidebar::after,
.sidebar-version {
    flex: 0 0 auto;
    padding: .5rem .75rem;
    font-size: .75rem;
    font-weight: 600;
    color: var(--dfa-text-secondary);
    border-top: 1px solid var(--dfa-border);
    white-space: nowrap;
    overflow: hidden;
}

.app-sidebar::after {
    content: var(--dfa-admin-version, "");
}

/* The link replaces the fallback label rather than sitting under it. */
.app-sidebar.has-version-link::after {
    content: none;
}

.sidebar-version {
    display: block;
    text-decoration: none;
}

/* Same hover treatment as the sidebar menu items below, so the label reads as
   part of the same navigation rather than as decoration that happens to move. */
.sidebar-version:hover,
.sidebar-version:focus-visible {
    color: var(--dfa-primary);
    background-color: var(--dfa-hover-bg);
    text-decoration: none;
}

.sidebar-version__short {
    display: none;
}

/* Collapsed (icon-only) sidebar is 4.6rem wide — show the short form centred
   rather than clipping "Version 2.0.1" mid-word. */
.sidebar-collapse .app-sidebar::after {
    content: var(--dfa-admin-version-short, "");
}

.sidebar-collapse .app-sidebar::after,
.sidebar-collapse .sidebar-version {
    padding-right: .25rem;
    padding-left: .25rem;
    text-align: center;
}

.sidebar-collapse .sidebar-version__full {
    display: none;
}

.sidebar-collapse .sidebar-version__short {
    display: inline;
}

.sidebar-menu > .nav-item > .nav-link,
.sidebar-menu .nav-treeview > .nav-item > .nav-link {
    color: var(--dfa-text);
    font-weight: 700;
}

.sidebar-menu .nav-link:hover,
.sidebar-menu .nav-link.active {
    color: var(--dfa-primary) !important;
    background-color: var(--dfa-hover-bg) !important;
}

/* Sidebar section headers ("Home", "Board infos", "FAQs", ...) — Jazzmin
   renders these as <li class="nav-header"> inside ul.sidebar-menu (not
   .nav-sidebar as the class name might suggest). app-sidebar.scss sets
   font-weight on this exact selector, so match its specificity. Leave
   color untouched — the same markup is reused for the collapsed sidebar's
   dark hover flyout, and a fixed dark color would go invisible there. */
.sidebar-menu .nav-header {
    font-weight: 700 !important;
}

.sidebar-menu .nav-link.active i,
.sidebar-menu .nav-link.active p,
.sidebar-menu .nav-link:hover i,
.sidebar-menu .nav-link:hover p {
    color: var(--dfa-primary) !important;
}

.sidebar-search .form-control-sidebar {
    border: 1px solid var(--dfa-border);
}

/* ---- Change-form horizontal tabs (General/Content/Advanced) ---- */
.nav-tabs .nav-link {
    color: var(--dfa-text-secondary);
}

.nav-tabs .nav-link:hover {
    color: var(--dfa-primary);
}

.nav-tabs .nav-link.active {
    color: var(--dfa-primary) !important;
    border-bottom-color: #ffffff;
}

/* ---- Change-form fieldsets: card, tabs, rows, roles ----
   Jazzmin's own change_form.html wraps every fieldset in a bare, unstyled
   <div class="card"> and renders Django's raw fieldset/form-row markup as-is
   — none of jazzmin/main.css's Bootstrap restyling reaches this (main.css
   only touches Django's own widget classes like .vTextField, not the
   surrounding label/row/help markup). Worst hit: the User add form, whose
   custom CMS/LMS-role fields (apps/core/admin.py CmsLmsRoleFormMixin) are
   CheckboxSelectMultiple widgets that render as a bare stack of
   <div><label><input></div> with no layout at all. */
.change-form .col-lg-9 > .card {
    border: 1px solid var(--dfa-border);
    border-top: 3px solid var(--dfa-primary);
    border-radius: 8px;
    box-shadow: 0 1px 3px rgba(0, 0, 0, .06);
}

.change-form .card-body {
    padding: 1.75rem 2rem;
}

/* Intro line above the tabs on the add-user form only (admin/auth/user/
   add_form.html's form_top block) — boxed as a hint, matching the field
   help boxes below, instead of floating centred text. */
.change-form #content-main > form > p.text-center {
    text-align: left !important;
    padding: .65rem 1rem;
    margin: 0 0 1.25rem;
    background: var(--dfa-border-secondary);
    border-left: 3px solid var(--dfa-info);
    border-radius: 4px;
    color: var(--dfa-text-secondary);
    font-size: .85rem;
}

/* Tabs: a clearer segmented strip that reads as part of the card below it,
   on top of the text-colour rules above. */
.change-form #jazzy-tabs.nav-tabs {
    border-bottom: 2px solid var(--dfa-border);
    gap: .25rem;
}

.change-form #jazzy-tabs .nav-link {
    padding: .6rem 1.1rem;
    font-weight: 600;
    font-size: .85rem;
    border: none;
    border-bottom: 2px solid transparent;
    margin-bottom: -2px;
    border-radius: 0;
}

.change-form #jazzy-tabs .nav-link:hover {
    background-color: var(--dfa-hover-bg);
}

.change-form #jazzy-tabs .nav-link.active {
    border-bottom-color: var(--dfa-primary);
    background: none;
}

.change-form fieldset.module {
    border: none;
    padding: 0;
    margin: 0;
}

.change-form .form-row {
    padding: 0 0 1.1rem;
    margin-bottom: 1.1rem;
    border-bottom: 1px solid var(--dfa-border-secondary);
}

.change-form .tab-pane .form-row:last-child {
    border-bottom: none;
    margin-bottom: 0;
    padding-bottom: 0;
}

.change-form .form-row .flex-container > label {
    display: block;
    margin-bottom: .4rem;
    font-weight: 600;
    font-size: .8rem;
    color: var(--dfa-text);
}

/* Help text (password rules, "Required. 150 characters..." etc.) — boxed as
   a hint instead of bare floating text/bullets. */
.change-form .form-row .help > div {
    padding: .6rem .9rem;
    margin-top: .3rem;
    background: var(--dfa-border-secondary);
    border-left: 3px solid var(--dfa-info);
    border-radius: 4px;
    font-size: .78rem;
    color: var(--dfa-text-secondary);
}

.change-form .form-row .help ul {
    margin: 0;
    padding-left: 1.1rem;
}

.change-form .form-row .help li {
    margin-bottom: .2rem;
}

/* Password-based-authentication radio (django.contrib.auth.forms's
   usable_password field, widget attrs class="radiolist") — a bare vertical
   div stack by default; laid out as a segmented toggle instead. */
.change-form .radiolist {
    display: flex;
    gap: .6rem;
    margin-top: .2rem;
}

.change-form .radiolist > div {
    margin: 0;
}

.change-form .radiolist label {
    display: flex;
    align-items: center;
    gap: .4rem;
    padding: .45rem .9rem;
    border: 1px solid var(--dfa-border);
    border-radius: 20px;
    font-weight: 500;
    font-size: .82rem;
    color: var(--dfa-text-secondary);
    cursor: pointer;
    transition: all .12s ease-in-out;
}

.change-form .radiolist label:hover {
    border-color: var(--dfa-primary);
    color: var(--dfa-primary);
}

.change-form .radiolist label:has(input:checked) {
    border-color: var(--dfa-primary);
    background: var(--dfa-hover-bg);
    color: var(--dfa-primary);
}

.change-form .radiolist input[type="radio"] {
    accent-color: var(--dfa-primary);
    margin: 0;
}

/* Password fields (UserCreationForm's password1/password2) are plain form
   fields, not model fields, so ModelAdmin never gives them the vTextField
   class the username field gets — leaving them at the browser's cramped
   default input width/height. Match the rest of the form. */
.change-form input[type="password"] {
    width: 100%;
    max-width: 100%;
    height: calc(2.25rem + 2px);
    padding: .375rem .75rem;
    border: 1px solid var(--dfa-border);
    border-radius: .375rem;
}

.change-form input[type="password"]:focus {
    border-color: var(--dfa-text-secondary);
    outline: 0;
    box-shadow: none;
}

/* CMS/LMS role checkboxes (apps/core/admin.py CmsLmsRoleFormMixin's
   site_roles/cms_roles/lms_roles, all CheckboxSelectMultiple) — Django's
   widget template gives each option its own bare <div><label><input></div>
   with no wrapper class beyond the field's own id, rendering as a plain
   vertical stack of checkboxes. Laid out as a card grid instead.

   Each label now carries two lines (RoleChoiceField.label_from_instance
   emits a .role-name and a .role-help), so the label is a 2-column grid —
   checkbox in its own gutter, both text lines stacked beside it — rather
   than the single-line flex row this held when the label was just a name.
   A Group outside the catalogue has no description and so renders as a bare
   text node, which auto-places into the same cell .role-name would occupy. */
.change-form #id_site_roles,
.change-form #id_cms_roles,
.change-form #id_lms_roles {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(270px, 100%), 1fr));
    gap: .5rem;
    margin-top: .3rem;
    max-width: 960px;
}

.change-form #id_site_roles > div,
.change-form #id_cms_roles > div,
.change-form #id_lms_roles > div {
    margin: 0;
}

.change-form #id_site_roles label,
.change-form #id_cms_roles label,
.change-form #id_lms_roles label {
    display: grid;
    grid-template-columns: 16px 1fr;
    column-gap: .55rem;
    align-items: start;
    height: 100%;
    padding: .6rem .8rem;
    border: 1px solid var(--dfa-border);
    border-radius: 6px;
    font-size: .82rem;
    font-weight: 500;
    color: var(--dfa-text);
    cursor: pointer;
    background: #ffffff;
    transition: all .12s ease-in-out;
}

.change-form #id_site_roles label:hover,
.change-form #id_cms_roles label:hover,
.change-form #id_lms_roles label:hover {
    border-color: var(--dfa-primary);
    background: var(--dfa-hover-bg);
}

.change-form #id_site_roles label:has(input:checked),
.change-form #id_cms_roles label:has(input:checked),
.change-form #id_lms_roles label:has(input:checked) {
    border-color: var(--dfa-primary);
    background: var(--dfa-hover-bg);
}

.change-form #id_site_roles input[type="checkbox"],
.change-form #id_cms_roles input[type="checkbox"],
.change-form #id_lms_roles input[type="checkbox"] {
    accent-color: var(--dfa-primary);
    width: 15px;
    height: 15px;
    margin-top: 2px;
    grid-column: 1;
    grid-row: 1;
    flex-shrink: 0;
}

.change-form .role-name {
    grid-column: 2;
    grid-row: 1;
    font-weight: 600;
}

.change-form label:has(input:checked) .role-name {
    color: var(--dfa-primary);
}

/* The description line is the whole point of the wider card: it must wrap
   freely rather than force the grid column wider (min-width:0 — a grid item
   defaults to min-content, which a long sentence would blow out). */
.change-form .role-help {
    grid-column: 2;
    grid-row: 2;
    min-width: 0;
    margin-top: 3px;
    font-size: 11.5px;
    line-height: 1.45;
    font-weight: 400;
    color: var(--dfa-text-secondary);
    overflow-wrap: anywhere;
}

/* ---- Role pills ----
   Used by the User changelist's Roles/Access columns and by the bulk
   "Change role" confirmation list, neither of which is inside .change-form. */
.role-tag {
    display: inline-block;
    margin: 1px 2px 1px 0;
    padding: 1px 8px;
    border-radius: 10px;
    background: var(--dfa-hover-bg);
    border: 1px solid var(--dfa-border);
    color: var(--dfa-secondary);
    font-size: 11px;
    line-height: 1.7;
    white-space: nowrap;
}

.role-tag--none {
    background: transparent;
    border-color: transparent;
    color: var(--dfa-text-secondary);
    font-style: italic;
}

.role-tag--super {
    background: var(--dfa-secondary);
    border-color: var(--dfa-secondary);
    color: #ffffff;
}

.role-tag--staff {
    background: var(--dfa-primary);
    border-color: var(--dfa-primary);
    color: #ffffff;
}

.role-tag--site {
    background: #ffffff;
    color: var(--dfa-text-secondary);
}

/* Confirmation list on the bulk "Change role" page. */
.role-target-list {
    margin: .4rem 0 0;
    padding: 0;
    list-style: none;
    max-height: 320px;
    overflow-y: auto;
}

.role-target-list li {
    padding: 4px 0;
    border-bottom: 1px solid var(--dfa-border-secondary);
}

.role-target-list .quiet {
    margin: 0 6px;
    color: var(--dfa-text-secondary);
}

@media screen and (max-width: 767px) {
    .change-form #id_site_roles,
    .change-form #id_cms_roles,
    .change-form #id_lms_roles {
        grid-template-columns: 1fr;
    }
}

/* ---- Nested inline groups (django-nested-admin) ----
   django-nested-admin ships its own templates for inline formsets (tabular
   and stacked) that render Django's classic pre-Bootstrap admin markup
   (fieldset.module, .form-row, .djn-table, td.original, ...) instead of
   Jazzmin's Bootstrap change_form partials. Django's own base.css — which
   normally styles that classic markup — never loads under Jazzmin, and
   Jazzmin's main.css has exactly one selector for nested-admin
   (.djn-checkbox-select-all), so every nested inline (e.g. Question's
   per-type answer/option detail) rendered with no layout at all: a bare
   <h2>, an auto-layout <table> that a CKEditor5 toolbar blew out to
   ~2900px wide (silently clipped by the page's own overflow-x:hidden, so
   the Fraction/Feedback/Delete columns were unreachable without dev
   tools), a 300px-tall rich-text editor per row regardless of content
   length, and a stray "<p>Curiosity</p>" from nested-admin's own hidden
   "original value" column (nested_admin.css only zeroes its width under
   "#content.colM", the classic-admin wrapper Jazzmin doesn't render). */

.change-form .djn-group {
    margin: 0 0 1.75rem;
}

/* nested-admin's collapsed-row summary column, meant to stay invisible
   except via its own JS toggle (which needs "#content.colM" to fire).
   display:none (tried first) removes it from the box tree entirely, but
   Chromium's table-layout:fixed column-width algorithm still treated the
   "Text" column as if it had a second, equally-weighted auto-width sibling
   to share space with — leaving Text stuck at half-width with a wide dead
   gap after Delete. Giving this column an explicit 0 width instead (nested
   admin's own original intent, see the selector these two rules are
   adapted from) removes the ambiguity: every column but Text now has a
   concrete width, so Text is the one and only auto column and gets 100%
   of what's left. */
.change-form .djn-table td.original,
.change-form .djn-table th.original {
    width: 0;
    padding: 0;
    border: 0;
    overflow: hidden;
    font-size: 0;
    line-height: 0;
}

/* Each inline group (tabular or stacked) reads as its own elevated card —
   matching the top-level "col-lg-9 > .card" treatment above it — instead of
   floating fieldset content with no boundary of its own. overflow:hidden
   lets the h2 header bar's square corners get clipped to the card's radius
   without needing its own border-radius. */
.change-form .djn-fieldset {
    background: #ffffff;
    border: 1px solid var(--dfa-border);
    border-radius: 8px;
    box-shadow: 0 1px 3px rgba(0, 0, 0, .06);
    overflow: hidden;
}

/* Real chrome heading only — the ">" keeps this off CKEditor5 heading
   markup a user types inside an option's rich-text cell, which lives many
   levels deeper (td > .ck-editor-container > .ck-editor__main > .ck-content
   > h2), never as a direct child of the fieldset. */
.change-form .djn-fieldset > h2 {
    margin: 0;
    padding: .85rem 1.25rem;
    background: linear-gradient(to bottom, #fafafa, var(--dfa-border-secondary));
    border-bottom: 1px solid var(--dfa-border);
    font-size: .95rem;
    font-weight: 700;
    color: var(--dfa-text);
    letter-spacing: .01em;
}

/* Everything below the header bar (hidden management-form inputs aside)
   gets breathing room instead of sitting flush against the card edge. */
.change-form .djn-fieldset > .items,
.change-form .djn-fieldset > div.items {
    padding: 1.1rem 1.25rem 1.25rem;
}

/* Each stacked nested item ("Multiple choice detail: ...") reads as its
   own card instead of a bare h3 sitting directly above its fields. */
.change-form .djn-item.djn-module.inline-related {
    padding: 1rem 1.1rem 1.25rem;
    margin-bottom: 1rem;
    border: 1px solid var(--dfa-border);
    border-radius: 6px;
    background: #ffffff;
}

.change-form .djn-item.djn-module.inline-related:last-child {
    margin-bottom: 0;
}

.change-form .djn-drag-handler {
    display: flex;
    align-items: center;
    gap: .5rem;
    margin: -1rem -1.1rem 1.15rem;
    padding: .65rem 1.1rem;
    background: var(--dfa-border-secondary);
    border-bottom: 1px solid var(--dfa-border);
    border-radius: 6px 6px 0 0;
    font-size: .85rem;
    font-weight: 600;
    color: var(--dfa-text-secondary);
    cursor: move;
}

.change-form .djn-drag-handler b {
    color: var(--dfa-text);
}

/* Grab-handle icon injected by admin_actions.js (decorateInlineControls) —
   a visual cue that these stacked items are drag-to-reorder. */
.change-form .djn-drag-handler .fa-grip-vertical {
    color: var(--dfa-text-secondary);
    opacity: .6;
}

/* Tabular child rows (options/pairs/tokens/items/...) — a real bordered
   table instead of a bare auto-layout one. table-layout:fixed also stops
   a CKEditor5 toolbar from dictating the column's (and so the whole
   table's) width — see the CKEditor rule below. */
.change-form .djn-table {
    width: 100%;
    table-layout: fixed;
    border-collapse: collapse;
    background: #ffffff;
}

.change-form .djn-table th,
.change-form .djn-table td {
    padding: .6rem .75rem;
    vertical-align: top;
    border: 1px solid var(--dfa-border-secondary);
}

.change-form .djn-table thead th {
    background: var(--dfa-border-secondary);
    font-size: .78rem;
    text-transform: uppercase;
    letter-spacing: .03em;
    color: var(--dfa-text-secondary);
    text-align: left;
}

/* The "Delete?" header <th> carries no distinguishing class of its own
   (only its <td> gets "delete" — nested_admin's tabular.html only adds a
   field-name class to the body cell), so table-layout:fixed treated it as
   just as flexible as the Text column and split the remaining width evenly
   between the two — starving Text down to the same ~140px as an
   almost-empty Delete column. It's always the last column in nested_admin's
   own template, delete-widget-or-not, so pin it by position instead. */
.change-form .djn-table thead th:last-child {
    width: 72px;
    text-align: center;
    white-space: nowrap;
}

.change-form .djn-table tbody.djn-tbody:nth-of-type(odd) {
    background: #fcfbfc;
}

.change-form .djn-table tbody tr:hover {
    background: var(--dfa-hover-bg);
}

.change-form .djn-table tbody.djn-tbody:hover {
    background: var(--dfa-hover-bg);
}

.change-form .djn-table th.order,
.change-form .djn-table .field-order,
.change-form .djn-table th.group,
.change-form .djn-table .field-group,
.change-form .djn-table th.blank_number,
.change-form .djn-table .field-blank_number,
.change-form .djn-table th.gap_number,
.change-form .djn-table .field-gap_number,
.change-form .djn-table th.correct_order,
.change-form .djn-table .field-correct_order,
.change-form .djn-table th.word_index,
.change-form .djn-table .field-word_index {
    width: 90px;
}

.change-form .djn-table .field-order input,
.change-form .djn-table .field-fraction input {
    width: 100%;
}

/* Fraction column: wider than the other narrow columns since it now also
   holds the "Correct" checkbox (admin_actions.js) stacked above the
   number input, not just the raw fraction value. */
.change-form .djn-table th.fraction,
.change-form .djn-table .field-fraction {
    width: 130px;
}

/* "Correct" checkbox injected above each row's Fraction input, so setting
   the right answer doesn't require knowing what a positive fraction means
   (see wireCorrectAnswerTables() in admin_actions.js). */
.change-form .djn-table .dfa-correct-toggle {
    display: inline-flex;
    align-items: center;
    gap: .3rem;
    margin-bottom: .4rem;
    padding: .2rem .55rem;
    border: 1px solid var(--dfa-border);
    border-radius: 20px;
    background: #ffffff;
    font-size: .68rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .03em;
    color: var(--dfa-text-secondary);
    cursor: pointer;
    transition: all .12s ease-in-out;
    user-select: none;
}

.change-form .djn-table .dfa-correct-toggle:hover {
    border-color: var(--dfa-success);
    color: var(--dfa-success);
}

.change-form .djn-table .dfa-correct-toggle input {
    accent-color: var(--dfa-success);
    width: 12px;
    height: 12px;
    margin: 0;
    cursor: pointer;
}

.change-form .djn-table .dfa-correct-toggle:has(input:checked) {
    background: var(--dfa-success);
    border-color: var(--dfa-success);
    color: #ffffff;
}

.change-form .djn-table td.delete {
    width: 72px;
    text-align: center;
}

/* Icon-only circular button (the icon itself is injected by
   decorateInlineControls() in admin_actions.js — the text "Remove" moves
   to a title/aria-label instead, since 56px has no room for both). */
.change-form .djn-table .inline-deletelink {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    padding: 0;
    border-radius: 50%;
    background: var(--dfa-border-secondary);
    color: var(--dfa-error) !important;
    font-size: .8rem;
    text-decoration: none;
    transition: all .12s ease-in-out;
}

.change-form .djn-table .inline-deletelink:hover {
    background: var(--dfa-error);
    color: #ffffff !important;
}

/* CKEditor5 in a table cell otherwise sizes its toolbar at its natural
   unwrapped width (~2900px across a full row of options) instead of the
   cell's actual width. Constraining the cell forces the toolbar's own
   flex-wrap to kick in instead of blowing out the table. The min-height
   override needs !important: django_ckeditor_5's own bundled CSS sets it
   on the same class, and loses no cascade tie against it otherwise. */
.change-form .djn-table .ck-editor-container,
.change-form .djn-table .ck.ck-editor {
    width: 100%;
    max-width: 100%;
}

.change-form .djn-table .ck-editor__editable_inline {
    /* Rows here are usually a word or a short phrase (option text, match
       pairs, token labels, ...), not paragraphs — the editable area still
       grows past this if someone pastes in more. */
    min-height: 44px !important;
}

.change-form tr.add-row td {
    padding: .75rem;
    background: #fcfbfc;
    text-align: center;
    border-top: 1px dashed var(--dfa-border);
}

.change-form a.add-handler {
    display: inline-flex;
    align-items: center;
    gap: .45rem;
    padding: .5rem 1.15rem;
    border-radius: 20px;
    background: var(--dfa-hover-bg);
    font-size: .8rem;
    font-weight: 600;
    color: var(--dfa-primary);
    text-decoration: none;
    transition: all .12s ease-in-out;
}

.change-form a.add-handler:hover {
    background: var(--dfa-primary);
    color: #ffffff;
}

/* ---- Buttons (DFA: solid fills in the semantic palette) ---- */
.btn-primary {
    background-color: var(--dfa-primary) !important;
    border-color: var(--dfa-primary) !important;
    color: #ffffff !important;
}

.btn-primary:hover,
.btn-primary:focus {
    background-color: var(--dfa-secondary) !important;
    border-color: var(--dfa-secondary) !important;
}

.btn-success {
    background-color: var(--dfa-success) !important;
    border-color: var(--dfa-success) !important;
}

/* The changelist "Add <model>" button reuses Jazzmin's success/green button
   class, but green there reads as an alert colour ("it worked") rather than
   a primary action ("create new"). Recolour it to the brand maroon instead,
   and shrink the plus-circle icon so it doesn't visually compete with the
   button's own rounded corners. */
#change-list-filters .btn-success {
    background-color: var(--dfa-primary) !important;
    border-color: var(--dfa-primary) !important;
    color: #ffffff !important;
    font-size: .875rem;
    box-shadow: none;
}

#change-list-filters .btn-success:hover,
#change-list-filters .btn-success:focus {
    background-color: var(--dfa-secondary) !important;
    border-color: var(--dfa-secondary) !important;
}

#change-list-filters .btn-success i {
    font-size: .85em;
}

.btn-warning {
    background-color: var(--dfa-warning) !important;
    border-color: var(--dfa-warning) !important;
    color: #ffffff !important;
}

.btn-danger {
    background-color: var(--dfa-error) !important;
    border-color: var(--dfa-error) !important;
}

.btn-info {
    background-color: var(--dfa-info) !important;
    border-color: var(--dfa-info) !important;
    color: #ffffff !important;
}

/* Edit/Delete row-action buttons rendered by RowActionsAdminMixin. */
a.button.dfa-btn-edit,
a.button.dfa-btn-delete {
    display: inline-block;
    padding: 4px 10px;
    border-radius: 3px;
    font-size: 12px;
    line-height: 1.5;
    color: #ffffff !important;
}

a.button.dfa-btn-edit {
    background: var(--dfa-primary);
}

a.button.dfa-btn-edit:hover {
    background: var(--dfa-secondary);
}

a.button.dfa-btn-delete {
    background: var(--dfa-error);
}

a.button.dfa-btn-delete:hover {
    background: #96302f;
}

/* ---- Links & text accents ---- */
/* The course builder (.cw) colours its own links; this rule outranks all of them. */
a:not(.btn):not(.button):not(.nav-link):not(.dropdown-item):not(.page-link):not(.cw a) {
    color: var(--dfa-primary);
}

a:not(.btn):not(.button):not(.nav-link):not(.dropdown-item):not(.page-link):not(.cw a):hover {
    color: var(--dfa-secondary);
}

.text-primary {
    color: var(--dfa-primary) !important;
}

/* ---- Form inputs (DFA: border-only focus state, no glow) ---- */
.form-control:focus,
.custom-select:focus,
select:focus {
    border-color: var(--dfa-text-secondary) !important;
    box-shadow: none !important;
}

/* ---- Cards / panels ---- */
.card {
    border: 1px solid var(--dfa-border);
}

.card.card-primary.card-outline {
    border-top: 3px solid var(--dfa-primary);
}

.card-header {
    background: var(--dfa-border-secondary);
    border-bottom: 1px solid var(--dfa-border);
}

/* ---- Tables / change list ---- */
#changelist table thead th,
.table thead th {
    color: var(--dfa-text);
    background: var(--dfa-border-secondary);
    border-bottom: 2px solid var(--dfa-border);
}

#changelist table tbody tr:hover {
    background: var(--dfa-hover-bg);
}

/* Change list — result card, header and row polish. */
#changelist > .card {
    border: 1px solid var(--dfa-border);
    border-radius: 8px;
    box-shadow: 0 1px 3px rgba(0, 0, 0, .06);
    overflow: hidden;
}

#changelist table#result_list thead th {
    padding: 12px 16px;
    font-size: 11px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .04em;
    color: var(--dfa-text-secondary);
    white-space: nowrap;
}

#changelist table#result_list thead th .text a,
#changelist table#result_list thead th .text span {
    color: inherit;
}

/* Django renders the first list_display column (the row's edit link,
   e.g. "Title") as <th>, not <td> — target both or that column silently
   falls back to Bootstrap's default vertical-align:top/8px padding while
   every sibling <td> in the same row gets this rule, throwing the row
   out of vertical alignment. */
#changelist table#result_list tbody td,
#changelist table#result_list tbody th {
    padding: 10px 16px;
    vertical-align: middle;
    border-top: 1px solid var(--dfa-border-secondary);
    font-weight: normal;
}

#changelist table#result_list.table-striped tbody tr:nth-of-type(odd) {
    background-color: #fcfbfc;
}

#changelist table#result_list tbody tr {
    transition: background-color .12s ease-in-out;
}

#changelist table#result_list tbody tr:hover {
    background-color: var(--dfa-hover-bg);
}

/* Title column: make the primary link stand out as the row's main label. */
#changelist table#result_list td.field-title a,
#changelist table#result_list th.field-title a {
    font-weight: 600;
    color: var(--dfa-text);
}

#changelist table#result_list td.field-title a:hover,
#changelist table#result_list th.field-title a:hover {
    color: var(--dfa-primary);
}

/* Weight column (list_editable reorder field): keep it compact so Title gets the room. */
#changelist table#result_list th.column-weight,
#changelist table#result_list td.field-weight {
    width: 70px;
    max-width: 70px;
}

#changelist table#result_list td.field-weight input[type="number"] {
    width: 60px;
    text-align: center;
}

#changelist table#result_list th.column-title,
#changelist table#result_list td.field-title,
#changelist table#result_list th.field-title {
    width: auto;
}

/* Thumbnail preview column (thumbnail_preview() in admin_mixins.py). */
.dfa-thumb {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 48px;
    height: 48px;
    border-radius: 6px;
    background: var(--dfa-border-secondary);
    overflow: hidden;
}

.dfa-thumb img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.dfa-thumb-empty {
    color: var(--dfa-text-secondary);
    font-size: 16px;
    border: 1px dashed var(--dfa-border);
}

/* "Preview" toggle for raw-HTML textareas that bypass CKEditor (see
   wireHtmlPreviewButtons() in admin_actions.js). */
.dfa-html-preview-toggle {
    margin-top: 6px;
}

.dfa-html-preview-frame {
    display: block;
    width: 100%;
    min-height: 320px;
    margin-top: 8px;
    border: 1px solid var(--dfa-border);
    border-radius: 6px;
    background: #fff;
}

/* "Is published" list_editable checkbox: bigger, on-brand, clearly clickable. */
#changelist table#result_list td.field-is_published input[type="checkbox"] {
    width: 18px;
    height: 18px;
    accent-color: var(--dfa-primary);
    cursor: pointer;
}

/* Edit/Delete row-action buttons: icon + label pill pair (row_actions() in
   admin_mixins.py), right-aligned and evenly spaced within their column. */
.dfa-row-actions {
    display: flex;
    gap: 6px;
    justify-content: flex-end;
    flex-wrap: nowrap;
}

/* "a.button" (element + 2 classes) matches the specificity of the base
   a.button.dfa-btn-edit/-delete rule above, so source order — this rule
   comes later — decides the winner and the flex layout actually applies. */
.dfa-row-actions a.button {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    white-space: nowrap;
    line-height: 1;
}

/* Header cell for the row_actions column: right-align so "Actions" lines
   up over the right-aligned button pair below it. */
#changelist table#result_list thead th.column-row_actions {
    text-align: right;
}

/* Toolbar (the "search" block override in templates/admin/change_list.html):
   filters + result count, above the results card. */
#change-list-filters {
    padding: 14px 16px;
    background: var(--dfa-border-secondary);
    border: 1px solid var(--dfa-border);
    border-radius: 8px;
    margin-bottom: 4px !important;
}

.dfa-filters-bar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 10px;
}

/* list_filter dropdowns group on the left... */
.dfa-filters-group {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 10px;
}

.dfa-filters-group .form-group {
    margin-bottom: 0;
}

/* ...search box (icon + input) follows immediately after, in the same
   left-aligned run as the filters — pushing it off to the far right (a
   margin-left: auto on this group, tried earlier) made the filter and the
   search box read as two unrelated controls instead of one toolbar. */
.dfa-search-group {
    position: relative;
}

.dfa-search-icon {
    position: absolute;
    top: 50%;
    left: 10px;
    transform: translateY(-50%);
    font-size: 11px;
    color: var(--dfa-text-secondary);
    pointer-events: none;
}

/* Match the DFA style guide's "Filter Box" component (styleguide.dataforall.org
   /v5/filter.html): flat 4px-radius fields on a white background, not the
   pill-shaped (20px) search box/button this previously used. */
#change-list-filters #searchbar {
    height: 34px;
    padding: 0 10px;
    font-size: 12px;
    border: 1px solid var(--dfa-border);
    border-radius: 4px;
    background-color: #ffffff;
    color: var(--dfa-text);
}

/* Jazzmin's own change_list.js turns every ".search-filter" select into a
   select2 widget on load (see searchFilters() in jazzmin/js/change_list.js),
   which hides the native <select> and inserts its own markup — so styling
   has to target select2's rendered box (main.css's default select2 rule sets
   its own border colour/radius, which is why the filter box and the search
   box next to it looked visibly different) rather than "select.form-control".
   Same fix already applied to the bulk-actions select2 below (.dfa-actions-bar). */
/* select2's own JS sets an inline "width" style on the container (it
   defaults to `width: 'resolve'`, which falls back to 100% since the
   underlying <select class="form-control"> resolves to a 100%-width
   select). With more than one filter this makes selects race for space
   and forces some onto their own wrapped row instead of sitting in a
   neat line (visible on any changelist with 3+ list_filter entries, e.g.
   lms_assessment.Question). !important is required to beat that inline
   style, since a plain rule here loses to it either way. */
.dfa-filters-group .select2-container {
    width: 200px !important;
    min-width: 170px;
}

.dfa-filters-group .select2-container--default .select2-selection--single {
    height: 34px;
    display: flex;
    align-items: center;
    border: 1px solid var(--dfa-border);
    border-radius: 4px;
    background-color: #ffffff;
}

.dfa-filters-group .select2-container--default .select2-selection--single .select2-selection__rendered {
    padding-left: 10px;
    padding-right: 28px;
    color: var(--dfa-text);
    font-size: 12px;
    line-height: normal;
}

.dfa-filters-group .select2-container--default .select2-selection--single .select2-selection__arrow {
    height: 100%;
    right: 8px;
}

.dfa-filters-group .select2-container--default.select2-container--focus .select2-selection--single,
.dfa-filters-group .select2-container--default.select2-container--open .select2-selection--single {
    border-color: var(--dfa-text-secondary);
    outline: none;
}

/* Room for the leading search icon, and a comfortable fixed width so the
   field doesn't balloon to the "min-width: 250px" the stock template used. */
#change-list-filters #searchbar {
    width: 220px;
    padding-left: 28px;
}

/* Scoped to the search form's own button, not "#change-list-filters .btn" —
   Jazzmin renders the "Add <model>" object-tools link as a sibling .btn in
   the same #change-list-filters flex row, and the broader selector was
   shrinking that button down to the search button's compact size too. */
#change-list-filters .dfa-search-submit {
    height: 34px;
    padding: 0 16px;
    font-size: 12px;
    border-radius: 4px;
}

.dfa-result-count {
    margin-left: 4px;
    color: var(--dfa-text-secondary);
}

/* ---- Bulk actions bar (templates/admin/actions.html override) ----
   Jazzmin's stock actions.html renders a bare <select> + <button> + text
   node with no wrapper classes, so it inherits raw browser widget styling
   and sits flush against the page instead of reading as part of the DFA
   toolbar chrome above it (#change-list-filters). Give it the same card
   treatment and lay the controls out in a flex bar. */
.dfa-actions-bar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 10px 16px;
    padding: 10px 16px;
    background: var(--dfa-border-secondary);
    border: 1px solid var(--dfa-border);
    border-radius: 8px;
}

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

.dfa-actions-label {
    margin: 0;
}

/* Jazzmin enhances the action <select> into a select2 widget (see
   change_list.js's `$('.actions select').select2()`), which hides the
   native element and inserts its own markup next to it — so the pill
   styling has to target select2's rendered box, not the select itself. */
.dfa-actions-bar .select2-container--default .select2-selection--single {
    height: calc(1.5em + .75rem + 2px);
    display: flex;
    align-items: center;
    border: 1px solid var(--dfa-border);
    border-radius: 20px;
    background-color: #ffffff;
}

.dfa-actions-bar .select2-container--default .select2-selection--single .select2-selection__rendered {
    padding-left: 1rem;
    color: var(--dfa-text);
    font-size: .875rem;
    line-height: normal;
}

.dfa-actions-bar .select2-container--default .select2-selection--single .select2-selection__arrow {
    height: 100%;
    right: 8px;
}

.dfa-actions-bar .select2-container--default.select2-container--focus .select2-selection--single,
.dfa-actions-bar .select2-container--default.select2-container--open .select2-selection--single {
    border-color: var(--dfa-text-secondary);
    outline: none;
}

.dfa-actions-bar .btn {
    border-radius: 20px;
    padding: .375rem 1rem;
    font-size: .875rem;
    margin: 0;
}

.dfa-actions-reset {
    background-color: #ffffff;
    border-color: var(--dfa-border);
    color: var(--dfa-text-secondary);
}

.dfa-actions-reset:hover {
    background-color: var(--dfa-hover-bg);
    border-color: var(--dfa-primary);
    color: var(--dfa-primary);
}

.dfa-actions-counter {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 10px;
    font-size: .8125rem;
    color: var(--dfa-text-secondary);
}

.dfa-actions-counter .question a,
.dfa-actions-counter .clear a {
    color: var(--dfa-primary);
    font-weight: 600;
}

.dfa-actions-counter .question a:hover,
.dfa-actions-counter .clear a:hover {
    color: var(--dfa-secondary);
}

/* ---- Pagination ---- */
.pagination .page-link {
    color: var(--dfa-primary);
}

/* Active page number: the general .page-link rule above sets maroon text,
   so without an override here the active page's number is maroon-on-maroon
   (background-color below) and effectively invisible. */
.pagination .page-item.active .page-link {
    background-color: var(--dfa-primary);
    border-color: var(--dfa-primary);
    color: #ffffff;
}

/* ---- Django admin messages -> DFA alert colours ---- */
.alert-success,
.messagelist .success {
    background-color: var(--dfa-success) !important;
    border-color: var(--dfa-success) !important;
    color: #ffffff !important;
}

.alert-warning,
.messagelist .warning {
    background-color: var(--dfa-warning) !important;
    border-color: var(--dfa-warning) !important;
    color: #ffffff !important;
}

.alert-danger,
.messagelist .error {
    background-color: var(--dfa-error) !important;
    border-color: var(--dfa-error) !important;
    color: #ffffff !important;
}

.alert-info {
    background-color: var(--dfa-info) !important;
    border-color: var(--dfa-info) !important;
    color: #ffffff !important;
}

/* ---- Login page ----
   Jazzmin's login-logo <img> has no size rule of its own, so the PARAKH
   SVG (drawn at its intrinsic ~1000px width) fills the whole login box.
   AdminLTE also leaves body.login-page a plain block flow, so the box
   sits pinned near the top with a dead gap below it — center it instead. */
body.login-page {
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 100vh;
    background-color: var(--dfa-secondary);
}

.login-box {
    width: 380px;
    margin: 0;
}

.login-logo {
    display: flex;
    justify-content: center;
    margin-bottom: 16px;
}

.login-logo img {
    max-width: 130px;
    height: auto;
}

.login-box-msg {
    text-align: center;
    font-weight: 600;
    color: var(--dfa-text);
    margin-bottom: 20px;
}

.login-box .card,
.register-box .card {
    border-top: 3px solid var(--dfa-primary);
    border-radius: 10px;
    box-shadow: 0 8px 24px rgba(0, 0, 0, .16);
}

.login-card-body {
    padding: 28px 30px;
}

.login-box .input-group {
    margin-bottom: 16px !important;
}

.login-box .input-group .form-control {
    border-right: none;
    height: 44px;
}

.login-box .input-group-text {
    background: #fff;
    border-left: none;
    color: var(--dfa-text-secondary);
}

.login-box .input-group:focus-within .form-control,
.login-box .input-group:focus-within .input-group-text {
    border-color: var(--dfa-text-secondary);
}

/* Show/hide-password toggle (templates/admin/login.html override). */
.login-box .password-toggle {
    cursor: pointer;
}

.login-box .btn-primary {
    background-color: var(--dfa-primary) !important;
    border-color: var(--dfa-primary) !important;
    height: 44px;
    font-weight: 600;
}

/* ---- Drupal-style file/image widgets (DrupalStyleFileWidget /
   DrupalStyleImageWidget in apps/core/admin_widgets.py) ---- */
.drupal-file-current {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 10px 12px;
    margin-bottom: 8px;
    background: var(--dfa-border-secondary);
    border: 1px solid var(--dfa-border);
    border-radius: 4px;
}

.drupal-file-thumb {
    height: 56px;
    width: 56px;
    border-radius: 4px;
    object-fit: cover;
    flex-shrink: 0;
    box-shadow: 0 0 2px rgba(0, 0, 0, .3);
}

.drupal-file-icon {
    font-size: 28px;
    color: var(--dfa-text-secondary);
    flex-shrink: 0;
    width: 56px;
    text-align: center;
}

.drupal-file-meta .clearable-file-input {
    margin-left: 10px;
}

.drupal-file-remove {
    padding: 2px 10px;
    font-size: .8rem;
}

.drupal-file-remove input[type="checkbox"] {
    display: none;
}

.drupal-file-replace {
    color: var(--dfa-text-secondary);
    font-size: .85rem;
    margin-bottom: 4px;
}

/* ---- Version log page (templates/admin/version_log.html) ----
   The body of this page is HTML converted from version_log.md at request time,
   so its headings and lists arrive as bare <h1>/<h2>/<ul> with no classes to
   target. Scoping to .version-log lets them be styled as prose without
   affecting the heading elements the rest of the admin uses for its own
   chrome. Capped at a readable measure — release notes are paragraphs, not a
   data table, and full-width lines are hard to track on a wide monitor. */
.version-log {
    max-width: 52rem;
    color: var(--dfa-text);
    line-height: 1.6;
}

.version-log > h1:first-child {
    /* The card already carries the page title; the file's own top-level
       heading would just repeat it. */
    display: none;
}

.version-log__current {
    font-weight: 700;
}

/* One <h2> per release. The rule above separates releases when several are
   listed, but not before the first one. */
.version-log h2 {
    margin-top: 2.5rem;
    padding-top: 1.5rem;
    border-top: 1px solid var(--dfa-border);
    font-size: 1.5rem;
    font-weight: 700;
    color: var(--dfa-primary);
}

.version-log > hr + h2,
.version-log h2:first-of-type {
    margin-top: 0;
    padding-top: 0;
    border-top: 0;
}

.version-log hr {
    display: none;
}

.version-log h3 {
    margin-top: 1.75rem;
    margin-bottom: .5rem;
    font-size: 1.05rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .04em;
    color: var(--dfa-text-secondary);
}

.version-log p,
.version-log ul,
.version-log ol {
    margin-bottom: 1rem;
}

.version-log ul,
.version-log ol {
    padding-left: 1.25rem;
}

.version-log li {
    margin-bottom: .4rem;
}

.version-log code {
    padding: .1em .35em;
    border-radius: 3px;
    background-color: var(--dfa-border-secondary);
    color: var(--dfa-secondary);
}

.version-log pre {
    padding: .75rem 1rem;
    border: 1px solid var(--dfa-border);
    border-radius: 4px;
    background-color: var(--dfa-border-secondary);
    overflow-x: auto;
}

.version-log pre code {
    padding: 0;
    background: none;
    color: inherit;
}

.version-log table {
    width: 100%;
    margin-bottom: 1rem;
    border-collapse: collapse;
}

.version-log th,
.version-log td {
    padding: .5rem .75rem;
    border: 1px solid var(--dfa-border);
    text-align: left;
    vertical-align: top;
}

.version-log th {
    background-color: var(--dfa-border-secondary);
    font-weight: 700;
}

.version-log a {
    color: var(--dfa-primary);
}

/* ---- Scrollbar (matches the guide's thin custom scrollbar) ---- */
::-webkit-scrollbar {
    width: 8px;
    height: 8px;
}

::-webkit-scrollbar-track {
    background: #F2F2F2;
}

::-webkit-scrollbar-thumb {
    background: #DDDDDD;
}

::-webkit-scrollbar-thumb:hover {
    background: #999999;
}


/* ============================================================================
   Responsive / touch hardening for the admin.

   The public site gets this from static/css/responsive-enhance.css, linked in
   templates/base.html. The admin never loads that file — Jazzmin renders its
   own base template and pulls in only this sheet (JAZZMIN_SETTINGS
   'custom_css') — so the same fixes have to be repeated here for editors
   working on a tablet or phone.
   ========================================================================= */

/* iOS Safari zooms the viewport in whenever a focused control is under 16px,
   and never zooms back out. The admin's inputs render at 12-14px, so every
   tap into a filter, a search box or a change-form field left the editor on a
   panned, zoomed page. Same threshold and reasoning as the public sheet;
   `!important` because Jazzmin/AdminLTE declare these at class specificity. */
@media screen and (max-width: 991px) {
    .form-control,
    .form-select,
    input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="hidden"]),
    select,
    textarea,
    .select2-container .select2-search__field,
    .select2-container--default .select2-selection--single .select2-selection__rendered {
        font-size: 16px !important;
    }
}

/* Touch targets. Restricted to coarse pointers so the dense desktop admin --
   where the row height is what makes long changelists readable -- is untouched. */
@media (pointer: coarse) {
    .btn,
    button,
    input[type="submit"],
    input[type="button"],
    .form-control,
    .form-select,
    select {
        min-height: 44px;
    }

    input[type="checkbox"],
    input[type="radio"] {
        min-width: 24px;
        min-height: 24px;
    }

    /* Changelist row actions and the object links inside them. */
    .paginator a,
    .object-tools a,
    .nav-sidebar .nav-link {
        min-height: 44px;
        display: flex;
        align-items: center;
    }
}

/* Minimum legible size: the changelist's row links and the help/quiet text
   render at 11px, which is below the practical floor on a phone. */
@media screen and (max-width: 991px) {
    .help,
    .helptext,
    .quiet,
    small,
    .paginator,
    #changelist table a,
    .results a {
        font-size: 12px;
    }

    /* The changelist column headers are deliberately small-caps 11px, which
       reads fine on a desktop but falls under the legible floor on a phone.
       Raised only here, so the desktop table keeps its intended density. */
    #changelist table#result_list thead th,
    #changelist table#result_list thead th span {
        font-size: 12px;
    }
}

/* Wide changelists must scroll inside their own container rather than being
   clipped or pushing the whole admin sideways. */
@media screen and (max-width: 991px) {
    #changelist .results,
    .change-list .results,
    .table-responsive {
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
        overscroll-behavior-x: contain;
    }

    /* Stacked change-form rows: the label-beside-field layout has no room on a
       phone, so labels sit above their inputs. */
    .change-form .form-row > div,
    .change-form .form-group {
        display: block;
    }

    .change-form .form-row input[type="text"],
    .change-form .form-row input[type="email"],
    .change-form .form-row input[type="url"],
    .change-form .form-row select,
    .change-form .form-row textarea {
        max-width: 100%;
        width: 100%;
    }
}

/* Jazzmin/AdminLTE give the login and password-reset cards a hard
   `width: 380px`, so on any phone narrower than that -- iPhone SE and the
   Galaxy Fold's 280px outer screen -- the card hung 30px+ past the viewport
   and the "Log in" button sat partly off-screen. Fluid with the same visual
   cap on anything roomier. */
.login-box,
.register-box {
    width: 100%;
    max-width: 380px;
    padding-left: 12px;
    padding-right: 12px;
}


/* ==========================================================================
   Permission grid (apps/core/admin_widgets.py PermissionMatrixWidget)
   Replaces Django's filter_horizontal dual-list on User.user_permissions and
   Group.permissions. Django's own widgets.css — which styles `.selector` —
   never loads under Jazzmin, which is why that control rendered as two
   unstyled, text-truncating boxes in the first place; the grid below is
   styled entirely here and depends on no Django admin stylesheet.
   ========================================================================== */

.perm-matrix {
    /* Django's .related-widget-wrapper is a flex container, so without an
       explicit width this shrinks to its widest collapsed row (~370px) and
       leaves most of the form empty. */
    width: 100%;
    max-width: 100%;
    flex: 1 1 auto;
    min-width: 0;
    font-size: .82rem;
}

.perm-matrix__toolbar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .6rem;
    padding: .6rem .75rem;
    margin-bottom: .9rem;
    border: 1px solid var(--dfa-border);
    border-radius: 6px;
    background: #fafafa;
    position: sticky;
    top: 0;
    z-index: 3;
}

.perm-matrix__search {
    flex: 1 1 240px;
    min-width: 0;
    padding: .4rem .7rem;
    border: 1px solid var(--dfa-border);
    border-radius: 4px;
    font-size: .82rem;
}

.perm-matrix__search:focus {
    border-color: var(--dfa-primary);
    outline: 0;
}

.perm-matrix__summary {
    color: var(--dfa-text-secondary);
    white-space: nowrap;
}

.perm-matrix__summary b {
    color: var(--dfa-primary);
}

.perm-matrix__clear {
    padding: .35rem .8rem;
    border: 1px solid var(--dfa-border);
    border-radius: 4px;
    background: #fff;
    color: var(--dfa-text-secondary);
    font-size: .78rem;
    cursor: pointer;
}

.perm-matrix__clear:hover {
    border-color: var(--dfa-error);
    color: var(--dfa-error);
}

.perm-matrix__section {
    margin-bottom: 1.1rem;
}

.perm-matrix__section-title {
    margin: 0 0 .4rem;
    font-size: .72rem;
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--dfa-text-secondary);
}

/* The site's global style.css hides bare <details> (see the Drupal markup
   notes elsewhere in this file), and Bootstrap gives <summary> no affordance
   of its own — so both are set explicitly rather than inherited. */
.perm-matrix__app {
    display: block;
    margin-bottom: .4rem;
    border: 1px solid var(--dfa-border);
    border-radius: 6px;
    background: #fff;
    overflow: hidden;
}

.perm-matrix__app-summary {
    display: flex;
    align-items: center;
    gap: .5rem;
    padding: .55rem .8rem;
    cursor: pointer;
    list-style: none;
    font-weight: 600;
    color: var(--dfa-text);
    background: #fff;
    user-select: none;
}

.perm-matrix__app-summary::-webkit-details-marker {
    display: none;
}

/* Own disclosure triangle, since the native marker is suppressed above so
   the row can be a flex container. */
.perm-matrix__app-summary::before {
    content: "";
    flex: 0 0 auto;
    width: 0;
    height: 0;
    border-left: 5px solid var(--dfa-text-secondary);
    border-top: 4px solid transparent;
    border-bottom: 4px solid transparent;
    transition: transform .15s ease;
}

.perm-matrix__app[open] > .perm-matrix__app-summary::before {
    transform: rotate(90deg);
}

.perm-matrix__app-summary:hover {
    background: var(--dfa-hover-bg);
}

.perm-matrix__app-name {
    flex: 1 1 auto;
    min-width: 0;
    overflow-wrap: anywhere;
}

.perm-matrix__app-count {
    flex: 0 0 auto;
    min-width: 1.6rem;
    padding: 0 .45rem;
    border-radius: 10px;
    background: var(--dfa-primary);
    color: #fff;
    font-size: 11px;
    font-weight: 600;
    line-height: 1.7;
    text-align: center;
}

.perm-matrix__app-count.is-empty {
    background: transparent;
    color: var(--dfa-text-secondary);
    font-weight: 400;
}

.perm-matrix__table {
    width: 100%;
    border-collapse: collapse;
    border-top: 1px solid var(--dfa-border);
    table-layout: fixed;
}

.perm-matrix__table thead th {
    padding: .35rem .5rem;
    background: #fafafa;
    border-bottom: 1px solid var(--dfa-border);
    font-size: .7rem;
    font-weight: 600;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--dfa-text-secondary);
    text-align: center;
}

.perm-matrix__table thead th.perm-matrix__item-col,
.perm-matrix__table tbody th {
    width: auto;
    text-align: left;
}

/* Fixed layout + a narrow action column keeps the Item column wide, so a
   long model name wraps instead of squeezing the tick-boxes off-screen. */
.perm-matrix__table thead th:not(.perm-matrix__item-col) {
    width: 68px;
}

.perm-matrix__table tbody th {
    padding: .3rem .8rem;
    font-weight: 400;
    color: var(--dfa-text);
    overflow-wrap: anywhere;
}

.perm-matrix__table tbody td {
    padding: .3rem .5rem;
    text-align: center;
}

.perm-matrix__table tbody tr + tr {
    border-top: 1px solid var(--dfa-border-secondary);
}

.perm-matrix__table tbody tr:hover {
    background: var(--dfa-hover-bg);
}

/* A generous hit area around a 15px box, so a mis-aimed click still lands. */
.perm-matrix__box {
    display: inline-block;
    margin: 0;
    padding: .2rem .45rem;
    cursor: pointer;
    line-height: 1;
}

.perm-matrix__box input[type="checkbox"] {
    accent-color: var(--dfa-primary);
    width: 15px;
    height: 15px;
    margin: 0;
    vertical-align: middle;
}

.perm-matrix__box--named {
    display: inline-flex;
    align-items: center;
    gap: .35rem;
    font-size: .78rem;
}

.perm-matrix__extra-row td {
    text-align: left;
}

.perm-matrix__na {
    color: var(--dfa-border);
}

.perm-matrix__empty {
    margin: .6rem 0 0;
    color: var(--dfa-text-secondary);
    font-style: italic;
}

/* Hidden by the search filter. A row/app/section is hidden with an attribute
   rather than a class so the JS can clear it without tracking what else may
   have put a class there. */
.perm-matrix [hidden] {
    display: none !important;
}

@media screen and (max-width: 767px) {
    .perm-matrix__toolbar {
        position: static;
    }

    .perm-matrix__table thead th:not(.perm-matrix__item-col) {
        width: 52px;
    }

    .perm-matrix__table tbody th,
    .perm-matrix__table thead th.perm-matrix__item-col {
        padding-left: .5rem;
        padding-right: .5rem;
    }
}

/* Jazzmin lays every field out as a label column plus a field column inside
   `.form-group > .row` (here col-sm-3 + col-sm-9), which is right for a text
   input and far too narrow for a 4-column grid — it wrapped the toolbar and
   squeezed the tick-boxes. Collapsing both columns to full width for this one
   field stacks the label above the grid and hands it every available pixel. */
.form-group:has(.perm-matrix) > .row > [class*="col-sm-"],
.form-group:has(.perm-matrix) > .row > [class*="col-md-"],
.form-group:has(.perm-matrix) > .row > label {
    flex: 0 0 100%;
    max-width: 100%;
    width: 100%;
    text-align: left;
}

.form-group:has(.perm-matrix) > .row > label {
    margin-bottom: .45rem;
}

.form-group:has(.perm-matrix) .related-widget-wrapper {
    width: 100%;
}

/* ==========================================================================
   LMS progress console (apps/lms_reports)
   ==========================================================================
   Two custom admin pages that replace a change form: one learner's history
   course by course, and one course's drop-off plus roster. Everything here
   is scoped under .dfa-console or one of the .dfa-progress/.dfa-tag helpers,
   which are also used in changelist columns by
   apps.lms_reports.admin._progress_bar. */

.dfa-console {
    font-family: var(--dfa-font);
    color: var(--dfa-text);
}

.dfa-console-head {
    display: flex;
    flex-wrap: wrap;
    gap: 1rem;
    align-items: flex-start;
    justify-content: space-between;
    padding: 1rem 1.25rem;
    margin-bottom: 1.25rem;
    background: #fff;
    border: 1px solid var(--dfa-border);
    border-left: 4px solid var(--dfa-primary);
    border-radius: 4px;
}

.dfa-console-name {
    margin: 0 0 .35rem;
    font-size: 1.35rem;
    color: var(--dfa-secondary);
}

/* Inline fact list: separated by a bullet rather than by punctuation inside
   each span, so a missing optional value leaves no stray separator behind. */
.dfa-console-meta {
    margin: 0 0 .25rem;
    font-size: .85rem;
    color: var(--dfa-text-secondary);
}

.dfa-console-meta span + span::before {
    content: "\00b7";
    margin: 0 .5rem;
}

.dfa-console-actions {
    flex-shrink: 0;
}

.dfa-console-section {
    margin: 1.75rem 0 .65rem;
    font-size: 1.05rem;
    color: var(--dfa-secondary);
}

.dfa-console-section small {
    font-weight: normal;
    color: var(--dfa-text-secondary);
}

.dfa-console-empty {
    padding: .85rem 1rem;
    font-size: .9rem;
    color: var(--dfa-text-secondary);
    background: var(--dfa-border-secondary);
    border-radius: 4px;
}

/* --- Per-course card -----------------------------------------------------
   display:block is not redundant. A bare <details> is display:none under
   this project's stylesheets, which renders the card as an empty strip
   rather than a collapsed one — the same trap documented for the public
   site's own <details> elements. Any new <details> here must restate it. */
.dfa-console-course {
    display: block;
    margin-bottom: .85rem;
    background: #fff;
    border: 1px solid var(--dfa-border);
    border-radius: 4px;
    overflow: hidden;
}

.dfa-console-course > summary {
    display: flex;
    flex-wrap: wrap;
    gap: .75rem;
    align-items: center;
    justify-content: space-between;
    padding: .7rem 1rem;
    cursor: pointer;
    list-style: none;
    background: var(--dfa-border-secondary);
}

.dfa-console-course > summary::-webkit-details-marker {
    display: none;
}

.dfa-console-course > summary::before {
    content: "\25b8";
    margin-right: .5rem;
    color: var(--dfa-primary);
    transition: transform .15s ease;
}

.dfa-console-course[open] > summary::before {
    content: "\25be";
}

.dfa-console-course > summary:hover {
    background: var(--dfa-hover-bg);
}

.dfa-course-title {
    flex: 1 1 14rem;
    min-width: 0;
    font-weight: 600;
    overflow-wrap: anywhere;
}

.dfa-course-stats {
    display: flex;
    flex-wrap: wrap;
    gap: .5rem;
    align-items: center;
    font-size: .82rem;
    color: var(--dfa-text-secondary);
}

.dfa-course-body {
    padding: .85rem 1rem 1rem;
}

.dfa-course-facts {
    display: flex;
    flex-wrap: wrap;
    gap: 1.5rem;
    margin: 0 0 .85rem;
    font-size: .85rem;
}

.dfa-course-facts dt {
    font-size: .72rem;
    text-transform: uppercase;
    letter-spacing: .04em;
    color: var(--dfa-text-secondary);
}

.dfa-course-facts dd {
    margin: 0;
}

/* --- Tables --------------------------------------------------------------
   table-layout stays auto: the activity-title column has to absorb titles
   that run from three words to a full sentence, which a fixed layout would
   either clip or pad. */
.dfa-console-table {
    width: 100%;
    font-size: .85rem;
    border-collapse: collapse;
}

.dfa-console-table th {
    padding: .45rem .6rem;
    font-size: .72rem;
    text-transform: uppercase;
    letter-spacing: .04em;
    color: var(--dfa-text-secondary);
    text-align: left;
    border-bottom: 1px solid var(--dfa-border);
}

.dfa-console-table td {
    padding: .45rem .6rem;
    vertical-align: top;
    border-bottom: 1px solid var(--dfa-border-secondary);
}

.dfa-console-table .dfa-col-num {
    text-align: right;
    white-space: nowrap;
}

.dfa-console-table tr.dfa-row-node > td {
    font-weight: 600;
    color: var(--dfa-secondary);
    background: var(--dfa-border-secondary);
}

.dfa-console-table tr.dfa-row-done .dfa-tick {
    color: var(--dfa-success);
}

.dfa-tick {
    display: inline-block;
    width: 1em;
    margin-right: .35rem;
    color: var(--dfa-border);
    text-align: center;
}

.dfa-console-paginator {
    display: flex;
    gap: 1rem;
    align-items: center;
    margin-top: .75rem;
    font-size: .85rem;
}

/* --- Progress meter ------------------------------------------------------
   Also used in changelist columns, where a bare percentage in a column of
   percentages is very hard to scan; the bar is what makes an outlier row
   visible without reading every number. */
.dfa-progress {
    display: inline-block;
    width: 5.5rem;
    height: .5rem;
    overflow: hidden;
    vertical-align: middle;
    background: var(--dfa-border);
    border-radius: 999px;
}

.dfa-progress-fill {
    display: block;
    height: 100%;
    background: var(--dfa-primary);
    border-radius: 999px;
}

.dfa-progress-label {
    margin-left: .4rem;
    font-size: .8rem;
    font-variant-numeric: tabular-nums;
    color: var(--dfa-text-secondary);
    vertical-align: middle;
}

.dfa-progress-empty {
    color: var(--dfa-text-secondary);
}

/* --- Status tags --------------------------------------------------------- */
.dfa-tag {
    display: inline-block;
    padding: .1rem .45rem;
    font-size: .7rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: .03em;
    white-space: nowrap;
    border-radius: 3px;
}

.dfa-tag-done {
    color: #2f6b2f;
    background: #e5f3e5;
}

.dfa-tag-warn {
    color: #8a5a11;
    background: #fdf1de;
}

.dfa-tag-muted {
    color: var(--dfa-text-secondary);
    background: var(--dfa-border-secondary);
}

@media (max-width: 767px) {
    .dfa-console-head {
        flex-direction: column;
    }

    /* Both console tables are wide by nature (5 columns of facts), so they
       scroll inside their own wrapper rather than forcing the page to
       scroll horizontally. */
    .dfa-console-table {
        display: block;
        overflow-x: auto;
        white-space: nowrap;
    }
}
