/* Override font-display: block → swap for faster text rendering */
@font-face {
    font-family: "Font Awesome 7 Free";
    font-display: swap;
    src: url("node_modules/@fortawesome/fontawesome-free/webfonts/fa-solid-900.bd30bbc09dfe.woff2");
}
@font-face {
    font-family: "Font Awesome 7 Brands";
    font-display: swap;
    src: url("node_modules/@fortawesome/fontawesome-free/webfonts/fa-brands-400.6ec5376d46cd.woff2");
}
@font-face {
    font-family: "bootstrap-icons";
    font-display: swap;
    src: url("node_modules/bootstrap-icons/font/fonts/bootstrap-icons.84a4d15b9e44.woff2");
}

/* ==============================================
   App theme variables
   ==============================================
   --app-brand is the per-event brand color: base.html overrides it inline
   from Event.primary_color. Everything else derives from it with
   color-mix(), so one hex drives links, buttons, sidebar and focus states
   in both themes. */
:root {
    --app-brand: #337ab7;
    --app-primary: var(--app-brand);
    --app-primary-hover: color-mix(in srgb, var(--app-brand) 75%, #000);
    --app-primary-subtle: color-mix(in srgb, var(--app-brand) 12%, transparent);
    --bs-focus-ring-color: color-mix(in srgb, var(--app-primary) 25%, transparent);
}

[data-bs-theme=dark] {
    /* Lighten the brand color so it keeps contrast on dark surfaces. */
    --app-primary: color-mix(in srgb, var(--app-brand) 65%, #fff);
    --app-primary-hover: color-mix(in srgb, var(--app-brand) 50%, #fff);
    --app-primary-subtle: color-mix(in srgb, var(--app-brand) 20%, transparent);
}

/* Solid buttons: --app-btn-bg is the effective button surface. It keeps
   the brand HUE but normalizes the LIGHTNESS (lch clamp) so the button is
   never disproportionately dark on a light page, never glares on a dark
   page, and always has ≥~4.5:1 contrast for its white label — whatever
   the event picks as its brand color. The default #337ab7 (L* ≈ 49) sits
   inside the light-theme clamp, so the stock look is unchanged. Browsers
   without relative color syntax fall back to the raw/darkened brand. */
.btn-primary,
.btn-outline-primary {
    --app-btn-bg: var(--app-brand);
    --app-btn-fg: #fff;
}

[data-bs-theme=dark] .btn-primary,
[data-bs-theme=dark] .btn-outline-primary {
    --app-btn-bg: color-mix(in srgb, var(--app-brand) 70%, #000);
}

@supports (color: lch(from red l c h)) {
    .btn-primary,
    .btn-outline-primary {
        --app-btn-bg: lch(from var(--app-brand) clamp(44, l, 52) c h);
    }

    [data-bs-theme=dark] .btn-primary,
    [data-bs-theme=dark] .btn-outline-primary {
        --app-btn-bg: lch(from var(--app-brand) clamp(36, l, 46) c h);
    }
}

.btn-primary {
    --bs-btn-bg: var(--app-btn-bg);
    --bs-btn-border-color: var(--app-btn-bg);
    --bs-btn-color: var(--app-btn-fg);
    --bs-btn-hover-bg: color-mix(in srgb, var(--app-btn-bg) 85%, #000);
    --bs-btn-hover-border-color: color-mix(in srgb, var(--app-btn-bg) 85%, #000);
    --bs-btn-hover-color: var(--app-btn-fg);
    --bs-btn-active-bg: color-mix(in srgb, var(--app-btn-bg) 75%, #000);
    --bs-btn-active-border-color: color-mix(in srgb, var(--app-btn-bg) 75%, #000);
    --bs-btn-active-color: var(--app-btn-fg);
    --bs-btn-disabled-bg: var(--app-btn-bg);
    --bs-btn-disabled-border-color: var(--app-btn-bg);
    --bs-btn-disabled-color: var(--app-btn-fg);
}

.btn-outline-primary {
    --bs-btn-color: var(--app-primary);
    --bs-btn-border-color: var(--app-primary);
    --bs-btn-hover-bg: var(--app-btn-bg);
    --bs-btn-hover-border-color: var(--app-btn-bg);
    --bs-btn-hover-color: var(--app-btn-fg);
    --bs-btn-active-bg: var(--app-btn-bg);
    --bs-btn-active-border-color: var(--app-btn-bg);
    --bs-btn-active-color: var(--app-btn-fg);
    --bs-btn-disabled-color: var(--app-primary);
    --bs-btn-disabled-border-color: var(--app-primary);
}

/* Link-style buttons follow the brand color like plain <a> elements do
   (Bootstrap defaults them to --bs-link-color blue). */
.btn-link {
    --bs-btn-color: var(--app-primary);
    --bs-btn-hover-color: var(--app-primary-hover);
    --bs-btn-active-color: var(--app-primary-hover);
}

.form-control:focus,
.form-select:focus {
    border-color: color-mix(in srgb, var(--app-primary) 50%, var(--bs-body-bg));
    box-shadow: 0 0 0 0.25rem color-mix(in srgb, var(--app-primary) 25%, transparent);
}

/* Follow the brand color instead of Bootstrap blue (works in both themes:
   --app-primary is already the lightened variant in dark mode). */
.text-primary {
    color: var(--app-primary) !important;
}

/* Icons in page/card headings follow the heading's font color — brand
   color everywhere reads as too colorful. This neutralizes only
   .text-primary (which maps to the brand above); semantic colors like
   .text-danger / .text-muted on heading icons keep their meaning. */
h1 > i.text-primary,
h2 > i.text-primary,
h3 > i.text-primary,
.card-title > i.text-primary {
    color: inherit !important;
}

/* Brand accent line at the bottom edge of the top bar. Inset box-shadow
   instead of border so the navbar height stays exactly --app-topbar-h
   (the sidebar and pinned dropdowns are positioned against it). */
.navbar.fixed-top {
    box-shadow: inset 0 -3px 0 var(--app-primary);
}

.nav-link {
    color: #3c3f43;
}

[data-bs-theme=dark] .nav-link {
    color: #e6e6e6;
}

textarea {
    border-color: #3a3b3b !important;
}


.scroll-menu {
    min-width: 220px;
    max-height: 90vh;
    max-height: 90dvh;
    overflow: auto !important;
}

/*
 * Navbar responsive: icon-only when space is tight
 */
.navbar .nav-link,
.navbar .navbar-brand,
.navbar .dropdown-toggle {
    white-space: nowrap;
}

.navbar .nav-icon-compact {
    display: none;
}

/*
 * Pidä yläpalkki aina yhdellä rivillä. Tapahtuman nimi (.navbar-event-name)
 * piilotetaan JS:llä kun tila loppuu (ks. base.html ResizeObserver), jolloin
 * jäljelle jää pelkkä logo. Ikonirivi ei kutistu eikä rivity.
 */
.navbar.fixed-top > .container-fluid {
    flex-wrap: nowrap;
    /* Keep the top-bar contents clear of a landscape notch (viewport-fit=cover).
       max() preserves the default gutter on devices with no inset. */
    padding-left: max(var(--bs-gutter-x, 0.75rem), env(safe-area-inset-left));
    padding-right: max(var(--bs-gutter-x, 0.75rem), env(safe-area-inset-right));
}

.navbar.fixed-top .navbar-nav.flex-row {
    flex-wrap: nowrap;
    flex-shrink: 0;
}

/* Event-vaihtaja ei saa kutistua sisältönsä alle: muuten nimi vuotaisi
   ikonien päälle eikä navbarin scrollWidth kasvaisi, jolloin JS ei
   havaitsisi ahtautta. Pidä luonnollinen leveys → ahtaus näkyy
   scrollWidthissä → JS piilottaa nimen. */
.navbar.fixed-top > .container-fluid > .dropdown,
.navbar.fixed-top > .container-fluid > .navbar-brand {
    flex-shrink: 0;
}

/* Kaikki navbar-dropdownit: rajaa korkeus näyttöön, jotta pitkä valikko
   vierittyy eikä leikkaudu alareunasta. */
.navbar.fixed-top .dropdown-menu {
    max-height: calc(100dvh - var(--app-topbar-h) - 0.5rem);
    overflow-y: auto;
    overscroll-behavior: contain;
}

/* Oikean laidan asetus-/käyttäjävalikko on pisin ja lähimpänä reunaa.
   Kiinnitä se navbarin alle oikeaan reunaan ja rajaa leveys KAIKILLA
   leveyksillä, ettei pisimmät rivit (esim. "Kaikki palautteet") valu
   viewportin oikean reunan yli. Koskee vain ms-auto-listaa, joten vasemman
   laidan event-vaihtaja ja lähetyskone-valikko säilyttävät oman sijaintinsa. */
.navbar.fixed-top .navbar-nav.ms-auto .dropdown-menu {
    position: fixed !important;
    top: var(--app-topbar-h) !important;
    right: 0.5rem !important;
    left: auto !important;
    transform: none !important;
    max-width: calc(100vw - 1rem);
}

@media (min-width: 768px) and (max-width: 1050px) {
    .navbar .nav-label {
        display: none;
    }
    .navbar .nav-icon-compact {
        display: inline;
    }
    .navbar .nav-link i,
    .navbar .dropdown-toggle i {
        font-size: 1.1rem;
    }
}

/*
 * Mobile menu: when the collapsed navbar is opened it can be taller than the
 * viewport. Give it its own scroll container so swiping inside the menu
 * scrolls the menu — not the page underneath. `overscroll-behavior: contain`
 * stops the scroll from chaining to <body> when the user reaches either end.
 */
@media (max-width: 767.98px) {
    .navbar.fixed-top .navbar-collapse {
        max-height: calc(100dvh - 56px);
        overflow-y: auto;
        overscroll-behavior: contain;
    }
}

/*
 * iOS zoom-on-focus guard: Safari zooms the whole page when a focused
 * field's font-size is under 16px. On phone-width screens force every
 * form control to 1rem (16px) — !important so it also beats the -sm
 * variants (0.875rem) and inline font-size styles. Desktop is untouched.
 */
@media (max-width: 767.98px) {
    .form-control,
    .form-select,
    .form-control-sm,
    .form-select-sm,
    .choices__input {
        font-size: 1rem !important;
    }
}

/* Show it is fixed to the top */
body {
    /* "Twemoji Country Flags" is prepended for the Windows flag-emoji polyfill
       (country-flag-emoji-polyfill, loaded in radio/base.html). That polyfill
       injects the matching @font-face only on browsers that lack native flag
       glyphs (Windows Chromium); its unicode-range is scoped to flag codepoints,
       so non-flag text is unaffected and platforms with native flags (macOS,
       Android) simply have no such font and fall through to Helvetica. */
    font-family: "Twemoji Country Flags", "Helvetica Neue", Helvetica, Arial, sans-serif;
    font-size: 14px;
    line-height: 1.42857143;
    /* color: #555; */
}

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

a:hover {
    color: var(--app-primary-hover);
    text-decoration: underline;
}

/*
 * Sidebar (desktop pysyvä) + offcanvas drawer (mobiili).
 * Aside ja offcanvas-body sisältävät saman _sidebar_nav.html -partialin.
 */

:root {
    --app-topbar-h: 56px;
    --app-sidebar-w: 240px;
}

.app-sidebar {
    position: fixed;
    top: var(--app-topbar-h);
    left: 0;
    bottom: 0;
    width: var(--app-sidebar-w);
    z-index: 1025; /* alle navbarin (1030) */
    overflow-y: auto;
    background-color: #f8f9fa;
    border-right: 1px solid rgba(0, 0, 0, 0.1);
}

[data-bs-theme=dark] .app-sidebar {
    background-color: #212529;
    border-right-color: rgba(255, 255, 255, 0.1);
}

.app-sidebar .nav-link,
.offcanvas .app-sidebar-nav .nav-link {
    font-weight: 500;
    color: #333;
    display: flex;
    align-items: center;
    gap: 0.6rem;
    padding: 0.55rem 1rem;
}

.app-sidebar .nav-link i,
.offcanvas .app-sidebar-nav .nav-link i {
    width: 1.25rem;
    text-align: center;
}

[data-bs-theme=dark] .app-sidebar .nav-link,
[data-bs-theme=dark] .offcanvas .app-sidebar-nav .nav-link {
    color: #b4b1b1;
}

/* Sidebar section headings (Yleiset / Tehtävät / Tekniikka / Muut) */
.app-sidebar .app-sidebar-heading,
.offcanvas .app-sidebar-nav .app-sidebar-heading {
    padding: 0.9rem 1rem 0.25rem;
    font-size: 0.7rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: #6c757d;
}

[data-bs-theme=dark] .app-sidebar .app-sidebar-heading,
[data-bs-theme=dark] .offcanvas .app-sidebar-nav .app-sidebar-heading {
    color: #868e96;
}

/* Keep the sidebar compact: the first heading sits right under the search box,
   so it needs far less top padding than the between-section headings. Selectors
   mirror the specificity of the base heading rules above (desktop + offcanvas)
   so this override wins in both. */
.app-sidebar .app-sidebar-search + .app-sidebar-heading,
.offcanvas .app-sidebar-nav .app-sidebar-search + .app-sidebar-heading {
    padding-top: 0.3rem;
}

/* Sidebar navigation search results (radio/_sidebar_nav.html + nav-search.js) */
.js-nav-search-results .nav-search-result {
    color: #333;
    border-radius: 0.2rem;
}

/* .active is toggled by keyboard arrow navigation; :hover mirrors it. */
.js-nav-search-results .nav-search-result:hover,
.js-nav-search-results .nav-search-result.active {
    background-color: var(--bs-secondary-bg, #e9ecef);
    color: #000;
}

[data-bs-theme=dark] .js-nav-search-results .nav-search-result {
    color: #dee2e6;
}

[data-bs-theme=dark] .js-nav-search-results .nav-search-result:hover,
[data-bs-theme=dark] .js-nav-search-results .nav-search-result.active {
    background-color: #343a40;
    color: #fff;
}



/*
 *  Main view
 */
.main {
    /* --app-topbar-h seuraa navbarin todellista korkeutta (ks. base.html
       ResizeObserver), joten sisältö ei jää fixed-top-palkin alle vaikka
       palkki olisi oletusta 56 px korkeampi. */
    padding-top: calc(var(--app-topbar-h) + 12px);
    /* max(20px, env(...)) keeps content clear of a notch / the home indicator
       in an installed PWA (viewport-fit=cover); the inset is 0 elsewhere. */
    padding-left: max(20px, env(safe-area-inset-left));
    padding-right: max(20px, env(safe-area-inset-right));
    padding-bottom: max(20px, env(safe-area-inset-bottom));
}

@media (min-width: 992px) {
    .main-with-sidebar {
        margin-left: var(--app-sidebar-w);
    }
}

/* Floating action buttons (feedback + search) stack in the bottom-right
   corner on every authenticated page. On phones give the content extra
   bottom padding so it can always scroll clear of the button stack. */
@media (max-width: 575.98px) {
    .main {
        padding-bottom: 9rem;
    }
}

/* Rich-text previews in the global search preview modal can contain
   embedded images; constrain them so they never overflow the modal on
   narrow phones. */
#previewModalBody img {
    max-width: 100%;
    height: auto;
}


/*
 * Form
 */

.form-signin {
    width: 100%;
    max-width: 330px;
    padding: 15px;
    margin: auto;
}

.normal-link {
    text-decoration: none;
    color: var(--app-primary);
}

/*Kalenterin fontin väri*/
#cal-slide-content a.event-item {
    font-weight: normal;
    line-height: 22px;
}

.data-left {
    width: 150px;
    float: left;
    overflow-wrap: break-word;
    font-weight: bold;
}

.data-right {
    overflow-wrap: break-word;
    width: calc(100% - 150px);
    float: left;
    padding-bottom: 3px;
}

.data.row {
    margin-bottom: 10px;
}

.small_text {
    color: #6c6a6a;
    font-size: 90%;
}

.indent {
    margin-left: 40px;
}


.error-text {
    color: #a94442;
}

.list-group {
    margin-bottom: 0;
}

.rounded-block {
    margin: 20px;
}

/*.container {
    width: 100% !important  ;
}*/

.margin_top_5 {
    margin-top: 5rem;
}

.custom-file-label {
    width: 100%;
}

.custom-file-border {
    line-height: 1.5;
    padding: .375rem .75rem;
    color: #495057;
    background-color: #ffffff;
    border: 1px solid #ced4da;
}

.custom-file-ext-border {
    margin-left: -.5rem;
    padding: .5rem 1rem .8rem .7rem;
    line-height: 1.5;
    color: #495057;
    background-color: #e9ecef;
    border: 1px solid #ced4da;
}

.custom-modal-title {
    display: inline;
}

.table-responsive .dt-buttons {
    margin-bottom: 4rem;
}


.draft {
    font-style: italic;
    color: #000000; /* #a9a9a9 was too light for datatables view*/
}

.draft a {
    color: #000000; /* #b0c4de was too light for datatables view*/
}

.loader-box {
    text-align: center;
    text-align: -webkit-center;
    padding: 6rem;
}

.loader {
    border: 16px solid #f3f3f3; /* Light grey */
    border-top: 16px solid var(--app-primary);
    border-radius: 50%;
    width: 120px;
    height: 120px;
    -webkit-animation: spin 2s linear infinite; /* Safari */
    animation: spin 2s linear infinite;
}

.text-white {
    color: #d3d3d3;
}

.mb-2 {
    margin-bottom: 2rem;
}

/* Safari */
@-webkit-keyframes spin {
    0% {
        -webkit-transform: rotate(0deg);
    }
    100% {
        -webkit-transform: rotate(360deg);
    }
}

@keyframes spin {
    0% {
        transform: rotate(0deg);
    }
    100% {
        transform: rotate(360deg);
    }
}


.app-sidebar .nav-link.active,
.offcanvas .app-sidebar-nav .nav-link.active {
    color: var(--app-primary) !important;
    background-color: var(--app-primary-subtle);
    border-left: 4px solid var(--app-primary);
    font-weight: 600;
}

.app-sidebar .nav-link:hover,
.offcanvas .app-sidebar-nav .nav-link:hover {
    color: inherit;
    background-color: rgba(0, 0, 0, 0.05);
}

[data-bs-theme=dark] .app-sidebar .nav-link:hover,
[data-bs-theme=dark] .offcanvas .app-sidebar-nav .nav-link:hover {
    background-color: rgba(255, 255, 255, 0.05);
}

/* Remove list bullets from navbar dropdown items */
.navbar .nav-item {
    list-style: none;
}

.navbar ul {
    list-style: none;
}

/* Improve table-secondary visibility in dark mode (for past programs) */
[data-bs-theme=dark] .table-secondary {
    --bs-table-bg: #3a3f44;
    --bs-table-color: #b0b3b8;
    background-color: var(--bs-table-bg) !important;
    color: var(--bs-table-color) !important;
}

[data-bs-theme=dark] .table-secondary td,
[data-bs-theme=dark] .table-secondary th {
    background-color: var(--bs-table-bg);
    color: var(--bs-table-color);
}

/* Authentication card styling (login, 2FA) */
.auth-card {
    background-color: #e3e3e3;
}

[data-bs-theme=dark] .auth-card {
    background-color: #2b3035;
}

/* ==============================================
   Choices.js Dropdown Styling
   ============================================== */

/* An open Choices dropdown must paint above positioned elements that come
   later in the DOM (e.g. a CKEditor toolbar right below the select) — the
   library's own z-index loses to them. 1000 matches Bootstrap's dropdown
   layer and stays below the fixed navbar (1030) and modals (1055). */
.choices.is-open {
    z-index: 1000;
}

/* Main container background */
[data-bs-theme=dark] .choices__inner {
    background-color: #212529;
    border-color: #495057;
}

/* Dropdown menu background */
[data-bs-theme=dark] .choices__list--dropdown {
    background-color: #212529;
    border-color: #495057;
}

/* Dropdown items text color */
[data-bs-theme=dark] .choices__list--dropdown .choices__item {
    color: #dee2e6;
}

/* Highlighted (hovered) and currently-selected item in dropdown.
   Choices.js' default CSS uses the same #f2f2f2 background for both, which
   leaves the selected row almost invisible against light text in dark mode. */
[data-bs-theme=dark] .choices__list--dropdown .choices__item--selectable.is-highlighted,
[data-bs-theme=dark] .choices__list--dropdown .choices__item--selectable.is-selected,
[data-bs-theme=dark] .choices__list[aria-expanded] .choices__item--selectable.is-selected {
    background-color: #3a3f44;
    color: #dee2e6;
}

/* Selected item text color */
[data-bs-theme=dark] .choices__item {
    color: #dee2e6;
}

/* Search input inside dropdown */
[data-bs-theme=dark] .choices__input {
    background-color: #212529;
    color: #dee2e6;
}

/* Search input specifically for single-select (more specific selector) */
[data-bs-theme=dark] .choices[data-type*=select-one] .choices__input {
    background-color: #212529;
    border-bottom-color: #495057;
    color: #dee2e6;
}

/* Placeholder text */
[data-bs-theme=dark] .choices__placeholder {
    color: #6c757d;
}

/* Dropdown arrow for single-select */
[data-bs-theme=dark] .choices[data-type*=select-one]::after {
    border-color: #dee2e6 transparent transparent transparent;
}

/* Focus state for choices container */
[data-bs-theme=dark] .choices.is-focused .choices__inner {
    border-color: var(--app-primary);
}

/* Multi-select selected items (tags) */
[data-bs-theme=dark] .choices__list--multiple .choices__item {
    background-color: #3a3f44;
    border-color: #495057;
    color: #dee2e6;
}

/* Remove button on multi-select items */
[data-bs-theme=dark] .choices__button {
    filter: invert(1);
}

/* ==============================================
   Dark Mode: Multi-Select Dropdown Styling
   ============================================== */

/* Main containers background */
[data-bs-theme=dark] .ms-container .ms-selectable,
[data-bs-theme=dark] .ms-container .ms-selection {
    background-color: #212529;
    color: #dee2e6;
}

/* List containers */
[data-bs-theme=dark] .ms-container .ms-list {
    background-color: #212529;
    border-color: #495057;
}

/* Focus state for list */
[data-bs-theme=dark] .ms-container .ms-list.ms-focus {
    border-color: var(--app-primary);
    box-shadow: 0 0 0 0.2rem color-mix(in srgb, var(--app-primary) 25%, transparent);
}

/* List items text color - more specific selector to override default */
[data-bs-theme=dark] .ms-container .ms-selectable li.ms-elem-selectable,
[data-bs-theme=dark] .ms-container .ms-selection li.ms-elem-selection {
    color: #dee2e6;
    border-bottom-color: #495057;
}

/* Hover state for list items */
[data-bs-theme=dark] .ms-container .ms-selectable li.ms-hover,
[data-bs-theme=dark] .ms-container .ms-selection li.ms-hover {
    background-color: #3a3f44;
    color: #fff;
}

/* Disabled/grayed out items */
[data-bs-theme=dark] .ms-container .ms-selectable li.disabled,
[data-bs-theme=dark] .ms-container .ms-selection li.disabled {
    background-color: #2c3034;
    color: #6c757d;
}

/* Header labels */
[data-bs-theme=dark] .ms-container .ms-selectable-header,
[data-bs-theme=dark] .ms-container .ms-selection-header {
    background-color: #2c3034;
    color: #dee2e6;
    border-bottom-color: #495057;
}

/* Search input styling */
[data-bs-theme=dark] .ms-container .search-input {
    background-color: #2c3034;
    border: 1px solid #495057;
    color: #dee2e6;
}

[data-bs-theme=dark] .ms-container .search-input::placeholder {
    color: #6c757d;
}

/* Help text labels (Vaihtoehdot/Valitut) */
[data-bs-theme=dark] .ms-container .help {
    color: #adb5bd;
}

/* ==============================================
   Category Colors (.category-color)
   ==============================================
   Class-based category coloring: the element carries
   class="category-color" and the color in a custom property
   (style="--category-color: #ff6600"), set by JS (program_list.js) or a
   template. color-mix() gives a consistent darkened variant in dark mode
   instead of the unpredictable brightness()/saturate() filters used
   before. !important mirrors the old inline style="background-color:..."
   behavior, which also beat every theme rule (e.g. .table-secondary). */
.category-color {
    background-color: var(--category-color) !important;
    print-color-adjust: exact;
    -webkit-print-color-adjust: exact;
}

[data-bs-theme=dark] .category-color {
    background-color: color-mix(in srgb, var(--category-color) 60%, #212529) !important;
    color: #fff;
}

/* Past programs: fade the category color further into the background. */
[data-bs-theme=dark] .table-secondary .category-color {
    background-color: color-mix(in srgb, var(--category-color) 35%, #212529) !important;
    color: #b0b3b8;
}

/* Table headers in dark mode */
[data-bs-theme=dark] #event-table thead th {
    color: #f8f9fa;
}

/* Gone/past programs - ensure grey overlay shows properly in dark mode */
[data-bs-theme=dark] .gone,
[data-bs-theme=dark] tr.gone td {
    background-color: #3a3f44 !important;
    color: #b0b3b8;
    opacity: 0.8;
}

/* Current program highlight in dark mode */
[data-bs-theme=dark] .current,
[data-bs-theme=dark] tr.current td {
    background-color: #1a4a5c !important;
    color: #f8f9fa;
}

/* Coming programs with category colors in dark mode */
[data-bs-theme=dark] .coming[style*="background-color"],
[data-bs-theme=dark] tr.coming[style*="background-color"] td {
    filter: brightness(0.5) saturate(1.4);
}

/* Darken inline background colors in tables for dark mode */
[data-bs-theme=dark] .table td[style*="background-color"] {
    position: relative;
}

[data-bs-theme=dark] .table td[style*="background-color"]::after {
    content: '';
    position: absolute;
    inset: 0;
    background-color: rgba(0, 0, 0, 0.4);
    pointer-events: none;
    z-index: 0;
}

[data-bs-theme=dark] .table td[style*="background-color"] > * {
    position: relative;
    z-index: 1;
}

/* Ensure table-secondary works with inline styles in dark mode */
[data-bs-theme=dark] .table-secondary td[style*="background-color"] {
    filter: brightness(0.4) saturate(1.2) !important;
    opacity: 0.7;
}

/* ==============================================
   Dark Mode: CKEditor 5 Styling
   ============================================== */

[data-bs-theme=dark] .ck.ck-editor {
    --ck-color-base-background: #212529;
    --ck-color-base-text: #dee2e6;
    --ck-color-base-border: #495057;
    --ck-color-base-active-focus: var(--app-primary);
    --ck-color-base-focus: #495057;
    --ck-color-toolbar-background: #2b3035;
    --ck-color-toolbar-border: #495057;
    --ck-color-button-default-background: transparent;
    --ck-color-button-default-hover-background: #3a3f44;
    --ck-color-button-on-background: #3a3f44;
    --ck-color-button-on-hover-background: #495057;
    --ck-color-button-on-active-background: #495057;
    --ck-color-button-default-disabled-background: transparent;
    --ck-color-dropdown-panel-background: #212529;
    --ck-color-dropdown-panel-border: #495057;
    --ck-color-input-background: #2b3035;
    --ck-color-input-border: #495057;
    --ck-color-input-text: #dee2e6;
    --ck-color-list-background: #212529;
    --ck-color-list-button-hover-background: #3a3f44;
    --ck-color-list-button-on-background: #495057;
    --ck-color-list-button-on-text: #fff;
    --ck-color-panel-background: #212529;
    --ck-color-panel-border: #495057;
    --ck-color-text: #dee2e6;
    --ck-color-engine-placeholder-text: #6c757d;
    --ck-focus-ring: 1px solid var(--app-primary);
}

[data-bs-theme=dark] .ck.ck-editor__editable:not(.ck-editor__nested-editable) {
    background-color: #212529;
    color: #dee2e6;
    border-color: #495057;
}

[data-bs-theme=dark] .ck.ck-editor__editable.ck-focused {
    border-color: var(--app-primary);
}

[data-bs-theme=dark] .ck.ck-list__item .ck-button.ck-on {
    background-color: #495057;
    color: #fff;
}

[data-bs-theme=dark] .ck.ck-list__item .ck-button:hover:not(.ck-disabled) {
    background-color: #3a3f44;
}

.navbar-event-logo {
    height: 1.5em;
    max-width: 3em;
    object-fit: contain;
    border-radius: 0.25rem;
    vertical-align: middle;
}

#event-table .btn.py-0 {
    padding-top: .2rem !important;
    padding-bottom: .2rem !important;
}

#event-table .btn.px-2 {
    padding-right: .3rem !important;
    padding-left: .3rem !important;
}

/* Language flag emoji. Rendered as text (Unicode regional-indicator flags)
   instead of an <img>, so bump the size up from body text to stay legible
   next to the language name. */
.lang-flag {
    font-size: 1.4em;
    line-height: 1;
    vertical-align: -0.05em;
}
/* Last-played hydration placeholders (js/core/last-played.js): dim the "…"
   until the batch endpoint fills the cell, then render as normal text. */
[data-last-played]:not([data-lp-done]),
[data-play-count]:not([data-lp-done]) {
    color: var(--bs-secondary-color);
}

/* ==============================================
   Print styles
   ==============================================
   Global print layer: every list and detail view inherits these through
   base.html → radio.css. Goal: black-on-white paper output with no
   interactive chrome, compact tables that repeat their header on every
   page, and cards flattened to thin outlines. Pages can opt individual
   elements in/out with Bootstrap's d-print-none / d-print-block
   utilities; page-specific tweaks live next to the page (e.g.
   css/record-detail.css). */

/* Event name + logo header, rendered in base.html; visible only on paper. */
.print-header {
    display: none;
}

@media print {
    @page {
        margin: 12mm;
    }

    /* Print on a light page regardless of the active theme: reset the
       Bootstrap theme variables that dark mode overrides, then flatten any
       remaining hardcoded dark backgrounds/colors. Category colors are the
       one thing that must survive (schedule printouts rely on them) — they
       are re-asserted at the end of this block so they also win over the
       badge/card flattening below. */
    [data-bs-theme=dark] {
        color-scheme: light;
        --bs-body-bg: #fff;
        --bs-body-color: #000;
        --bs-emphasis-color: #000;
        --bs-secondary-color: rgba(0, 0, 0, 0.75);
        --bs-secondary-bg: #e9ecef;
        --bs-tertiary-color: rgba(0, 0, 0, 0.5);
        --bs-tertiary-bg: #f8f9fa;
        --bs-heading-color: #000;
        --bs-link-color: #000;
        --bs-link-hover-color: #000;
        --bs-border-color: #dee2e6;
    }

    [data-bs-theme=dark] *:not(.category-color) {
        color: #000 !important;
        background-color: transparent !important;
    }

    /* Hide navigation and other screen chrome: app shell, buttons and
       menus, list-page filter/search widgets, DataTables controls
       (search / length / info / paging / export buttons / sort arrows /
       FixedHeader clone / ColumnControl), players and overlays. */
    .navbar,
    .app-sidebar,
    .offcanvas,
    .offcanvas-backdrop,
    .btn,
    .btn-group,
    .btn-toolbar,
    .dropdown-menu,
    .nav,
    .breadcrumb,
    .pagination,
    .modal,
    .modal-backdrop,
    .tooltip,
    .popover,
    .toast-container,
    .feedback-widget-btn,
    .feedback-modal-overlay,
    .alert,
    .app-footer,
    audio,
    video,
    iframe,
    .plyr,
    .plyr-container,
    .spinner-border,
    .spinner-grow,
    .htmx-indicator,
    .driver-popover,
    .driver-overlay,
    input[type="search"],
    .input-group:has(input[type="search"]),
    input[type="file"],
    .form-switch,
    .choices,
    a[hx-get],
    a[hx-post],
    a[hx-delete],
    a[hx-put],
    .dt-search,
    .dt-length,
    .dt-info,
    .dt-paging,
    .dt-buttons,
    .dt-processing,
    .dt-column-order,
    .dtfh-floatingparent,
    .fixedHeader-floating,
    .fixedHeader-locked,
    .dtcc {
        display: none !important;
    }

    /* Content gets the full page width (no fixed navbar/sidebar). */
    .main,
    .main-with-sidebar {
        margin-left: 0 !important;
        padding: 0 !important;
        width: 100% !important;
    }

    .container,
    .container-fluid {
        max-width: 100% !important;
        padding-left: 0 !important;
        padding-right: 0 !important;
    }

    /* Sticky/fixed positioning makes elements repeat or overlap on paper. */
    .sticky-top,
    .sticky-bottom,
    .fixed-top,
    .fixed-bottom {
        position: static !important;
    }

    /* Paper typography: slightly smaller body text, headings kept with
       the content that follows them, no widowed lines. */
    body {
        background: #fff !important;
        font-size: 11pt;
        line-height: 1.35;
        orphans: 3;
        widows: 3;
    }

    h1, h2, h3, h4, h5, h6 {
        break-after: avoid;
    }

    h1 { font-size: 17pt; }
    h2 { font-size: 15pt; }
    h3 { font-size: 13pt; }
    h4, h5, h6 { font-size: 11.5pt; }

    /* Links read as normal text on paper. */
    a,
    a:visited {
        color: inherit !important;
        text-decoration: none !important;
    }

    img,
    canvas,
    svg {
        max-width: 100% !important;
    }

    /* Truncated cells: on paper there is no hover/scroll, so wrap instead
       of losing the text. */
    .text-truncate {
        white-space: normal !important;
        overflow: visible !important;
        text-overflow: clip !important;
    }

    /* Tables: full width, compact cells, visible row separators (screen
       styling often relies on striping, which most printers drop), and
       the header repeated at the top of every printed page. */
    .table-responsive {
        overflow: visible !important;
    }

    thead {
        display: table-header-group;
    }

    tfoot {
        display: table-footer-group;
    }

    .table {
        font-size: 9.5pt;
        width: 100% !important;
    }

    .table > :not(caption) > * > * {
        padding: 0.2rem 0.4rem;
        border-bottom: 1px solid #ccc;
    }

    .table thead th {
        border-bottom: 2px solid #000;
    }

    /* Keep table rows, cards and list items intact across page breaks. */
    tr,
    .card,
    .list-group-item {
        break-inside: avoid;
    }

    /* Cards flatten to thin outlines — shadows and tinted headers turn
       into mud on paper. */
    .card {
        border: 1px solid #bbb !important;
        box-shadow: none !important;
    }

    .card-header,
    .card-footer {
        background-color: transparent !important;
        border-color: #bbb !important;
    }

    .card-header {
        font-weight: 600;
    }

    /* Badges: colored backgrounds don't print by default, which would
       leave invisible white-on-white text — print them as outlined black
       text instead. */
    .badge {
        background-color: transparent !important;
        color: #000 !important;
        border: 1px solid #999;
    }

    /* List-group flattening to match the cards. */
    .list-group-item {
        background-color: transparent !important;
        border-color: #ccc !important;
    }

    /* Progress bars carry information in their fill width: force a
       printable gray fill and a visible track. */
    .progress {
        border: 1px solid #999;
        background-color: transparent !important;
    }

    .progress-bar,
    [data-bs-theme=dark] .progress-bar {
        background-color: #999 !important;
        print-color-adjust: exact;
        -webkit-print-color-adjust: exact;
    }

    /* Any form fields still visible (detail pages sometimes render data
       in read-only inputs) print as plain text with a thin underline. */
    .form-control,
    .form-select,
    textarea.form-control {
        border: none !important;
        border-bottom: 1px solid #ccc !important;
        background-color: transparent !important;
        box-shadow: none !important;
        padding-left: 0 !important;
        padding-right: 0 !important;
    }

    /* Print the true category color, not the dark-mode darkened mix.
       Placed after the badge/card/dark-mode flattening on purpose: equal
       specificity + !important means source order decides, and this must
       win. */
    .category-color,
    [data-bs-theme=dark] .category-color {
        background-color: var(--category-color) !important;
        color: #000 !important;
    }

    .print-header {
        display: flex;
        align-items: center;
        gap: 0.75rem;
        margin-bottom: 1rem;
    }

    .print-header img {
        height: 40px;
        max-width: 120px;
        object-fit: contain;
    }

    .print-header .print-header-title {
        font-size: 1.4rem;
        font-weight: 700;
    }
}
