/* ============================================================
   Dashboard chrome + components — java-mastery.com design
   ------------------------------------------------------------
   Re-skins the admin / student / affiliate shell (top bar, sidebar,
   user menu, notification sheet) with theme.css tokens so the
   dashboards match the public site in both themes, and defines the
   `jm-d*` components that migrated pages are written with.

   Every selector is prefixed `body.jm-dash`, which only the three
   dashboard layouts carry: public pages can never be affected, and
   the prefix outranks the legacy rules in dashboard.css (same
   specificity class count, but this file is linked last).

   Every dashboard page and script has been migrated to this vocabulary,
   so the temporary dashboard-bridge.css (which re-pointed the old Tailwind
   palette at the tokens) is gone. Do not reintroduce palette utilities:
   LegacyPaletteGuardTest fails the build on them.

   The component vocabulary for a page rewrite:
     .jm-dhead / -title / -sub / -actions   page header
     .jm-dgrid + --2 --3 --4                responsive card grid
     .jm-dstat (+ -icon -label -value)      KPI card
     .jm-dcard (+ -head -icon -title -sub -body -foot)
     .jm-dtable-wrap + .jm-table            table in a card
     .jm-davatar (+ --initials)             list avatars
     .jm-dchart                             canvas box
     .jm-dbanner (+ -title -sub)            welcome banner
   Plus everything in site.css: .jm-btn*, .jm-chip*, .jm-empty,
   .jm-progress, .jm-input, .jm-tabs, .jm-alert, .jm-pagination.
   ============================================================ */

/* ---------- base: undo the public-site rules that hurt dashboards ---------- */

/* site.css paints every bare <a> cyan; dashboards have hundreds of
   links inside tables, menus and buttons that must inherit instead.
   Opt in to the public link colour with .jm-link. */
:where(body.jm-dash) a { color: inherit; }
:where(body.jm-dash) a:hover { color: inherit; }
body.jm-dash .jm-link { color: var(--cyan); }
body.jm-dash .jm-link:hover { color: var(--accent-ink); }

/* site.css sets overflow-x:hidden, which kills position:sticky table headers. */
body.jm-dash { overflow-x: visible; background: var(--bg); color: var(--text); }

/* Dashboard chrome runs a notch smaller than the public site; the family itself
   is the site-wide --font-ui stack inherited from body.jm-site. */
body.jm-dash { font-size: 15px; line-height: 1.6; }

/* ---------- top bar ---------- */
body.jm-dash .nav-glass {
    background: var(--hdr-bg);
    backdrop-filter: blur(14px);
    -webkit-backdrop-filter: blur(14px);
    border-bottom: 1px solid var(--hdr-border);
    box-shadow: none;
}
body.jm-dash .nav-icon-btn,
body.jm-dash .notification-btn,
body.jm-dash .dark-mode-btn {
    display: grid;
    place-items: center;
    width: 40px;
    height: 40px;
    border-radius: 11px;
    border: 1px solid var(--border);
    background: var(--card);
    color: var(--muted);
    cursor: pointer;
    transition: color .2s, border-color .2s, transform .2s;
}
/* The `display: grid` above outranks Tailwind's hiding utilities, so restore them:
   the sidebar toggle is `nav-icon-btn lg:hidden` and must disappear on desktop. */
body.jm-dash .nav-icon-btn.hidden,
body.jm-dash .notification-btn.hidden,
body.jm-dash .dark-mode-btn.hidden { display: none; }
@media (min-width: 1024px) {
    body.jm-dash .nav-icon-btn.lg\:hidden,
    body.jm-dash .notification-btn.lg\:hidden,
    body.jm-dash .dark-mode-btn.lg\:hidden { display: none; }
}
body.jm-dash .nav-icon-btn:hover,
body.jm-dash .notification-btn:hover,
body.jm-dash .dark-mode-btn:hover {
    color: var(--accent-ink);
    border-color: var(--border2);
    transform: translateY(-2px);
}
body.jm-dash .notification-btn .notif-dot,
body.jm-dash #notification-badge {
    background: var(--danger);
    color: #fff;
    border: 2px solid var(--bg2);
}

/* ============================================================
   Sidebar — collapsible rail
   ------------------------------------------------------------
   Two widths, driven by one variable so the sidebar and the main
   column can never disagree: --jm-sb-w. `html.sb-collapsed` is set
   by the bootstrap in fragments/head.html before first paint, so a
   collapsed rail never flashes open on load.

   Below `lg` the rail is a drawer: off-canvas, slid in by .open
   (app.js initSidebar, #sidebar-toggle) with #sidebar-overlay behind
   it. Collapsing is a desktop-only idea, so the drawer ignores it.
   ============================================================ */
body.jm-dash {
    --jm-sb-w: 16rem;
    --jm-sb-w-collapsed: 4.5rem;
}
html.sb-collapsed body.jm-dash { --jm-sb-w: var(--jm-sb-w-collapsed); }

body.jm-dash #sidebar {
    position: fixed;
    top: 4rem;
    inset-inline-start: 0;
    z-index: 20;
    height: calc(100vh - 4rem);
    width: var(--jm-sb-w);
    display: flex;
    flex-direction: column;
    background: var(--bg2);
    border-inline-end: 1px solid var(--border);
    transition: width .18s ease, transform .2s ease-in-out;
}
html.dark body.jm-dash #sidebar { background: linear-gradient(180deg, var(--bg2), var(--bg)); }

/* ---------- head: search + collapse ---------- */
body.jm-dash .jm-dsb-head {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 14px 12px 10px;
    border-bottom: 1px solid var(--border);
}
body.jm-dash .jm-dsb-search { position: relative; flex: 1; min-width: 0; }
body.jm-dash .jm-dsb-search-ico {
    position: absolute;
    inset-inline-start: 10px;
    top: 50%;
    transform: translateY(-50%);
    width: 15px;
    height: 15px;
    color: var(--faint);
    pointer-events: none;
}
body.jm-dash .jm-dsb-search-input {
    width: 100%;
    background: var(--card);
    border: 1px solid var(--border);
    border-radius: 10px;
    color: var(--text);
    font-family: inherit;
    font-size: .85rem;
    padding: 8px 10px;
    padding-inline-start: 31px;
    padding-inline-end: 38px;
    appearance: none;
}
body.jm-dash .jm-dsb-search-input::placeholder { color: var(--faint); }
body.jm-dash .jm-dsb-search-input:focus {
    outline: none;
    border-color: var(--accent);
    background: var(--bg2);
}
body.jm-dash .jm-dsb-search-input::-webkit-search-cancel-button { filter: grayscale(1) opacity(.6); }
body.jm-dash .jm-dsb-kbd {
    position: absolute;
    inset-inline-end: 8px;
    top: 50%;
    transform: translateY(-50%);
    font-family: var(--mono);
    font-size: .66rem;
    color: var(--faint);
    background: var(--card2);
    border: 1px solid var(--border);
    border-radius: 6px;
    padding: 1px 5px;
    pointer-events: none;
}
body.jm-dash .jm-dsb-collapse {
    flex: none;
    display: grid;
    place-items: center;
    width: 34px;
    height: 34px;
    border-radius: 10px;
    border: 1px solid var(--border);
    background: var(--card);
    color: var(--muted);
    cursor: pointer;
    transition: color .18s, border-color .18s;
}
body.jm-dash .jm-dsb-collapse:hover { color: var(--accent-ink); border-color: var(--border2); }
body.jm-dash .jm-dsb-collapse svg { width: 17px; height: 17px; transition: transform .18s; }
html.sb-collapsed body.jm-dash .jm-dsb-collapse svg { transform: rotate(180deg); }
[dir="rtl"] html.sb-collapsed body.jm-dash .jm-dsb-collapse svg { transform: rotate(180deg) scaleX(-1); }

/* ---------- scroll area ---------- */
body.jm-dash .jm-dsb-scroll {
    flex: 1;
    overflow-y: auto;
    overflow-x: hidden;
    padding: 10px 10px 22px;
    scrollbar-width: thin;
    scrollbar-color: var(--border) transparent;
}
body.jm-dash .jm-dsb-scroll::-webkit-scrollbar { width: 4px; }
body.jm-dash .jm-dsb-scroll::-webkit-scrollbar-thumb { background: var(--border); border-radius: 10px; }
body.jm-dash .jm-dsb-scroll::-webkit-scrollbar-thumb:hover { background: var(--faint); }

body.jm-dash .jm-dsb-list { list-style: none; margin: 0 0 2px; padding: 0; }
body.jm-dash .jm-dsb-group + .jm-dsb-group,
body.jm-dash .jm-dsb-group + .jm-dsb-sec { margin-top: 6px; }
body.jm-dash .jm-dsb-section {
    font-size: .64rem;
    font-weight: 700;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--faint);
    margin: 14px 0 6px;
    padding-inline: 10px;
}
body.jm-dash .jm-dsb-sec:first-child .jm-dsb-section { margin-top: 2px; }

/* ---------- an item ---------- */
body.jm-dash .jm-dsb-item { position: relative; display: flex; align-items: center; }
/* A submenu parent is wrapped in a <div> that also holds its <ul>, so the row
   must stretch through that wrapper. */
body.jm-dash .jm-dsb-item > div { flex: 1; min-width: 0; }
body.jm-dash .jm-dsb-link {
    /* positioned so the active bar measures the row, not the item + its submenu */
    position: relative;
    flex: 1;
    width: 100%;
    min-width: 0;
    display: flex;
    align-items: center;
    gap: 11px;
    padding: 9px 10px;
    border-radius: 11px;
    color: var(--muted);
    font-size: .875rem;
    font-weight: 600;
    text-align: start;
    background: none;
    border: 0;
    cursor: pointer;
    font-family: inherit;
    transition: background .15s, color .15s;
}
body.jm-dash .jm-dsb-link:hover { background: var(--card); color: var(--text); }
body.jm-dash .jm-dsb-link.is-active {
    background: rgba(249, 161, 27, .12);
    color: var(--accent-ink);
    font-weight: 700;
}
body.jm-dash .jm-dsb-link.is-active::before {
    content: "";
    position: absolute;
    inset-inline-start: -10px;
    top: 50%;
    transform: translateY(-50%);
    width: 3px;
    height: 56%;
    border-radius: 0 3px 3px 0;
    background: var(--grad);
}
[dir="rtl"] body.jm-dash .jm-dsb-link.is-active::before { border-radius: 3px 0 0 3px; }
body.jm-dash .jm-dsb-ico {
    flex: none;
    display: grid;
    place-items: center;
    width: 26px;
    height: 26px;
    border-radius: 8px;
    background: var(--card);
    color: var(--faint);
    transition: background .15s, color .15s;
}
body.jm-dash .jm-dsb-ico svg { width: 15px; height: 15px; stroke-width: 1.9; }
body.jm-dash .jm-dsb-link:hover .jm-dsb-ico { color: var(--text); }
body.jm-dash .jm-dsb-link.is-active .jm-dsb-ico {
    background: rgba(249, 161, 27, .18);
    color: var(--accent-ink);
}
body.jm-dash .jm-dsb-label {
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
body.jm-dash .jm-dsb-chev {
    flex: none;
    width: 14px;
    height: 14px;
    color: var(--faint);
    transition: transform .18s;
}
body.jm-dash .jm-dsb-link.is-open .jm-dsb-chev { transform: rotate(180deg); }

/* submenu */
body.jm-dash .jm-dsb-sub { list-style: none; margin: 2px 0 4px; padding: 0; padding-inline-start: 37px; }
body.jm-dash .jm-dsb-sublink {
    display: block;
    padding: 6px 10px;
    border-radius: 9px;
    font-size: .8125rem;
    font-weight: 600;
    color: var(--muted);
    transition: background .15s, color .15s;
}
body.jm-dash .jm-dsb-sublink:hover { background: var(--card); color: var(--text); }
body.jm-dash .jm-dsb-sublink.is-active { color: var(--accent-ink); }

/* attention badges (pending reviews, affiliate + discount alerts) */
body.jm-dash .jm-dsb-badge {
    flex: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 1.25rem;
    height: 1.25rem;
    padding: 0 .375rem;
    border-radius: 999px;
    font-size: .7rem;
    font-weight: 700;
    line-height: 1;
    background: var(--grad);
    color: var(--btn-text);
}
body.jm-dash .jm-dsb-badge--alert { background: var(--danger); color: #fff; }
body.jm-dash .jm-dsb-bell { width: 15px; height: 15px; color: var(--danger); flex: none; }

/* pin button — appears on hover / focus, stays put once pinned */
body.jm-dash .jm-dsb-pin {
    position: absolute;
    inset-inline-end: 6px;
    display: grid;
    place-items: center;
    width: 24px;
    height: 24px;
    border: 0;
    border-radius: 7px;
    background: none;
    color: var(--faint);
    cursor: pointer;
    opacity: 0;
    transition: opacity .15s, color .15s, background .15s;
}
body.jm-dash .jm-dsb-pin svg { width: 14px; height: 14px; }
body.jm-dash .jm-dsb-item:hover .jm-dsb-pin,
body.jm-dash .jm-dsb-pin:focus-visible { opacity: 1; }
body.jm-dash .jm-dsb-pin:hover { background: var(--card2); color: var(--accent-ink); }
body.jm-dash .jm-dsb-pin.is-pinned { opacity: 1; color: var(--accent); }
/* a badge and the pin would collide, so the badge steps aside on hover */
body.jm-dash .jm-dsb-item:hover .jm-dsb-badge { margin-inline-end: 26px; }

body.jm-dash .jm-dsb-noresults {
    display: none;
    color: var(--faint);
    font-size: .82rem;
    text-align: center;
    padding: 22px 10px;
}
body.jm-dash .jm-dsb-noresults[hidden] { display: none; }
body.jm-dash .jm-dsb-noresults.is-shown { display: block; }
body.jm-dash .jm-dsb-item[hidden],
body.jm-dash .jm-dsb-sec[hidden],
body.jm-dash .jm-dsb-group[hidden] { display: none; }

/* ============================================================
   Collapsed rail (desktop only)
   ============================================================ */
@media (min-width: 1024px) {
    html.sb-collapsed body.jm-dash .jm-dsb-search,
    html.sb-collapsed body.jm-dash .jm-dsb-label,
    html.sb-collapsed body.jm-dash .jm-dsb-chev,
    html.sb-collapsed body.jm-dash .jm-dsb-pin,
    html.sb-collapsed body.jm-dash .jm-dsb-sub,
    html.sb-collapsed body.jm-dash .jm-dsb-section { display: none; }

    html.sb-collapsed body.jm-dash .jm-dsb-head { justify-content: center; padding-inline: 0; }
    html.sb-collapsed body.jm-dash .jm-dsb-scroll { padding-inline: 8px; }
    html.sb-collapsed body.jm-dash .jm-dsb-link { justify-content: center; padding-inline: 0; gap: 0; }
    html.sb-collapsed body.jm-dash .jm-dsb-link.is-active::before { inset-inline-start: -8px; }
    /* a group break reads as a divider once its label is gone */
    html.sb-collapsed body.jm-dash .jm-dsb-sec + .jm-dsb-sec,
    html.sb-collapsed body.jm-dash .jm-dsb-group + .jm-dsb-group,
    html.sb-collapsed body.jm-dash .jm-dsb-group + .jm-dsb-sec {
        border-top: 1px solid var(--border);
        padding-top: 8px;
        margin-top: 8px;
    }

    /* the badge shrinks to a dot on the icon */
    html.sb-collapsed body.jm-dash .jm-dsb-badge {
        position: absolute;
        top: 4px;
        inset-inline-end: 12px;
        min-width: 8px;
        height: 8px;
        padding: 0;
        font-size: 0;
        margin-inline-end: 0 !important;
    }
    html.sb-collapsed body.jm-dash .jm-dsb-bell { display: none; }

    /* hover flyout carrying the label the rail no longer shows */
    html.sb-collapsed body.jm-dash .jm-dsb-link::after {
        content: attr(data-label);
        position: absolute;
        inset-inline-start: calc(100% + 10px);
        top: 50%;
        transform: translateY(-50%);
        white-space: nowrap;
        background: var(--bg2);
        color: var(--text);
        border: 1px solid var(--border);
        box-shadow: var(--shadow);
        border-radius: 9px;
        padding: 6px 11px;
        font-size: .82rem;
        font-weight: 600;
        opacity: 0;
        pointer-events: none;
        transition: opacity .12s;
        z-index: 40;
    }
    html.sb-collapsed body.jm-dash .jm-dsb-link:hover::after,
    html.sb-collapsed body.jm-dash .jm-dsb-link:focus-visible::after { opacity: 1; }
}

/* ============================================================
   Drawer behaviour below lg
   ============================================================ */
@media (max-width: 1023px) {
    body.jm-dash #sidebar {
        width: 16rem;
        transform: translateX(-100%);
    }
    [dir="rtl"] body.jm-dash #sidebar { transform: translateX(100%); }
    body.jm-dash #sidebar.open { transform: translateX(0); }
}

body.jm-dash #sidebar-overlay { background: rgba(3, 6, 15, .55); }

/* The main column tracks the rail width (logical margin, so RTL follows). */
body.jm-dash .jm-dmain { transition: margin .18s ease; }
@media (min-width: 1024px) {
    body.jm-dash .jm-dmain { margin-inline-start: var(--jm-sb-w); }
}

/* ---------- notification sheet ---------- */
body.jm-dash .notification-sheet {
    background: var(--bg2);
    border: 1px solid var(--border);
    box-shadow: var(--shadow);
    color: var(--text);
}
body.jm-dash .notification-sheet__handle { background: var(--border); }
body.jm-dash .notification-sheet__header,
body.jm-dash .notification-sheet__footer { border-color: var(--border); }
body.jm-dash .notification-sheet__title { color: var(--text); }
body.jm-dash .notification-sheet__mark-all,
body.jm-dash .notification-sheet__view-all { color: var(--accent-ink); }
body.jm-dash .notification-sheet__mark-all:hover,
body.jm-dash .notification-sheet__view-all:hover { color: var(--accent); }
body.jm-dash .notification-sheet__close { color: var(--faint); }
body.jm-dash .notification-sheet__close:hover { color: var(--text); background: var(--card); }
body.jm-dash .notification-sheet__empty { color: var(--faint); }
body.jm-dash .notification-item { border-color: var(--border); color: var(--text); }
body.jm-dash .notification-item:hover { background: var(--card); }

/* ---------- user menu ---------- */
body.jm-dash .user-menu-trigger {
    background: var(--card);
    border: 1px solid var(--border);
    color: var(--text);
}
body.jm-dash .user-menu-trigger:hover,
body.jm-dash .user-menu-trigger[aria-expanded="true"] {
    border-color: var(--border2);
    background: var(--card2);
}
body.jm-dash .user-menu-name { color: var(--text); }
body.jm-dash .user-menu-chevron { color: var(--faint); }
body.jm-dash .user-menu-pop {
    background: var(--bg2);
    border: 1px solid var(--border);
    box-shadow: var(--shadow);
}
body.jm-dash .user-menu-header { border-color: var(--border); }
body.jm-dash .user-menu-header__avatar { background: var(--card); }
body.jm-dash .user-menu-header__name { color: var(--text); }
body.jm-dash .user-menu-header__email,
body.jm-dash .user-menu-label { color: var(--faint); }
body.jm-dash .user-menu-divider { background: var(--border); }
body.jm-dash .user-menu-item { color: var(--text); }
body.jm-dash .user-menu-item:hover { background: var(--card); }
body.jm-dash .user-menu-item__icon { color: var(--faint); }
body.jm-dash .user-menu-item:hover .user-menu-item__icon { color: var(--accent-ink); }
body.jm-dash .user-menu-item--danger { color: var(--danger); }
body.jm-dash .user-menu-item--danger .user-menu-item__icon { color: var(--danger); }
body.jm-dash .user-menu-item--danger:hover { background: var(--danger-soft); }
body.jm-dash .user-menu-item--toggle .user-menu-switch { background: var(--card2); border: 1px solid var(--border); }
body.jm-dash .user-menu-switch__knob { background: var(--faint); }
html.dark body.jm-dash .user-menu-item--toggle .user-menu-switch { background: var(--grad); border-color: transparent; }
html.dark body.jm-dash .user-menu-switch__knob { background: var(--btn-text); }
body.jm-dash .user-menu-lang {
    background: var(--card);
    border: 1px solid var(--border);
    color: var(--muted);
}
body.jm-dash .user-menu-lang:hover { border-color: var(--border2); color: var(--text); }
body.jm-dash .user-menu-lang.is-active {
    background: var(--grad);
    border-color: transparent;
    color: var(--btn-text);
}
body.jm-dash .user-menu-lang.is-active .user-menu-lang__label { color: var(--btn-text); }

/* ---------- language menu (student / affiliate bars) ---------- */
body.jm-dash .lang-menu-btn {
    background: var(--card);
    border: 1px solid var(--border);
    color: var(--muted);
}
body.jm-dash .lang-menu-btn:hover,
body.jm-dash .lang-menu-btn[aria-expanded="true"] { border-color: var(--border2); color: var(--text); }
body.jm-dash .lang-menu-badge { background: var(--card2); color: var(--muted); }
body.jm-dash .lang-menu-pop {
    background: var(--bg2);
    border: 1px solid var(--border);
    box-shadow: var(--shadow);
}
body.jm-dash .lang-menu-item { color: var(--text); }
body.jm-dash .lang-menu-item:hover { background: var(--card); }
body.jm-dash .lang-menu-item.is-active { color: var(--accent-ink); }
body.jm-dash .lang-menu-check { color: var(--accent-ink); }
body.jm-dash .lang-switch { background: var(--card); border: 1px solid var(--border); }
body.jm-dash .lang-switch a { color: var(--muted); }
body.jm-dash .lang-switch a:hover { color: var(--text); }
body.jm-dash .lang-switch a.lang-active { background: var(--grad); color: var(--btn-text); }

/* ---------- shared fragments inside dashboard pages ---------- */
/* The public pagination sits under a hero with 44px of air; in a dashboard
   card it is already inside padding. */
body.jm-dash .jm-pagination { margin-top: 0; gap: 4px; }
body.jm-dash .jm-pagination a,
body.jm-dash .jm-pagination span { min-width: 36px; height: 36px; gap: 6px; }
body.jm-dash .jm-alert { align-items: center; }
body.jm-dash .jm-alert svg { width: 20px; height: 20px; }

/* ---------- avatars ---------- */
body.jm-dash .avatar-circle { background: var(--card2); color: var(--text); }
body.jm-dash .avatar-initials { background: var(--grad); color: var(--btn-text); }
body.jm-dash .nav-avatar-overlay { background: rgba(3, 6, 15, .55); color: #fff; }

/* ============================================================
   Dashboard components (migrated pages)
   ============================================================ */

/* ---------- page header ---------- */
body.jm-dash .jm-dhead {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 16px;
    flex-wrap: wrap;
    margin-bottom: 24px;
}
body.jm-dash .jm-dhead-title {
    font-size: 1.5rem;
    font-weight: 800;
    letter-spacing: -.02em;
    color: var(--text);
    margin: 0;
}
body.jm-dash .jm-dhead-sub { color: var(--muted); font-size: .9rem; margin: 4px 0 0; }
body.jm-dash .jm-dhead-actions { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }

/* ---------- welcome banner ---------- */
body.jm-dash .jm-dbanner {
    position: relative;
    overflow: hidden;
    background: linear-gradient(135deg, var(--bg2), var(--card));
    border: 1px solid var(--border2);
    border-radius: var(--r);
    padding: 28px 32px;
    margin-bottom: 24px;
}
body.jm-dash .jm-dbanner::before {
    content: "";
    position: absolute;
    inset-block: -60%;
    inset-inline-end: -10%;
    width: 420px;
    background: radial-gradient(circle, var(--hero-glow1) 0%, transparent 62%);
    pointer-events: none;
}
body.jm-dash .jm-dbanner > * { position: relative; z-index: 1; }
body.jm-dash .jm-dbanner-title { font-size: 1.5rem; font-weight: 800; letter-spacing: -.02em; margin: 0; color: var(--text); }
body.jm-dash .jm-dbanner-sub { color: var(--muted); font-size: .9rem; margin: 6px 0 0; }
body.jm-dash .jm-dbanner-name {
    background: var(--grad-text);
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
}

/* ---------- card grid ---------- */
body.jm-dash .jm-dgrid { display: grid; grid-template-columns: 1fr; gap: 18px; margin-bottom: 26px; }
@media (min-width: 640px) {
    body.jm-dash .jm-dgrid--2, body.jm-dash .jm-dgrid--3, body.jm-dash .jm-dgrid--4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (min-width: 1024px) {
    body.jm-dash .jm-dgrid--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
    body.jm-dash .jm-dgrid--4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
    body.jm-dash .jm-dgrid--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* ---------- KPI card ---------- */
body.jm-dash .jm-dstat {
    position: relative;
    display: flex;
    align-items: center;
    gap: 16px;
    background: var(--bg2);
    border: 1px solid var(--border);
    border-radius: var(--r);
    padding: 22px 24px;
    overflow: hidden;
    transition: transform .25s, box-shadow .25s, border-color .25s;
}
body.jm-dash .jm-dstat::before {
    content: "";
    position: absolute;
    inset-inline: 0;
    top: 0;
    height: 3px;
    background: var(--grad);
}
body.jm-dash .jm-dstat:hover { transform: translateY(-3px); border-color: var(--border2); box-shadow: var(--shadow); }
body.jm-dash .jm-dstat-icon {
    flex: none;
    display: grid;
    place-items: center;
    width: 46px;
    height: 46px;
    border-radius: 13px;
    background: rgba(249, 161, 27, .14);
    color: var(--accent-ink);
}
body.jm-dash .jm-dstat-icon svg { width: 22px; height: 22px; }
body.jm-dash .jm-dstat-label { color: var(--muted); font-size: .82rem; font-weight: 600; margin: 0 0 4px; }
body.jm-dash .jm-dstat-value { color: var(--text); font-size: 1.7rem; font-weight: 800; line-height: 1; letter-spacing: -.02em; margin: 0; }
body.jm-dash .jm-dstat-value small { font-size: .95rem; font-weight: 700; color: var(--muted); }

/* ---------- panel ---------- */
body.jm-dash .jm-dcard {
    background: var(--bg2);
    border: 1px solid var(--border);
    border-radius: var(--r);
    overflow: hidden;
}
body.jm-dash .jm-dcard--pad { padding: 22px 24px; }
body.jm-dash .jm-dcard--spaced { margin-bottom: 26px; }
body.jm-dash .jm-dcard-head {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 18px 24px;
    border-bottom: 1px solid var(--border);
}
body.jm-dash .jm-dcard--pad .jm-dcard-head { padding: 0 0 16px; border-bottom: 0; }
body.jm-dash .jm-dcard-icon {
    flex: none;
    display: grid;
    place-items: center;
    width: 34px;
    height: 34px;
    border-radius: 10px;
    background: rgba(249, 161, 27, .14);
    color: var(--accent-ink);
}
body.jm-dash .jm-dcard-icon svg { width: 18px; height: 18px; }
body.jm-dash .jm-dcard-title { font-size: .95rem; font-weight: 700; color: var(--text); margin: 0; }
body.jm-dash .jm-dcard-sub { font-size: .8rem; color: var(--muted); margin: 2px 0 0; }
body.jm-dash .jm-dcard-actions { margin-inline-start: auto; display: flex; align-items: center; gap: 8px; }
body.jm-dash .jm-dcard-body { padding: 20px 24px; }
/* Section heading outside a card (icon + title), same anatomy as a card head. */
body.jm-dash .jm-dsec-head { display: flex; align-items: center; gap: 12px; margin-bottom: 14px; }
body.jm-dash .jm-dcard-foot { padding: 14px 24px; border-top: 1px solid var(--border); }

/* ---------- table inside a card ---------- */
body.jm-dash .jm-dtable-wrap { overflow-x: auto; }
body.jm-dash .jm-dtable-wrap .jm-table th { background: var(--card); white-space: nowrap; }
body.jm-dash .jm-dtable-wrap .jm-table th:first-child,
body.jm-dash .jm-dtable-wrap .jm-table td:first-child { padding-inline-start: 24px; }
body.jm-dash .jm-dtable-wrap .jm-table th:last-child,
body.jm-dash .jm-dtable-wrap .jm-table td:last-child { padding-inline-end: 24px; }
body.jm-dash .jm-table tr:last-child td { border-bottom: 0; }
body.jm-dash .jm-tcell-title { font-weight: 600; color: var(--text); margin: 0; }
body.jm-dash .jm-tcell-sub { font-size: .78rem; color: var(--muted); margin: 2px 0 0; }
body.jm-dash .jm-tcell-empty { text-align: center; color: var(--faint); padding: 34px 14px; }

/* ---------- avatars in lists ---------- */
body.jm-dash .jm-davatar {
    width: 38px;
    height: 38px;
    border-radius: 50%;
    object-fit: cover;
    flex: none;
    border: 1px solid var(--border);
}
body.jm-dash .jm-davatar--initials {
    display: grid;
    place-items: center;
    background: var(--grad);
    color: var(--btn-text);
    font-weight: 700;
    font-size: .78rem;
    border-color: transparent;
}

/* ---------- chart box ---------- */
body.jm-dash .jm-dchart { position: relative; height: 280px; margin-top: 16px; }
body.jm-dash .jm-dchart--sm { height: 220px; }

/* ---------- small chip, for dense table cells ---------- */
body.jm-dash .jm-chip--sm { font-size: .74rem; padding: 3px 10px; gap: 5px; }
body.jm-dash .jm-chip--sm svg { width: 12px; height: 12px; }

/* ---------- "continue learning" card (student dashboard) ---------- */
body.jm-dash .jm-dresume {
    display: flex;
    flex-direction: column;
    max-width: 680px;
    background: var(--bg2);
    border: 1px solid var(--border);
    border-radius: var(--r);
    overflow: hidden;
    transition: transform .25s, border-color .25s, box-shadow .25s;
}
body.jm-dash .jm-dresume:hover { transform: translateY(-3px); border-color: var(--border2); box-shadow: var(--shadow); }
body.jm-dash .jm-dresume-thumb {
    position: relative;
    display: grid;
    place-items: center;
    aspect-ratio: 16 / 9;
    background: var(--thumb-bg);
    flex: none;
}
body.jm-dash .jm-dresume-thumb img { width: 100%; height: 100%; object-fit: cover; }
body.jm-dash .jm-dresume-thumb > svg { width: 46px; height: 46px; color: var(--faint); }
body.jm-dash .jm-dresume-cat {
    position: absolute;
    top: 10px;
    inset-inline-start: 10px;
    background: var(--hdr-bg);
    backdrop-filter: blur(8px);
    color: var(--text);
    font-size: .72rem;
    font-weight: 700;
    padding: 4px 10px;
    border-radius: 999px;
    border: 1px solid var(--border);
}
body.jm-dash .jm-dresume-body { padding: 20px 22px; display: flex; flex-direction: column; justify-content: center; flex: 1; }
body.jm-dash .jm-dresume-title { font-size: 1.05rem; font-weight: 700; color: var(--text); margin: 0 0 12px; }
body.jm-dash .jm-dresume-meta {
    display: flex;
    justify-content: space-between;
    gap: 12px;
    font-size: .8rem;
    color: var(--muted);
    margin-bottom: 7px;
}
body.jm-dash .jm-dresume-cta {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    margin-top: 16px;
    font-size: .9rem;
    font-weight: 700;
    color: var(--accent-ink);
}
body.jm-dash .jm-dresume-cta svg { width: 16px; height: 16px; }
@media (min-width: 640px) {
    body.jm-dash .jm-dresume { flex-direction: row; }
    body.jm-dash .jm-dresume-thumb { width: 240px; aspect-ratio: auto; }
}

/* ---------- inner course nav (fragments/sidebar-course.html) ---------- */
body.jm-dash .jm-dsubnav {
    width: 14rem;
    flex: none;
    border-inline-end: 1px solid var(--border);
    padding-inline-end: 1rem;
    margin-inline-end: 1.5rem;
}
body.jm-dash .jm-dsubnav-label {
    font-size: .7rem;
    font-weight: 700;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--faint);
    margin: 0 0 .75rem;
}
body.jm-dash .jm-dsubnav-link {
    display: flex;
    align-items: center;
    gap: .5rem;
    padding: .5rem .75rem;
    font-size: .875rem;
    color: var(--muted);
    border-radius: 0 10px 10px 0;
    border-inline-start: 2px solid transparent;
    transition: background .15s, color .15s, border-color .15s;
}
[dir="rtl"] body.jm-dash .jm-dsubnav-link { border-radius: 10px 0 0 10px; }
body.jm-dash .jm-dsubnav-link:hover { background: var(--card); color: var(--text); }
body.jm-dash .jm-dsubnav-link.is-active {
    color: var(--accent-ink);
    font-weight: 700;
    border-inline-start-color: var(--accent);
    background: rgba(249, 161, 27, .1);
}

/* ---------- affiliate area ---------- */
/* affiliate/tickets/index.html — ticket-create.js closes the modal on
   `e.target === modal`, so the scrim MUST be the .jm-modal element itself
   and not a .jm-modal-backdrop child (a child would swallow the click).
   This paints the container the way .jm-modal-backdrop paints its sibling. */
body.jm-dash .jm-dmodal-scrim {
    background: rgba(3, 6, 15, .7);
    backdrop-filter: blur(4px);
    -webkit-backdrop-filter: blur(4px);
}

/* affiliate/tickets/detail.html — the ticket conversation: a divided list of
   messages, with staff replies tinted so they read apart from the affiliate's. */
body.jm-dash .jm-dthread > li { padding: 16px 24px; border-bottom: 1px solid var(--border); }
body.jm-dash .jm-dthread > li:last-child { border-bottom: 0; }
body.jm-dash .jm-dthread-admin { background: var(--card); }
body.jm-dash .jm-dthread-msg { color: var(--muted); font-size: .9rem; white-space: pre-line; margin: 0; }
body.jm-dash .jm-dthread-who { font-size: .9rem; font-weight: 700; color: var(--text); }

/* affiliate/tickets/detail.html — reply avatar for a non-staff author; the
   accent-gradient .jm-davatar--initials is reserved for staff replies. */
body.jm-dash .jm-davatar--muted {
    background: var(--card2);
    color: var(--muted);
    border-color: var(--border);
}

/* dashboard/affiliates/*.html — soft "positive" action button (Approve,
   Mark Paid). Mirrors .jm-btn-danger from site.css on the success tokens;
   a full .jm-btn-p per table row is far too loud. */
body.jm-dash .jm-dbtn-success {
    background: var(--success-soft);
    border-color: var(--success-border);
    color: var(--success);
}
body.jm-dash .jm-dbtn-success:hover {
    color: var(--success);
    border-color: var(--success);
    transform: translateY(-2px);
}

/* dashboard/affiliates/index.html — open-request count riding inside the
   primary "Withdrawal Requests" button. */
body.jm-dash .jm-dcount {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 20px;
    height: 20px;
    padding: 0 6px;
    border-radius: 999px;
    background: rgba(0, 0, 0, .16);
    background: color-mix(in srgb, var(--btn-text) 18%, transparent);
    color: inherit;
    font-size: .72rem;
    font-weight: 800;
    line-height: 1;
}

/* ==== BEGIN page components (merged from the phase-2 rewrite) ==== */
/* ---------- student ---------- */
/* student/roadmaps/index.html — roadmap cards have no thumbnail image; a
   gradient band carrying the "path" icon stands in for one. */
body.jm-dash .jm-droadmap-thumb {
    display: grid;
    place-items: center;
    height: 128px;
    background: var(--grad);
    color: var(--btn-text);
    flex: none;
}
body.jm-dash .jm-droadmap-thumb svg {
    width: 46px;
    height: 46px;
    opacity: .5;
}

/* student/rewards/history.html, student/rewards/index.html — a compact KPI
   that sits in the page-header actions row instead of in the card grid. */
body.jm-dash .jm-dstat--inline { padding: 12px 18px; gap: 12px; }
body.jm-dash .jm-dstat--inline .jm-dstat-icon { width: 38px; height: 38px; border-radius: 11px; }
body.jm-dash .jm-dstat--inline .jm-dstat-icon svg { width: 19px; height: 19px; }
body.jm-dash .jm-dstat--inline .jm-dstat-value { font-size: 1.25rem; }

/* student/rewards/*, student/payments/*, student/tickets/* — small round icon
   badge for a table row or list item. .jm-dstat-icon is card-sized; this is
   the list-sized sibling. */
body.jm-dash .jm-dbadge-icon {
    flex: none;
    display: grid;
    place-items: center;
    width: 36px;
    height: 36px;
    border-radius: 50%;
    background: var(--card2);
    color: var(--muted);
}
body.jm-dash .jm-dbadge-icon svg { width: 16px; height: 16px; }
body.jm-dash .jm-dbadge-icon--accent { background: rgba(249, 161, 27, .14); color: var(--accent-ink); }
body.jm-dash .jm-dbadge-icon--success { background: var(--success-soft); color: var(--success); }
body.jm-dash .jm-dbadge-icon--danger { background: var(--danger-soft); color: var(--danger); }
body.jm-dash .jm-dbadge-icon--warn { background: var(--warn-soft); color: var(--warn); }
body.jm-dash .jm-dbadge-icon--cyan { background: var(--cyan-soft); color: var(--cyan); }
body.jm-dash .jm-dbadge-icon--lg { width: 48px; height: 48px; }
body.jm-dash .jm-dbadge-icon--lg svg { width: 22px; height: 22px; }

/* Semantic text colour for signed numbers, status words and "copied!" icons
   inside student tables, where a chip or an alert would be too heavy
   (rewards history, payments, subscriptions, profile). */
body.jm-dash .jm-dtxt--success { color: var(--success); }
body.jm-dash .jm-dtxt--danger { color: var(--danger); }
body.jm-dash .jm-dtxt--warn { color: var(--warn); }
body.jm-dash .jm-dtxt--accent { color: var(--accent-ink); }

/* student/tickets/*, student/subscriptions/index.html — site.css ships
   --muted/--cyan/--success/--danger chips but no warning chip, which the
   PENDING / EXPIRING states need. */
body.jm-dash .jm-chip--warn { color: var(--warn); background: var(--warn-soft); border-color: var(--warn-border); }

/* student/tickets/index.html — ticket-create.js closes the modal on a click
   whose target IS the modal root, so the scrim must live on the root instead
   of in a .jm-modal-backdrop child. */
body.jm-dash .jm-modal--scrim { background: rgba(3, 6, 15, .7); backdrop-filter: blur(4px); }

/* student/tickets/index.html — themed native file picker. */
body.jm-dash .jm-dfile { width: 100%; font-size: .88rem; color: var(--muted); }
body.jm-dash .jm-dfile::file-selector-button {
    margin-inline-end: 14px;
    padding: 8px 16px;
    border-radius: 10px;
    border: 1px solid var(--border);
    background: var(--card);
    color: var(--text);
    font: inherit;
    font-weight: 700;
    cursor: pointer;
}
body.jm-dash .jm-dfile::file-selector-button:hover { border-color: var(--border2); color: var(--accent-ink); }
body.jm-dash .jm-dfile--xs { font-size: .78rem; }
body.jm-dash .jm-dfile--xs::file-selector-button { margin-inline-end: 8px; padding: 5px 12px; border-radius: 8px; font-size: .78rem; }

/* student/tickets/detail.html — conversation rows inside a card; admin
   replies get a tinted row so the two voices are distinguishable. */
body.jm-dash .jm-dthread > * + * { border-top: 1px solid var(--border); }
body.jm-dash .jm-dthread-item { padding: 16px 24px; }
body.jm-dash .jm-dthread-item--admin { background: var(--card); }

/* student/tickets/detail.html — a neutral initials avatar, so the gradient
   .jm-davatar--initials can stay reserved for staff replies. */
body.jm-dash .jm-davatar--muted { background: var(--card2); color: var(--muted); border-color: var(--border); }

/* student/payments/detail.html — label/value rows in the "financial details"
   panel, with a highlighted total row. */
body.jm-dash .jm-dkv {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    padding: 10px 0;
    border-bottom: 1px solid var(--border);
    font-size: .9rem;
}
body.jm-dash .jm-dkv:last-child { border-bottom: 0; }
body.jm-dash .jm-dkv > :first-child { color: var(--muted); }
body.jm-dash .jm-dkv > :last-child { color: var(--text); font-weight: 600; }
body.jm-dash .jm-dkv--total {
    background: var(--card);
    border-radius: var(--r-sm);
    border-bottom: 0;
    padding: 12px 16px;
    margin-top: 6px;
}
body.jm-dash .jm-dkv--total > :first-child { color: var(--text); font-weight: 700; }
body.jm-dash .jm-dkv--total > :last-child { font-size: 1.05rem; font-weight: 800; }

/* student/payments/detail.html — "payment summary" tile: the brand gradient
   with ink-on-gradient text, so the page needs no text-white. */
body.jm-dash .jm-dsummary {
    background: var(--grad);
    color: var(--btn-text);
    border-radius: var(--r);
    padding: 24px;
    box-shadow: var(--glow);
}
body.jm-dash .jm-dsummary-amount { font-size: 1.9rem; font-weight: 800; letter-spacing: -.02em; margin: 0 0 2px; }
body.jm-dash .jm-dsummary-foot {
    margin-top: 16px;
    padding-top: 16px;
    border-top: 1px solid rgba(22, 16, 6, .22);
    font-size: .85rem;
    opacity: .8;
}

/* A finished progress bar reads green instead of brand-amber. */
body.jm-dash .jm-progress--done > span { background: var(--success); }

/* ---------- student/courses.html — "My courses" library ----------
   One resume panel, progress filters, then cover cards. Each card carries a
   lesson track (.jm-mc-track): one segment per lesson, so the student sees
   how many lessons are left. Nothing here is positioned outside its card,
   so the page can never scroll sideways. */
body.jm-dash .jm-mc { min-width: 0; }

/* Resume panel: the last opened course. */
body.jm-dash .jm-mc-resume {
    display: grid;
    grid-template-columns: 1fr;
    margin-bottom: 28px;
    background: var(--bg2);
    border: 1px solid var(--border);
    border-radius: var(--r);
    overflow: hidden;
}
@media (min-width: 768px) {
    body.jm-dash .jm-mc-resume { grid-template-columns: minmax(0, 2fr) minmax(0, 3fr); }
}
@media (min-width: 1280px) {
    body.jm-dash .jm-mc-resume { grid-template-columns: 440px minmax(0, 1fr); }
}
body.jm-dash .jm-mc-resume-thumb {
    display: grid;
    place-items: center;
    aspect-ratio: 16 / 9;
    background: var(--thumb-bg);
    overflow: hidden;
}
body.jm-dash .jm-mc-resume-thumb img { width: 100%; height: 100%; object-fit: cover; }
body.jm-dash .jm-mc-resume-thumb > svg { width: 56px; height: 56px; color: var(--faint); }
body.jm-dash .jm-mc-resume-body {
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: 12px;
    padding: 20px;
    min-width: 0;
}
@media (min-width: 1024px) { body.jm-dash .jm-mc-resume-body { padding: 28px 32px; } }
body.jm-dash .jm-mc-resume-kicker { margin: 0; font-size: .9rem; font-weight: 700; color: var(--accent-ink); }
body.jm-dash .jm-mc-resume-title {
    margin: 0;
    font-size: 1.35rem;
    font-weight: 700;
    line-height: 1.35;
    color: var(--text);
    overflow-wrap: anywhere;
}
@media (min-width: 1024px) { body.jm-dash .jm-mc-resume-title { font-size: 1.6rem; } }
body.jm-dash .jm-mc-resume .jm-mc-track { height: 10px; }
body.jm-dash .jm-mc-resume-cta { align-self: flex-start; margin-top: 4px; }
body.jm-dash .jm-mc-resume-cta svg { width: 16px; height: 16px; }

/* Progress filters. */
body.jm-dash .jm-mc-filters { margin-bottom: 20px; flex-wrap: wrap; row-gap: 0; overflow: visible; }
@media (max-width: 639px) { body.jm-dash .jm-mc-filters button { padding: 10px 10px; font-size: .88rem; } }
body.jm-dash .jm-mc-filters button { display: inline-flex; align-items: center; gap: 8px; }
body.jm-dash .jm-mc-filter-n {
    min-width: 22px;
    padding: 0 7px;
    border-radius: 999px;
    background: var(--card2);
    color: var(--muted);
    font-size: .75rem;
    line-height: 20px;
    text-align: center;
    font-variant-numeric: tabular-nums;
}
body.jm-dash .jm-mc-filters .is-active .jm-mc-filter-n { background: var(--warn-soft); color: var(--accent-ink); }
body.jm-dash .jm-mc-filters button:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; border-radius: 8px; }

/* Card grids: the library and the "explore more" shelf. */
body.jm-dash .jm-mc-grid,
body.jm-dash .jm-mc-dgrid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 250px), 1fr));
    gap: 16px;
    margin: 0;
    padding: 0;
    list-style: none;
}
body.jm-dash .jm-mc-dgrid { grid-template-columns: repeat(auto-fill, minmax(min(100%, 200px), 1fr)); gap: 14px; }

body.jm-dash .jm-mc-card,
body.jm-dash .jm-mc-dcard {
    position: relative;
    display: flex;
    flex-direction: column;
    min-width: 0;
    background: var(--bg2);
    border: 1px solid var(--border);
    border-radius: var(--r-sm);
    overflow: hidden;
    transition: border-color .2s;
}
body.jm-dash .jm-mc-card:hover,
body.jm-dash .jm-mc-dcard:hover { border-color: var(--border2); }
body.jm-dash .jm-mc-card:focus-within,
body.jm-dash .jm-mc-dcard:focus-within { outline: 2px solid var(--accent); outline-offset: 2px; }
body.jm-dash .jm-mc-card.is-removed .jm-mc-cover img { filter: grayscale(.7); opacity: .8; }

body.jm-dash .jm-mc-cover {
    position: relative;
    display: grid;
    place-items: center;
    aspect-ratio: 16 / 9;
    background: var(--thumb-bg);
    overflow: hidden;
}
body.jm-dash .jm-mc-cover img { width: 100%; height: 100%; object-fit: cover; }
body.jm-dash .jm-mc-cover > svg { width: 36px; height: 36px; color: var(--faint); }

body.jm-dash .jm-mc-badge {
    position: absolute;
    top: 10px;
    inset-inline-start: 10px;
    display: inline-flex;
    align-items: center;
    gap: 4px;
    max-width: calc(100% - 20px);
    padding: 3px 10px;
    border-radius: 999px;
    font-size: .75rem;
    font-weight: 700;
    line-height: 1.5;
}
body.jm-dash .jm-mc-badge svg { width: 13px; height: 13px; flex: none; }
body.jm-dash .jm-mc-badge--done { background: var(--success); color: var(--bg2); }
body.jm-dash .jm-mc-badge--removed { background: var(--bg2); color: var(--warn); border: 1px solid var(--warn-border); }
body.jm-dash .jm-mc-badge--done + .jm-mc-badge--removed { top: auto; bottom: 10px; }

body.jm-dash .jm-mc-body { display: flex; flex-direction: column; flex: 1; gap: 6px; padding: 14px 16px 16px; min-width: 0; }
body.jm-dash .jm-mc-cat { margin: 0; font-size: .8rem; font-weight: 700; color: var(--accent-ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
body.jm-dash .jm-mc-title {
    margin: 0;
    font-size: 1rem;
    font-weight: 700;
    line-height: 1.45;
    color: var(--text);
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    overflow-wrap: anywhere;
}
body.jm-dash .jm-mc-dcard .jm-mc-title { font-size: .92rem; }
/* The title link covers the whole card, so the card is one big target. */
body.jm-dash .jm-mc-link::after { content: ""; position: absolute; inset: 0; z-index: 1; }
body.jm-dash .jm-mc-link:focus-visible { outline: none; }
body.jm-dash .jm-mc-foot { display: flex; flex-direction: column; gap: 8px; margin-top: auto; padding-top: 8px; }

body.jm-dash .jm-mc-count {
    display: flex;
    justify-content: space-between;
    gap: 8px;
    margin: 0;
    font-size: .82rem;
    color: var(--muted);
    font-variant-numeric: tabular-nums;
}
body.jm-dash .jm-mc-count b { color: var(--text); font-weight: 700; }
body.jm-dash .jm-mc-cta { display: inline-flex; align-items: center; gap: 4px; font-size: .88rem; font-weight: 700; color: var(--accent-ink); }
body.jm-dash .jm-mc-cta svg { width: 15px; height: 15px; }

/* Lesson track: one segment per lesson, or one bar for long / empty courses. */
body.jm-dash .jm-mc-track { display: flex; gap: 2px; height: 7px; }
body.jm-dash .jm-mc-track > span { flex: 1 1 0; min-width: 0; border-radius: 2px; background: var(--card2); }
body.jm-dash .jm-mc-track > span.is-on { background: var(--accent); }
body.jm-dash .jm-mc-track.is-done > span.is-on { background: var(--success); }
body.jm-dash .jm-mc-track--bar { gap: 0; border-radius: 999px; background: var(--card2); overflow: hidden; }
body.jm-dash .jm-mc-track--bar > .jm-mc-track-fill { flex: none; border-radius: 999px; background: var(--accent); }
body.jm-dash .jm-mc-track--bar.is-done > .jm-mc-track-fill { background: var(--success); }

/* Explore more courses. */
body.jm-dash .jm-mc-discover { margin-top: 48px; }
body.jm-dash .jm-mc-dmeta { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-top: auto; padding-top: 6px; font-size: .85rem; }
body.jm-dash .jm-mc-star { display: inline-flex; align-items: center; gap: 3px; color: var(--muted); font-weight: 700; }
body.jm-dash .jm-mc-star svg { width: 14px; height: 14px; color: var(--accent2); }
body.jm-dash .jm-mc-price { display: inline-flex; align-items: baseline; gap: 6px; margin-inline-start: auto; }
body.jm-dash .jm-mc-price b { color: var(--text); font-weight: 700; }
body.jm-dash .jm-mc-price s { color: var(--faint); font-size: .78rem; }
body.jm-dash .jm-mc-price b.jm-mc-free { color: var(--success); }
/* The enrol button sits above the stretched title link. */
body.jm-dash .jm-mc-dcta { position: relative; z-index: 2; margin-top: 8px; }

/* Filtered-out cards use the hidden attribute; the display rules above would otherwise win. */
body.jm-dash .jm-mc-grid[hidden],
body.jm-dash .jm-mc-card[hidden] { display: none; }

@media (prefers-reduced-motion: reduce) {
    body.jm-dash .jm-mc-card, body.jm-dash .jm-mc-dcard { transition: none; }
}

/* student/profile.html — the large profile avatar (image or initial). */
body.jm-dash .jm-davatar-lg {
    width: 112px;
    height: 112px;
    border-radius: 50%;
    object-fit: cover;
    border: 4px solid var(--card2);
    display: grid;
    place-items: center;
    background: var(--grad);
    color: var(--btn-text);
    font-size: 2.25rem;
    font-weight: 700;
}

/* ---------- student/rewards/index.html ---------- */

/* Points hero — the brand gradient with ink-on-gradient text, replacing the
   old indigo→fuchsia panel. Overlays are tinted with the ink colour so they
   work at any gradient stop. */
body.jm-dash .jm-dhero {
    position: relative;
    overflow: hidden;
    border-radius: var(--r);
    background: var(--grad);
    color: var(--btn-text);
    box-shadow: var(--glow);
    padding: 24px;
}
@media (min-width: 640px) { body.jm-dash .jm-dhero { padding: 32px; } }
body.jm-dash .jm-dhero-eyebrow { margin: 0; font-size: 11px; font-weight: 700; letter-spacing: .2em; text-transform: uppercase; opacity: .7; }
body.jm-dash .jm-dhero-value { font-size: clamp(2.6rem, 6vw, 3.6rem); font-weight: 900; line-height: 1; font-variant-numeric: tabular-nums; }
body.jm-dash .jm-dhero-badge { display: grid; place-items: center; width: 80px; height: 80px; border-radius: 22px; background: rgba(22, 16, 6, .12); }
body.jm-dash .jm-dhero-badge svg { width: 46px; height: 46px; }
body.jm-dash .jm-dhero-tile { border-radius: 18px; background: rgba(22, 16, 6, .1); padding: 12px; }
body.jm-dash .jm-dhero-tile p { margin: 0; }
body.jm-dash .jm-dhero-tile-label { font-size: 10px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; opacity: .72; }
body.jm-dash .jm-dhero-tile-value { margin-top: 6px !important; font-size: 1.5rem; font-weight: 900; font-variant-numeric: tabular-nums; }
body.jm-dash .jm-dhero-tile-sub { font-size: 11px; opacity: .72; }
body.jm-dash .jm-dhero-tile svg { width: 18px; height: 18px; opacity: .8; }
/* The gradient is too light for .jm-btn-g / .jm-btn-p, so the hero has its
   own pair of CTAs. */
body.jm-dash .jm-dhero-btn { display: inline-flex; align-items: center; gap: 6px; padding: 9px 17px; border-radius: 999px; font-size: .88rem; font-weight: 700; border: 1px solid transparent; }
body.jm-dash .jm-dhero-btn svg { width: 16px; height: 16px; flex: none; }
body.jm-dash .jm-dhero-btn--solid { background: var(--bg2); color: var(--accent-ink); box-shadow: 0 6px 18px -8px rgba(22, 16, 6, .5); }
body.jm-dash .jm-dhero-btn--solid:hover { color: var(--accent-ink); }
body.jm-dash .jm-dhero-btn--ghost { background: rgba(22, 16, 6, .12); border-color: rgba(22, 16, 6, .18); color: var(--btn-text); }
body.jm-dash .jm-dhero-btn--ghost:hover { background: rgba(22, 16, 6, .2); color: var(--btn-text); }

/* Achievement card (cups / medals / badges). */
body.jm-dash .jm-dach {
    position: relative;
    overflow: hidden;
    border-radius: var(--r);
    border: 1px solid var(--border);
    background: var(--bg2);
    padding: 20px;
    transition: border-color .2s, box-shadow .2s;
}
body.jm-dash .jm-dach--earned { border-color: var(--border2); box-shadow: var(--shadow); }
body.jm-dash .jm-dach--locked { opacity: .78; }
body.jm-dash .jm-dach-flag {
    position: absolute;
    top: 12px;
    inset-inline-end: 12px;
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 2px 9px;
    border-radius: 999px;
    font-size: 10px;
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;
}
body.jm-dash .jm-dach-flag svg { width: 12px; height: 12px; }
body.jm-dash .jm-dach-flag--earned { background: var(--success-soft); color: var(--success); border: 1px solid var(--success-border); }
body.jm-dash .jm-dach-flag--locked { background: var(--card2); color: var(--faint); border: 1px solid var(--border); }
body.jm-dash .jm-dach-medal {
    position: relative;
    flex: none;
    display: grid;
    place-items: center;
    width: 64px;
    height: 64px;
    border-radius: 20px;
    background: var(--card2);
    color: var(--faint);
    box-shadow: 0 0 0 4px var(--card);
}
body.jm-dash .jm-dach-medal svg { width: 32px; height: 32px; }
body.jm-dash .jm-dach-medal--gold { background: var(--grad); color: var(--btn-text); box-shadow: 0 0 0 4px rgba(249, 161, 27, .2); }
body.jm-dash .jm-dach-medal--silver { background: linear-gradient(135deg, var(--faint), var(--muted)); color: var(--bg2); box-shadow: 0 0 0 4px var(--card2); }
body.jm-dash .jm-dach-medal--accent { background: linear-gradient(135deg, var(--cyan), var(--accent)); color: var(--btn-text); box-shadow: 0 0 0 4px var(--cyan-soft); }
body.jm-dash .jm-dach-medal--round { width: 80px; height: 80px; border-radius: 50%; margin-inline: auto; }
body.jm-dash .jm-dach-medal--sm { width: 56px; height: 56px; border-radius: 50%; margin-inline: auto; }
body.jm-dash .jm-dach-medal--sm svg { width: 28px; height: 28px; }
body.jm-dash .jm-dach-lock { position: absolute; inset: 0; display: grid; place-items: center; border-radius: inherit; background: rgba(3, 6, 15, .38); color: rgba(255, 255, 255, .92); }
body.jm-dash .jm-dach-lock svg { width: 26px; height: 26px; }
body.jm-dash .jm-dach-title { margin: 0; font-weight: 700; color: var(--text); }
body.jm-dash .jm-dach-desc { margin: 3px 0 0; font-size: .78rem; line-height: 1.5; color: var(--muted); }
body.jm-dash .jm-dach-meta { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; margin-bottom: 5px; font-size: 11px; font-weight: 600; color: var(--muted); }
body.jm-dash .jm-dach-meta b { color: var(--text); font-weight: 700; font-variant-numeric: tabular-nums; }
body.jm-dash .jm-dach-pts { display: inline-flex; align-items: center; gap: 4px; color: var(--accent-ink); font-variant-numeric: tabular-nums; }
body.jm-dash .jm-dach-pts svg { width: 12px; height: 12px; }
body.jm-dash .jm-dach-count {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 2px 10px;
    border-radius: 999px;
    background: var(--card2);
    color: var(--muted);
    font-size: 11px;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}
body.jm-dash .jm-dach-count--earned { background: var(--success-soft); color: var(--success); }

/* Thin progress bar for badge cards. */
body.jm-dash .jm-progress--sm { height: 6px; }

/* Category heading with a right-aligned tagline. */
body.jm-dash .jm-dsec-head--split { justify-content: space-between; align-items: flex-end; }
body.jm-dash .jm-dsec-tag { margin: 0; margin-inline-start: auto; font-size: .78rem; color: var(--faint); }

/* ---------- student/subscriptions/index.html ---------- */

/* Plan thumbnail: brand-gradient stand-in when the plan has no image, plus a
   dark scrim so the white name overlay stays readable over any photo. */
body.jm-dash .jm-dplan-ph { width: 100%; height: 100%; background: var(--grad); }
body.jm-dash .jm-dplan-scrim { position: absolute; inset: 0; background: linear-gradient(to top, rgba(3, 6, 15, .8), rgba(3, 6, 15, .25) 45%, transparent); }
body.jm-dash .jm-dplan-name { color: rgba(255, 255, 255, .96); font-size: 1rem; font-weight: 700; line-height: 1.3; margin: 0; }
body.jm-dash .jm-dplan-desc { color: rgba(255, 255, 255, .72); font-size: .75rem; margin: 2px 0 0; }

/* Solid duration badges that sit on the thumbnail (the translucent .jm-chip
   backgrounds disappear over a photo). The token pair inverts correctly in
   both themes. */
body.jm-dash .jm-dplan-badge {
    display: inline-flex;
    align-items: center;
    padding: 2px 8px;
    border-radius: 8px;
    font-size: 10px;
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;
}
body.jm-dash .jm-dplan-badge--cyan { background: var(--cyan); color: var(--bg2); }
body.jm-dash .jm-dplan-badge--success { background: var(--success); color: var(--bg2); }

/* Cancel / resume / details dialogs. subscription-manage.js drives them by
   toggling `hidden` on the root and opacity/scale utilities on the overlay and
   panel, so the three-element structure and those ids stay as they were. */
body.jm-dash .jm-ddialog-overlay { position: absolute; inset: 0; background: rgba(3, 6, 15, .7); backdrop-filter: blur(4px); }
body.jm-dash .jm-ddialog-panel {
    position: relative;
    width: 100%;
    background: var(--bg2);
    color: var(--text);
    border: 1px solid var(--border);
    border-radius: 20px;
    box-shadow: var(--shadow);
    padding: 24px;
}
body.jm-dash .jm-ddialog-title { margin: 0 0 8px; font-size: 1.1rem; font-weight: 700; text-align: center; }
body.jm-dash .jm-ddialog-text { margin: 0 0 24px; font-size: .9rem; color: var(--muted); text-align: center; }
body.jm-dash .jm-ddialog-icon { display: grid; place-items: center; width: 48px; height: 48px; margin: 0 auto 16px; border-radius: 50%; }
body.jm-dash .jm-ddialog-icon svg { width: 24px; height: 24px; }
body.jm-dash .jm-ddialog-icon--danger { background: var(--danger-soft); color: var(--danger); }
body.jm-dash .jm-ddialog-icon--success { background: var(--success-soft); color: var(--success); }

/* ---------- admin-people ---------- */
/* ============================================================
   SHARED — used by more than one of the rewritten page groups
   ============================================================ */

/* ---------- avatars, bigger than the 38px list default ----------
   .jm-davatar is sized for table rows; page-level identity blocks
   (users/edit.html, users/view.html, crm-users/view.html) need more. */
body.jm-dash .jm-davatar--md { width: 48px; height: 48px; }
body.jm-dash .jm-davatar--md.jm-davatar--initials { font-size: .95rem; }
body.jm-dash .jm-davatar--lg { width: 64px; height: 64px; }
body.jm-dash .jm-davatar--lg.jm-davatar--initials { font-size: 1.25rem; }

/* ---------- status dot that inherits its chip's colour ----------
   .jm-chip-dot is hard-wired to the amber accent; this variant takes
   currentColor so one rule serves online/offline/enabled/disabled
   inside --success / --danger / --muted chips alike.
   Used by users/view.html and crm-users/view.html. */
body.jm-dash .jm-ddot {
    flex: none;
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: currentColor;
}

/* ---------- accent-coloured figure ----------
   site.css ships .jm-muted / .jm-faint but no accent text utility. */
body.jm-dash .jm-daccent { color: var(--accent-ink); }

/* ---------- icon-only copy-to-clipboard button ----------
   users/index.html, users/view.html. .check-icon is the JS hook that
   swaps in after a successful copy — colour it, do not rename it. */
body.jm-dash .jm-dcopy {
    display: inline-grid;
    place-items: center;
    padding: 4px;
    border: 0;
    border-radius: 7px;
    background: none;
    color: var(--faint);
    cursor: pointer;
}
body.jm-dash .jm-dcopy:hover { color: var(--accent-ink); background: var(--card); }
body.jm-dash .jm-dcopy .check-icon { color: var(--success); }

/* ---------- video placeholder tile ----------
   courses/edit.html and bundles/{create,edit}.html, when a promo video
   has no thumbnail. */
body.jm-dash .jm-dvideo-ph {
    background: var(--thumb-bg);
    color: var(--faint);
}

/* ---------- character counter (JS RE-SKIN) ----------
   course-form.js / bundle-form.js / subscription-form.js /
   curriculum-builder.js set these three classes; input.css defines
   them with hex. -ok is the RESTING state (set on init), so it reads
   as help text rather than success green. */
body.jm-dash .char-counter-ok { color: var(--faint); }
body.jm-dash .char-counter-warn { color: var(--warn); }
body.jm-dash .char-counter-danger { color: var(--danger); }

/* ---------- th:field checkbox + .jm-switch (BUG FIX) ----------
   Thymeleaf's th:field emits a hidden `_field` input immediately after
   the checkbox, which breaks site.css's `input:checked + span`. The
   sibling combinator has to be `~`. Worth folding into site.css rather
   than here — it affects every th:field switch on the site. */
body.jm-dash .jm-switch input:checked ~ span { background: var(--grad); border-color: transparent; }
body.jm-dash .jm-switch input:checked ~ span::before { background: var(--btn-text); transform: translateX(20px); }
html[dir="rtl"] body.jm-dash .jm-switch input:checked ~ span::before { transform: translateX(-20px); }

/* ============================================================
   FROM: css-add-users-view.css
   ============================================================ */
/* ---------- negative / discount amount ----------
   users/view.html: the "-$10.00" discount figure in the payments table and
   in the payment popover. */
body.jm-dash .jm-dneg {
    color: var(--danger);
}

/* ---------- hover popover ----------
   users/view.html: the payment summary card in .payment-popover-template.
   user-view.js clones it and appends it to <body> (which carries .jm-dash)
   and positions it with inline top/left, so the template keeps Tailwind's
   `fixed z-[9999] w-72` and this rule supplies only the surface. */
body.jm-dash .jm-dpopover {
    background: var(--bg2);
    border: 1px solid var(--border);
    border-radius: var(--r-sm);
    box-shadow: var(--shadow);
    color: var(--text);
    padding: 16px;
}
/* Section divider inside the popover (financial summary, footer link). */
body.jm-dash .jm-dpopover-sec {
    border-top: 1px solid var(--border);
    margin-top: 12px;
    padding-top: 12px;
}

/* ---------- users/view.html tab bar ----------
   TEMPORARY SHIM. user-view.js::activateTab() rewrites button.className on
   every switch and injects the legacy utilities
     active   -> `border-indigo-500 text-indigo-600`
     inactive -> `border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300`
   plus `border-b-2`. The template cannot prevent that, so these rules
   re-colour the bar from tokens and use the injected `.text-indigo-600`
   purely as the active-state hook (the ::after bar that .jm-tabs normally
   draws from [aria-current]/[aria-selected]/.is-active).

   WHEN user-view.js IS UPDATED to toggle `.is-active` instead, delete the
   `.text-indigo-600` selectors below — `.jm-tabs .is-active` already works. */
body.jm-dash .jm-dtabs-userview .user-view-tab {
    color: var(--muted);
    border: 0;
}
body.jm-dash .jm-dtabs-userview .user-view-tab:hover {
    color: var(--text);
}
body.jm-dash .jm-dtabs-userview .user-view-tab.is-active,
body.jm-dash .jm-dtabs-userview .user-view-tab.text-indigo-600 {
    color: var(--text);
}
body.jm-dash .jm-dtabs-userview .user-view-tab.is-active::after,
body.jm-dash .jm-dtabs-userview .user-view-tab.text-indigo-600::after {
    content: "";
    position: absolute;
    inset-inline: 10px;
    bottom: -1px;
    height: 2px;
    border-radius: 2px;
    background: var(--grad);
}


/* ============================================================
   FROM: css-add-users-rest.css
   ============================================================ */
/* ============================================================
   Additions needed by dashboard/users/{index,edit,subscriptions}.html
   Append to dashboard-shell.css. Tokens only, no hardcoded colours.
   ============================================================ */

/* ---------- row-action dropdown ----------
   Needed by: dashboard/users/index.html (the "⋮" menu on every row).
   The menu is position:fixed and JS (user-management.js) sets top/left and
   toggles `hidden`, so this only paints the surface — no layout. */
body.jm-dash .jm-dmenu {
    background: var(--bg2);
    border: 1px solid var(--border);
    border-radius: var(--r-sm);
    box-shadow: var(--shadow);
    color: var(--text);
    padding: 6px;
    overflow: hidden;
}
body.jm-dash .jm-dmenu-item {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    padding: 9px 12px;
    border: 0;
    border-radius: 9px;
    background: none;
    color: var(--text);
    font: inherit;
    font-size: .88rem;
    font-weight: 600;
    text-align: start;
    cursor: pointer;
    transition: background .15s, color .15s;
}
body.jm-dash .jm-dmenu-item:hover { background: var(--card); color: var(--text); }
body.jm-dash .jm-dmenu-item svg { flex: none; width: 16px; height: 16px; color: var(--faint); }
body.jm-dash .jm-dmenu-item:hover svg { color: var(--accent-ink); }
body.jm-dash .jm-dmenu-item--danger,
body.jm-dash .jm-dmenu-item--danger svg { color: var(--danger); }
body.jm-dash .jm-dmenu-item--danger:hover { background: var(--danger-soft); color: var(--danger); }
body.jm-dash .jm-dmenu-item--danger:hover svg { color: var(--danger); }
body.jm-dash .jm-dmenu-sep { height: 1px; margin: 6px 4px; background: var(--border); }

/* ---------- warn chip ----------
   Needed by: users/subscriptions.html + users/edit.html — the subscription
   status set is 5-valued (ACTIVE / CANCELLED / EXPIRED / PAST_DUE / REFUNDED)
   and site.css only ships success / danger / muted / cyan. --warn already
   exists as a token; this is the missing chip variant. */
body.jm-dash .jm-chip--warn { color: var(--warn); background: var(--warn-soft); border-color: var(--warn-border); }

/* ---------- inline copy button ----------
   Needed by: users/subscriptions.html (copy transaction id).
   `.copy-icon` / `.check-icon` are subscription-management.js hooks. */

/* ---------- large list avatar ----------
   Needed by: users/edit.html profile header (the 38px .jm-davatar is too small
   for a page-level identity block). */

/* ---------- whole-row link ----------
   Needed by: users/index.html — the user cell is one <a> wrapping avatar +
   name + email; the name should pick up the accent on hover. */
body.jm-dash .jm-trow-link:hover .jm-tcell-title { color: var(--accent-ink); }

/* ---------- read-only detail list ----------
   Needed by: users/edit.html "User Information" panel. */
body.jm-dash .jm-ddl { display: grid; gap: 16px; margin: 0; }
body.jm-dash .jm-ddl dt { color: var(--faint); font-size: .82rem; font-weight: 600; }
body.jm-dash .jm-ddl dd { margin: 2px 0 0; color: var(--text); font-size: .92rem; font-weight: 600; }
@media (min-width: 640px) { body.jm-dash .jm-ddl { grid-template-columns: repeat(2, minmax(0, 1fr)); } }


/* ============================================================
   FROM: css-add-crm-users.css
   ============================================================ */
/* ============================================================
   Additions needed by dashboard/crm-users/* — append to dashboard-shell.css
   (written by the crm-users re-skin agent; tokens only, no hex)
   ============================================================ */

/* ---------- back-arrow link in a page header ----------
   Used by crm-users/create.html, edit.html and view.html: the chevron that
   sits before the <h1> and returns to the list. dashboard-shell.css has no
   equivalent, and a bare <a> inherits colour inside body.jm-dash. */
body.jm-dash .jm-dback {
    display: grid;
    place-items: center;
    flex: none;
    width: 34px;
    height: 34px;
    border-radius: 10px;
    color: var(--faint);
    transition: color .2s, background .2s;
}
body.jm-dash .jm-dback:hover { color: var(--accent-ink); background: var(--card); }

/* ---------- email-verified tick ----------
   crm-users/index.html (and dashboard/users/* use the same legacy
   .verified-badge) — a small inline check beside a user's name in a table
   cell. Too small for a .jm-chip pill. */
body.jm-dash .jm-dverified {
    display: inline-flex;
    flex: none;
    color: var(--success);
}
body.jm-dash .jm-dverified svg { width: 14px; height: 14px; }
/* .jm-davatar--lg / --md: see the shared "avatars" section above. */

/* Soft-deleted (archived) rows in crm-users/index.html: same shape as
   --initials but greyed out, so archived users read as inactive. */
body.jm-dash .jm-davatar--archived {
    display: grid;
    place-items: center;
    background: var(--card2);
    color: var(--faint);
    font-weight: 700;
    font-size: .78rem;
}

/* ---------- collapsible card head ----------
   crm-users/index.html "Archived Users" panel: #archived-toggle is a
   .jm-dcard-head that crm-user-management.js turns into a show/hide
   control. Only adds the affordance; layout comes from .jm-dcard-head. */
body.jm-dash .jm-dcard-toggle { cursor: pointer; user-select: none; }
body.jm-dash .jm-dcard-toggle:hover { background: var(--card); }

/* ---------- crm-user-view.js tab state ----------
   crm-users/view.html. The tab strip is now .jm-tabs, but crm-user-view.js
   (outside this migration's scope) still sets the legacy Tailwind classes
   `border-indigo-500 text-indigo-600` / `border-transparent text-gray-500
   hover:text-gray-700 hover:border-gray-300` to mark the active tab. These
   rules out-specify those utilities so the strip renders in theme colours
   either way. Delete them once that script switches to aria-selected. */
body.jm-dash .jm-tabs .crm-view-tab {
    border-bottom: 2px solid transparent;
    color: var(--muted);
}
body.jm-dash .jm-tabs .crm-view-tab:hover { color: var(--text); }
body.jm-dash .jm-tabs .crm-view-tab.border-transparent { border-bottom-color: transparent; }
body.jm-dash .jm-tabs .crm-view-tab.text-gray-500 { color: var(--muted); }
body.jm-dash .jm-tabs .crm-view-tab.text-indigo-600 { color: var(--text); }
body.jm-dash .jm-tabs .crm-view-tab.border-indigo-500 { border-bottom-color: var(--accent); }


/* ============================================================
   FROM: css-add-courses-view.css
   ============================================================ */
/* ============================================================
   Additions needed by dashboard/courses/view.html
   ------------------------------------------------------------
   Append to dashboard-shell.css. Every rule is token-driven and
   prefixed `body.jm-dash` so it outranks the Tailwind utilities
   that `static/js/course-stats-admin.js` still injects at runtime
   (tailwind.config.js scans static/js/**, so those legacy colour
   classes ARE compiled into output.css — but dashboard-shell.css
   is linked last and these selectors are more specific).
   ============================================================ */

/* ---------- mini stat tile (inside a card, no icon) ----------
   courses/view.html "Students Display" and "Ratings" panels show
   3-up centred figures inside a card. .jm-dstat is a top-level KPI
   card (gradient rule + 46px icon) and is too heavy here. */
body.jm-dash .jm-dminis {
    display: grid;
    grid-template-columns: 1fr;
    gap: 14px;
}
@media (min-width: 640px) {
    body.jm-dash .jm-dminis { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
body.jm-dash .jm-dmini {
    background: var(--card);
    border: 1px solid var(--border);
    border-radius: var(--r-sm);
    padding: 16px 14px;
    text-align: center;
}
body.jm-dash .jm-dmini--accent { background: var(--warn-soft); border-color: var(--warn-border); }
body.jm-dash .jm-dmini--success { background: var(--success-soft); border-color: var(--success-border); }
body.jm-dash .jm-dmini-label { font-size: .75rem; font-weight: 600; color: var(--muted); margin: 0 0 4px; }
body.jm-dash .jm-dmini--accent .jm-dmini-label { color: var(--warn); }
body.jm-dash .jm-dmini--success .jm-dmini-label { color: var(--success); }
body.jm-dash .jm-dmini-value { font-size: 1.6rem; font-weight: 800; line-height: 1.1; color: var(--text); margin: 0; }
body.jm-dash .jm-dmini--accent .jm-dmini-value { color: var(--warn); }
body.jm-dash .jm-dmini--success .jm-dmini-value { color: var(--success); }
/* the " / 5" suffix that follows the figure (rendered by the template AND
   re-injected by course-stats-admin.js as a second <span>) */
body.jm-dash .jm-dmini-value span + span { font-size: .85rem; font-weight: 600; color: var(--muted); }
body.jm-dash .jm-dmini-note { font-size: .72rem; color: var(--faint); margin: 4px 0 0; }

/* ---------- inset sub-panel ----------
   A tinted, bordered block *inside* a .jm-dcard that groups a set of controls
   (courses/view.html: the boost toggle row, the rating-source selector and the
   add-rating form). Deliberately separate from .jm-dmini, whose centred text
   would fight the start-aligned content here. */
body.jm-dash .jm-dpanel {
    background: var(--card);
    border: 1px solid var(--border);
    border-radius: var(--r-sm);
    padding: 16px 18px;
    text-align: start;
}

/* ---------- switch built on a <button role="switch"> ----------
   courses/view.html #show-boost-toggle. site.css .jm-switch needs a real
   <input type="checkbox">; this control is a button whose state the JS
   carries on aria-checked / data-active, so it is driven off aria-checked.
   `transform: none` neutralises the translate-x-1 / translate-x-6 classes
   the JS toggles on the knob, so the knob can travel with a logical
   property and therefore mirror correctly in Arabic. */
body.jm-dash .jm-dswitch {
    position: relative;
    flex: none;
    width: 46px;
    height: 26px;
    border-radius: 999px;
    background: var(--card2);
    border: 1px solid var(--border);
    cursor: pointer;
    transition: background .2s, border-color .2s;
}
body.jm-dash .jm-dswitch[aria-checked="true"] { background: var(--grad); border-color: transparent; }
body.jm-dash .jm-dswitch:disabled { opacity: .55; cursor: not-allowed; }
body.jm-dash .jm-dswitch-knob {
    position: absolute;
    top: 50%;
    inset-inline-start: 3px;
    width: 18px;
    height: 18px;
    border-radius: 50%;
    background: var(--faint);
    transform: none;
    margin-top: -9px;
    transition: inset-inline-start .2s, background .2s;
}
body.jm-dash .jm-dswitch[aria-checked="true"] .jm-dswitch-knob {
    inset-inline-start: 23px;
    background: var(--btn-text);
    transform: none;
}

/* ---------- segmented control ----------
   courses/view.html #rating-source-selector. The active option is driven by
   the container's data-active + each button's data-source, both of which the
   JS keeps up to date, so the legacy colour classes it also toggles are inert. */
body.jm-dash .jm-dseg { display: flex; flex-wrap: wrap; gap: 8px; }
body.jm-dash .jm-dseg .rating-source-btn {
    padding: 9px 16px;
    font-size: .78rem;
    font-weight: 700;
    border-radius: var(--r-sm);
    border: 1px solid var(--border);
    background: var(--bg2);
    color: var(--muted);
    cursor: pointer;
    font-family: inherit;
    transition: border-color .2s, background .2s, color .2s;
}
body.jm-dash .jm-dseg .rating-source-btn:hover { border-color: var(--border2); color: var(--text); }
body.jm-dash .jm-dseg .rating-source-btn:disabled { opacity: .55; cursor: not-allowed; }
body.jm-dash .jm-dseg[data-active="STUDENT"] .rating-source-btn[data-source="STUDENT"],
body.jm-dash .jm-dseg[data-active="OTHER"] .rating-source-btn[data-source="OTHER"],
body.jm-dash .jm-dseg[data-active="COMBINED"] .rating-source-btn[data-source="COMBINED"] {
    background: var(--grad);
    border-color: transparent;
    color: var(--btn-text);
}

/* ---------- star rating ----------
   Display stars (template-rendered). */
body.jm-dash .jm-dstar { color: var(--faint); opacity: .32; }
body.jm-dash .jm-dstar--on { color: var(--accent2); opacity: 1; }
/* Interactive picker, courses/view.html #star-input. The JS toggles
   .text-amber-400 on/off to paint; the base rule is the "empty" state. */
body.jm-dash .jm-dstars { display: flex; align-items: center; gap: 2px; }
body.jm-dash .jm-dstars .star-btn {
    background: none;
    border: 0;
    padding: 0;
    cursor: pointer;
    color: var(--faint);
    opacity: .32;
    transition: color .15s, opacity .15s;
}
body.jm-dash .jm-dstars .star-btn.text-amber-400 { color: var(--accent2); opacity: 1; }

/* ---------- rating rows ----------
   .other-rating-row is styled by its JS hook name (not a jm- name) so that
   rows appended by course-stats-admin.js get the same skin as the
   template-rendered ones. */
body.jm-dash .jm-drating-row,
body.jm-dash .other-rating-row {
    background: var(--card);
    border: 1px solid var(--border);
    border-radius: var(--r-sm);
    padding: 10px 13px;
}
body.jm-dash .other-rating-row { background: var(--warn-soft); border-color: var(--warn-border); }
body.jm-dash .jm-drating-row--student { background: var(--cyan-soft); border-color: var(--cyan-border); }
body.jm-dash .jm-drating-avatar {
    width: 28px;
    height: 28px;
    border-radius: 50%;
    overflow: hidden;
    flex: none;
    display: grid;
    place-items: center;
    background: var(--card2);
    color: var(--accent-ink);
    font-size: .7rem;
    font-weight: 700;
}

/* ---------- inline text buttons inside rating rows ----------
   Styled by JS hook name for the same reason. They must NOT set `display`,
   because the JS shows/hides .edit-note-btn with Tailwind's .hidden and
   output.css is linked before this file. */
body.jm-dash .edit-note-btn,
body.jm-dash .delete-rating-btn,
body.jm-dash .jm-dtextbtn {
    background: none;
    border: 0;
    padding: 0;
    font-family: inherit;
    font-size: .74rem;
    font-weight: 700;
    cursor: pointer;
    color: var(--cyan);
    transition: color .2s;
}
body.jm-dash .edit-note-btn:hover,
body.jm-dash .jm-dtextbtn:hover { color: var(--accent-ink); }
body.jm-dash .delete-rating-btn,
body.jm-dash .jm-dtextbtn--danger { color: var(--danger); }
body.jm-dash .delete-rating-btn:hover,
body.jm-dash .jm-dtextbtn--danger:hover { opacity: .75; }
body.jm-dash .delete-rating-btn:disabled,
body.jm-dash .edit-note-btn:disabled { opacity: .5; cursor: not-allowed; }

body.jm-dash .save-note-btn,
body.jm-dash .cancel-note-btn {
    font-size: .74rem;
    font-weight: 700;
    padding: 5px 12px;
    border-radius: 8px;
    border: 1px solid transparent;
    cursor: pointer;
    font-family: inherit;
    transition: opacity .2s;
}
body.jm-dash .save-note-btn { background: var(--grad); color: var(--btn-text); }
body.jm-dash .cancel-note-btn { background: var(--card2); border-color: var(--border); color: var(--muted); }
body.jm-dash .save-note-btn:disabled { opacity: .55; cursor: not-allowed; }

body.jm-dash .edit-note-textarea {
    width: 100%;
    padding: 7px 10px;
    font-family: inherit;
    font-size: .78rem;
    resize: none;
    background: var(--bg2);
    border: 1px solid var(--border);
    border-radius: 8px;
    color: var(--text);
}
body.jm-dash .edit-note-textarea:focus {
    outline: none;
    border-color: var(--accent);
    box-shadow: 0 0 0 3px rgba(249, 161, 27, .18);
}
body.jm-dash .note-text { font-size: .76rem; color: var(--muted); margin: 6px 0 0; line-height: 1.65; }
/* re-injected by the JS when the last row is removed */
body.jm-dash #no-other-ratings { color: var(--faint); }

/* ---------- avatar / file upload field ----------
   courses/view.html reviewer image picker. */
body.jm-dash .jm-dpreview {
    width: 36px;
    height: 36px;
    border-radius: 50%;
    overflow: hidden;
    flex: none;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--card2);
    border: 1px solid var(--border);
}
body.jm-dash .jm-dpreview svg { color: var(--faint); }
body.jm-dash .jm-dupload {
    display: block;
    padding: 7px 12px;
    text-align: center;
    font-size: .76rem;
    color: var(--muted);
    background: var(--card);
    border: 1px dashed var(--border);
    border-radius: var(--r-sm);
    transition: border-color .2s, color .2s;
}
body.jm-dash .jm-dupload:hover { border-color: var(--border2); color: var(--accent-ink); }

/* ---------- inline validation message ----------
   NOT .jm-field-error: that has `:not(:empty) { display: block }`, which would
   beat Tailwind's .hidden (output.css is linked first) and pin the message
   permanently open — the JS shows/hides it with .hidden. This rule sets no
   `display` at all, so .hidden keeps working. */
body.jm-dash .jm-derror { color: var(--danger); font-size: .76rem; font-weight: 600; margin: 5px 0 0; }
/* the JS flags the invalid name field by adding .border-red-400 / .ring-red-400 */
body.jm-dash .jm-input.border-red-400 {
    border-color: var(--danger);
    box-shadow: 0 0 0 4px var(--danger-soft);
}

/* ---------- clickable tile ----------
   courses/view.html "Related Subscriptions" cards. */
body.jm-dash .jm-dtile {
    display: block;
    background: var(--card);
    border: 1px solid var(--border);
    border-radius: var(--r-sm);
    padding: 15px 16px;
    transition: border-color .2s, box-shadow .2s, transform .2s;
}
body.jm-dash .jm-dtile:hover { border-color: var(--border2); box-shadow: var(--shadow); transform: translateY(-2px); }

/* ---------- thumbnail frame ---------- */
body.jm-dash .jm-dthumb {
    overflow: hidden;
    border-radius: var(--r-sm);
    background: var(--thumb-bg);
    border: 1px solid var(--border);
    display: flex;
    align-items: center;
    justify-content: center;
}
body.jm-dash .jm-dthumb svg { color: var(--faint); }

/* ---------- empty state heading ----------
   site.css styles .jm-empty h2; these panels already own the h2 (card title),
   so their empty state is an h3. */
body.jm-dash .jm-empty h3 { font-size: 1.05rem; margin: 0 0 6px; color: var(--text); font-weight: 700; }


/* ============================================================
   FROM: css-add-courses-rest.css
   ============================================================ */
/* ============================================================
   Additions needed by dashboard/courses/{index,guide,create,edit,curriculum}.html
   Append to dashboard-shell.css. Tokens only — no hex.
   ============================================================ */

/* ---------- clickable list row (dashboard/courses/index.html) ----------
   The course list is a stack of full-width <a> rows, not a table and not a
   card grid, so neither .jm-table nor .jm-dcard fits. Replaces the legacy
   `.course-row` rule in input.css, which hardcoded its hover colour. */
body.jm-dash .jm-drow {
    display: flex;
    align-items: center;
    background: var(--bg2);
    border: 1px solid var(--border);
    border-radius: var(--r-sm);
    transition: border-color .2s, background .2s, transform .2s, box-shadow .2s;
}
body.jm-dash .jm-drow:hover {
    background: var(--card);
    border-color: var(--border2);
    transform: translateY(-2px);
    box-shadow: var(--shadow);
}
/* Thumbnail well inside a row — same treatment as .jm-cthumb on the public site. */
body.jm-dash .jm-drow-thumb {
    background: var(--thumb-bg);
    border-radius: var(--r-sm);
    overflow: hidden;
    display: grid;
    place-items: center;
    color: var(--faint);
}

/* ---------- accent number (dashboard/courses/index.html) ----------
   "Earned all time" is the one figure highlighted against the neutral stats. */

/* ---------- dashed upload drop zone (courses/create.html, courses/edit.html) ----
   `.drop-zone` / `.drag-over` are added at runtime by file-upload.js and are
   defined with hardcoded greys in input.css; re-map both onto tokens. */
body.jm-dash .jm-ddrop,
body.jm-dash .jm-ddrop.drop-zone {
    position: relative;
    border: 2px dashed var(--border);
    border-radius: var(--r-sm);
    background: var(--card);
    color: var(--muted);
    transition: border-color .2s, background .2s;
    cursor: pointer;
}
body.jm-dash .jm-ddrop:hover { border-color: var(--border2); }
body.jm-dash .jm-ddrop.drag-over {
    border-color: var(--accent);
    background: var(--warn-soft);
}
body.jm-dash .jm-ddrop svg { color: var(--faint); }
/* Progress bar appended to the zone by course-form.js. */
body.jm-dash .jm-ddrop .upload-progress { background: var(--card2); }
body.jm-dash .jm-ddrop .upload-progress-bar { background: var(--grad); }
/* Placeholder tile behind a promo video with no thumbnail (courses/edit.html). */

/* ---------- character counter (courses/create.html, courses/edit.html) ----------
   course-form.js appends its own counter and toggles char-counter-ok / -warn /
   -danger, which input.css defines with hardcoded hex. */

/* ---------- JS-built multi-text list (courses/guide.html) ----------
   multi-text-list.js creates each row's <input> with the legacy palette baked
   into className. Scoping the list container lets the generated controls pick
   up .jm-input's look without touching the script. */
body.jm-dash .jm-dmulti .multi-text-item { gap: 8px; }
body.jm-dash .jm-dmulti .multi-text-item input {
    background: var(--card);
    border: 1px solid var(--border);
    border-radius: var(--r-sm);
    color: var(--text);
    padding: 11px 14px;
    font-family: inherit;
    font-size: .93rem;
}
body.jm-dash .jm-dmulti .multi-text-item input::placeholder { color: var(--faint); }
body.jm-dash .jm-dmulti .multi-text-item input:focus {
    outline: none;
    border-color: var(--accent);
    box-shadow: 0 0 0 4px rgba(249, 161, 27, .18);
}
body.jm-dash .jm-dmulti .multi-text-remove { color: var(--faint); }
body.jm-dash .jm-dmulti .multi-text-remove:hover { color: var(--danger); }

/* ---------- curriculum builder (courses/curriculum.html) ----------
   curriculum-builder.js wipes #sections-container on load and re-renders every
   section, lecture, dropdown and inline form from strings that still carry the
   legacy Tailwind palette. The template markup below it has been migrated, but
   the runtime markup can only be reached from CSS until those scripts are
   ported. Each rule is scoped to #sections-container and guarded against the
   `hover:` variants so a hover-only utility is not applied at rest. */
body.jm-dash .section-card {
    background: var(--bg2);
    border: 1px solid var(--border);
    border-inline-start: 4px solid var(--accent);
    border-radius: var(--r-sm);
    overflow: hidden;
}
body.jm-dash .section-card .lectures-list > div,
body.jm-dash .jm-dlecture {
    background: var(--bg2);
    border: 1px solid var(--border);
    border-radius: var(--r-sm);
}
body.jm-dash .section-card .lectures-list > div:hover,
body.jm-dash .jm-dlecture:hover { border-color: var(--border2); }
body.jm-dash .lecture-dropdown > div { background: var(--card); border-top: 1px solid var(--border); }
body.jm-dash .add-here-divider { background: var(--warn-soft); border-radius: var(--r-sm); }
body.jm-dash .add-here-divider button { color: var(--accent-ink); }
body.jm-dash .add-lecture-form {
    background: var(--card);
    border-top: 1px solid var(--border);
}
body.jm-dash .drag-handle svg,
body.jm-dash .section-drag-handle svg,
body.jm-dash .lecture-drag-handle svg { color: var(--faint); }
body.jm-dash .btn-delete-section,
body.jm-dash .btn-delete-lecture,
body.jm-dash .btn-delete-question,
body.jm-dash .btn-delete-option,
body.jm-dash .btn-toggle-dropdown { color: var(--faint); }
body.jm-dash .btn-delete-section:hover,
body.jm-dash .btn-delete-lecture:hover,
body.jm-dash .btn-delete-question:hover,
body.jm-dash .btn-delete-option:hover { color: var(--danger); background: var(--danger-soft); }
body.jm-dash .btn-toggle-dropdown:hover { color: var(--text); background: var(--card2); }
body.jm-dash .curriculum-type-dropdown {
    background: var(--bg2);
    border: 1px solid var(--border);
    border-radius: var(--r-sm);
    box-shadow: var(--shadow);
}
body.jm-dash .curriculum-type-dropdown button { color: var(--text); }
body.jm-dash .curriculum-type-dropdown button:hover { background: var(--card); color: var(--accent-ink); }

/* Blanket re-map for the palette utilities those scripts still emit. The
   :not() guards keep hover-only utilities from painting at rest. */
body.jm-dash #sections-container [class*="bg-white"] { background: var(--bg2); }
body.jm-dash #sections-container [class*="bg-gray-"]:not([class*="hover:bg-gray-"]) { background: var(--card); }
body.jm-dash #sections-container [class*="bg-indigo-"]:not([class*="hover:bg-indigo-"]) { background: var(--warn-soft); }
body.jm-dash #sections-container [class*="hover:bg-gray-"]:hover { background: var(--card2); }
body.jm-dash #sections-container [class*="hover:bg-indigo-"]:hover { background: var(--warn-soft); }
body.jm-dash #sections-container [class*="hover:bg-red-"]:hover { background: var(--danger-soft); }
body.jm-dash #sections-container [class*="border-gray-"]:not([class*="hover:border-gray-"]) { border-color: var(--border); }
body.jm-dash #sections-container [class*="border-indigo-"]:not([class*="hover:border-indigo-"]) { border-color: var(--border2); }
body.jm-dash #sections-container [class*="text-gray-9"],
body.jm-dash #sections-container [class*="text-gray-8"]:not([class*="hover:text-gray-8"]) { color: var(--text); }
body.jm-dash #sections-container [class*="text-gray-7"]:not([class*="hover:text-gray-7"]),
body.jm-dash #sections-container [class*="text-gray-6"]:not([class*="hover:text-gray-6"]) { color: var(--muted); }
body.jm-dash #sections-container [class*="text-gray-5"]:not([class*="hover:text-gray-5"]),
body.jm-dash #sections-container [class*="text-gray-4"]:not([class*="hover:text-gray-4"]),
body.jm-dash #sections-container [class*="text-gray-3"]:not([class*="hover:text-gray-3"]) { color: var(--faint); }
body.jm-dash #sections-container [class*="hover:text-gray-"]:hover { color: var(--text); }
body.jm-dash #sections-container [class*="text-indigo-"]:not([class*="hover:text-indigo-"]) { color: var(--accent-ink); }
body.jm-dash #sections-container [class*="hover:text-indigo-"]:hover { color: var(--accent); }
body.jm-dash #sections-container [class*="hover:text-red-"]:hover { color: var(--danger); }
body.jm-dash #sections-container [class*="text-green-"] { color: var(--success); }
body.jm-dash #sections-container [class*="text-blue-"] { color: var(--cyan); }
body.jm-dash #sections-container [class*="text-amber-"] { color: var(--accent-ink); }
/* The one filled button the builder injects ("Add Lecture" submit). */
body.jm-dash #sections-container .btn-submit-add-lecture {
    background: var(--grad);
    color: var(--btn-text);
    box-shadow: var(--glow);
}
body.jm-dash #sections-container .lecture-title-input,
body.jm-dash #sections-container .question-text,
body.jm-dash #sections-container .option-text {
    background: var(--bg2);
    border: 1px solid var(--border);
    color: var(--text);
}
body.jm-dash #sections-container .lecture-title-input:focus,
body.jm-dash #sections-container .question-text:focus,
body.jm-dash #sections-container .option-text:focus {
    outline: none;
    border-color: var(--accent);
    box-shadow: 0 0 0 4px rgba(249, 161, 27, .18);
}

/* ---------- lecture type icons (courses/curriculum.html) ----------
   One colour per lecture type so the three are scannable in a long list. */
body.jm-dash .jm-dtype-video { color: var(--cyan); }
body.jm-dash .jm-dtype-quiz { color: var(--success); }
body.jm-dash .jm-dtype-article { color: var(--accent-ink); }

/* ---------- curriculum: quiz builder blocks (courses/curriculum.html) ----------
   Cloned from the <template> elements in the page by lecture-editor.js. */
body.jm-dash .question-item {
    background: var(--card);
    border: 1px solid var(--border);
    border-radius: var(--r-sm);
}
body.jm-dash .option-correct { accent-color: var(--success); }


/* ============================================================
   FROM: css-add-bundles.css
   ============================================================ */
/* ============================================================
   Scratch additions — dashboard/bundles/{index,create,edit}.html
   Merge into css-additions-admin-people.css (or dashboard-shell.css).
   Tokens only, every selector prefixed `body.jm-dash`.

   Two kinds of rule live here:
     1. genuinely new components the bundle pages need;
     2. token re-skins of hook classes the TEMPLATE cannot drop,
        because JS binds to them or input.css hard-codes their
        colours (see the report for the matching JS lines).
   ============================================================ */

/* ---------- 1. new components ---------- */

/* bundles/create.html + edit.html — the 48px icon tile inside each
   upload drop zone (was `w-12 h-12 rounded-xl bg-gray-100`). */
body.jm-dash .jm-dzone-icon {
    display: grid;
    place-items: center;
    width: 48px;
    height: 48px;
    margin: 0 auto 12px;
    border-radius: 13px;
    background: var(--card2);
    color: var(--faint);
}
body.jm-dash .jm-dzone-icon svg { width: 24px; height: 24px; }

/* bundles/create.html + edit.html — number input with the absolutely
   positioned "$" prefix; needs a bigger start padding than .jm-input.
   A class (not a Tailwind ps-*) so it always outranks .jm-input. */
body.jm-dash .jm-dinput-money { padding-inline-start: 34px; }

/* bundles/create.html + edit.html — the course-search results popover
   (#course-search-results, was `bg-white border-gray-200 shadow-xl`). */
body.jm-dash .jm-dsearch-pop {
    background: var(--bg2);
    border: 1px solid var(--border);
    border-radius: var(--r-sm);
    box-shadow: var(--shadow);
}

/* ---------- 2. re-skins of classes the template must keep ---------- */

/* bundles/create.html + edit.html — drop zones. `.bundle-drop-zone`
   and its `.drag-over` state are bound by file-upload.js/createDropZone,
   and input.css paints them #d1d5db / #fafafa / #eef2ff. */
body.jm-dash .bundle-drop-zone {
    border: 2px dashed var(--border);
    background: var(--card);
    color: var(--text);
    transition: border-color .25s, background .25s, box-shadow .25s;
}
body.jm-dash .bundle-drop-zone:hover {
    border-color: var(--border2);
    background: var(--card2);
}
body.jm-dash .bundle-drop-zone.drag-over {
    border-color: var(--accent);
    background: var(--card2);
    box-shadow: 0 0 0 4px rgba(249, 161, 27, .16);
}

/* bundles/create.html + edit.html — rows built by bundle-form.js
   (`initCourseSelector`) inside #course-search-results. */
body.jm-dash .course-search-result {
    color: var(--text);
    border-bottom: 1px solid var(--border);
}
body.jm-dash .course-search-result:hover { background: var(--card); }

/* bundles/create.html + edit.html — selected-course chips built by
   bundle-form.js (`addCourseChip`) inside #selected-courses-list. */
body.jm-dash .course-chip {
    background: var(--card);
    border: 1px solid var(--border);
    color: var(--text);
}
body.jm-dash .course-chip-remove { color: var(--faint); }
body.jm-dash .course-chip-remove:hover {
    color: var(--danger);
    background: var(--danger-soft);
}

/* bundles/create.html + edit.html — target-audience / learning-goal
   rows built by multi-text-list.js (`addMultiTextItem`). */
body.jm-dash .multi-text-item input {
    background: var(--bg2);
    border: 1px solid var(--border);
    color: var(--text);
}
body.jm-dash .multi-text-item input::placeholder { color: var(--faint); }
body.jm-dash .multi-text-item input:focus {
    outline: none;
    border-color: var(--accent);
    box-shadow: 0 0 0 4px rgba(249, 161, 27, .18);
}
body.jm-dash .multi-text-remove { color: var(--faint); }
body.jm-dash .multi-text-remove:hover {
    color: var(--danger);
    background: var(--danger-soft);
}

/* bundles/create.html + edit.html — upload progress bar injected by
   bundle-form.js (`uploadThumbnail` / `uploadPromoVideo`);
   input.css hard-codes #e5e7eb / #6366f1. */
body.jm-dash .upload-progress { background: var(--card2); }
body.jm-dash .upload-progress-bar { background: var(--grad); }

/* bundles/edit.html — promo-video info card; input.css hard-codes
   #f9fafb / #e5e7eb / #111827 / #6366f1 (plus a `.dark` variant). */
body.jm-dash .video-info-card {
    background: var(--card);
    border-color: var(--border);
}
body.jm-dash .video-info-card .video-thumb { background: var(--thumb-bg); }
body.jm-dash .video-info-card .video-filename { color: var(--text); }
body.jm-dash .video-info-card .video-duration { color: var(--muted); }
body.jm-dash .video-info-card .video-edit-link { color: var(--accent-ink); }
body.jm-dash .video-info-card .video-edit-link:hover { color: var(--accent); }

/* ============================================================
   FROM: css-add-content-pages.css
   ============================================================ */
/* ---------- review avatar ----------
   dashboard/reviews/index.html: dashboard-reviews.js sets
   `avatar.style.background` to one of its own AVATAR_COLORS (all dark,
   saturated) and writes the initial as textContent, so this circle can
   never take the theme gradient of .jm-davatar--initials and always
   needs light text — same pattern as .nav-avatar-overlay in
   dashboard-shell.css. The gradient below is only the fallback shown
   before the JS paints it. */
body.jm-dash .jm-dreview-avatar {
    flex: none;
    display: grid;
    place-items: center;
    width: 40px;
    height: 40px;
    border-radius: 50%;
    overflow: hidden;
    background: var(--grad);
    color: #fff;
    font-size: .85rem;
    font-weight: 700;
}

/* ---------- upload dropzone ----------
   dashboard/testimonials/index.html avatar upload. .jm-empty is the only
   dashed-border component in the system and it is a 60px-tall empty
   state, not an interactive target. */
body.jm-dash .jm-ddropzone {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 4px;
    padding: 20px 16px;
    text-align: center;
    cursor: pointer;
    border: 2px dashed var(--border);
    border-radius: var(--r-sm);
    background: var(--card);
    color: var(--muted);
    transition: border-color .2s, background .2s, color .2s;
}
body.jm-dash .jm-ddropzone:hover {
    border-color: var(--border2);
    background: var(--card2);
    color: var(--text);
}
body.jm-dash .jm-ddropzone svg { width: 28px; height: 28px; color: var(--faint); }

/* ---------- roadmap tree item ----------
   dashboard/roadmaps/preview.html renders the roadmap tree server-side and
   distinguishes the five item types by an accent edge. The old markup used
   `border-left: 4px solid #7c3aed` inline, which also broke in Arabic —
   `border-inline-start` mirrors correctly. */
body.jm-dash .jm-droadmap-item {
    --tone: var(--accent);
    background: var(--bg2);
    border: 1px solid var(--border);
    border-inline-start: 4px solid var(--tone);
    border-radius: var(--r-sm);
}
body.jm-dash .jm-droadmap-item--course     { --tone: var(--cyan); }
body.jm-dash .jm-droadmap-item--article    { --tone: var(--success); }
body.jm-dash .jm-droadmap-item--link       { --tone: var(--accent2); }
body.jm-dash .jm-droadmap-item--attachment { --tone: var(--warn); }
body.jm-dash .jm-droadmap-item-icon { color: var(--tone); flex: none; width: 20px; height: 20px; }
body.jm-dash .jm-droadmap-item-head {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 14px 20px;
    border-bottom: 1px solid var(--border);
}
body.jm-dash .jm-droadmap-item-body { padding: 12px 20px; }

/* ---------- admin-sales ---------- */
/* Inline "feature enabled" toggle box that sits in a page header.
   Pages: dashboard/discounts/index.html, dashboard/rewards/settings.html */
body.jm-dash .jm-dtoggle-box {
    gap: 12px;
    background: var(--bg2);
    border: 1px solid var(--border);
    border-radius: var(--r-sm);
    padding: 9px 16px;
    color: var(--text);
}

/* Uploaded-document thumbnail frame (ID cards, proof images).
   Pages: dashboard/discounts/detail.html */
body.jm-dash .jm-ddoc {
    display: block;
    width: 100%;
    height: 12rem;
    object-fit: cover;
    border-radius: var(--r-sm);
    border: 1px solid var(--border);
    background: var(--thumb-bg);
}
body.jm-dash .jm-ddoc--empty {
    display: grid;
    place-items: center;
    background: var(--card);
    color: var(--faint);
}

/* Semantic tint for a whole panel (decision outcome summaries).
   Pages: dashboard/discounts/detail.html, dashboard/payments/detail.html */
body.jm-dash .jm-dpanel--success {
    background: var(--success-soft);
    border-color: var(--success-border);
    color: var(--success);
}
body.jm-dash .jm-dpanel--success .jm-dcard-title { color: var(--success); }
body.jm-dash .jm-dpanel--danger {
    background: var(--danger-soft);
    border-color: var(--danger-border);
    color: var(--danger);
}
body.jm-dash .jm-dpanel--danger .jm-dcard-title { color: var(--danger); }
body.jm-dash .jm-dpanel--warn {
    background: var(--warn-soft);
    border-color: var(--warn-border);
    color: var(--warn);
}
body.jm-dash .jm-dpanel--warn .jm-dcard-title { color: var(--warn); }

/* Hairline separators inside a padded card (replaces border-t border-gray-100).
   Pages: discounts/detail, payments/detail, subscriptions/*, sales/invoices/* */
body.jm-dash .jm-dsep-top { border-top: 1px solid var(--border); }
body.jm-dash .jm-dsep-bottom { border-bottom: 1px solid var(--border); }
body.jm-dash .jm-dsep-y > * + * { border-top: 1px solid var(--border); }

/* Definition-list row used by the "details" panels (label start, value end).
   Pages: payments/detail, subscriptions/view, sales/invoices/view */
body.jm-dash .jm-drow {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 16px;
    padding: 10px 0;
    font-size: .9rem;
}
body.jm-dash .jm-drow + .jm-drow { border-top: 1px solid var(--border); }
body.jm-dash .jm-drow dt, body.jm-dash .jm-drow-label { color: var(--muted); }
body.jm-dash .jm-drow dd, body.jm-dash .jm-drow-value { margin: 0; color: var(--text); font-weight: 600; text-align: end; }

/* Soft inset block: totals boxes, code previews, note bodies.
   Pages: sales/invoices/*, sales/coupons/*, tickets/detail */
body.jm-dash .jm-dwell {
    background: var(--card);
    border: 1px solid var(--border);
    border-radius: var(--r-sm);
    padding: 16px 18px;
}

/* Chat/message bubbles for the ticket thread and follow-up history.
   Pages: dashboard/tickets/detail.html, dashboard/follow-ups/index.html */
body.jm-dash .jm-dmsg {
    border: 1px solid var(--border);
    border-radius: var(--r-sm);
    background: var(--card);
    padding: 14px 16px;
}
body.jm-dash .jm-dmsg--mine {
    background: rgba(249, 161, 27, .10);
    border-color: var(--border2);
}
body.jm-dash .jm-dmsg-meta { font-size: .76rem; color: var(--faint); margin-bottom: 6px; }

/* Accent-tinted surface used for "highlight" stat rows (totals, balances).
   Pages: rewards/transactions, sales/invoices/view, subscriptions/view */
body.jm-dash .jm-dhilite {
    background: rgba(249, 161, 27, .10);
    border: 1px solid var(--border2);
    border-radius: var(--r-sm);
    padding: 16px 18px;
    color: var(--text);
}

/* Denser form control for cards that pack many fields into a small grid.
   Pages: dashboard/rewards/achievements.html, sales/invoices/create.html */
body.jm-dash .jm-input--dense { padding: 7px 11px; font-size: .88rem; border-radius: var(--r-sm); }
body.jm-dash .jm-input--dense[readonly] { background: var(--card); color: var(--muted); }
body.jm-dash .jm-input-wrap > .jm-input--dense { padding-inline-start: 34px; }
body.jm-dash .jm-input-wrap > svg.jm-dcoin { color: var(--accent); width: 16px; height: 16px; }

/* Achievement medallion header (category band + tier disc + category chip).
   Page: dashboard/rewards/achievements.html */
body.jm-dash .jm-dmedal {
    position: relative;
    height: 6rem;
    display: grid;
    place-items: center;
    overflow: hidden;
    border-bottom: 1px solid var(--border);
}
body.jm-dash .jm-dmedal::before {
    content: "";
    position: absolute;
    inset: 0;
    background:
        radial-gradient(circle at 20% 30%, rgba(255, 255, 255, .10), transparent 45%),
        radial-gradient(circle at 80% 70%, rgba(3, 6, 15, .10), transparent 50%);
    pointer-events: none;
}
body.jm-dash .jm-dmedal--cup { background: linear-gradient(135deg, var(--warn-soft), var(--card)); }
body.jm-dash .jm-dmedal--medal { background: linear-gradient(135deg, var(--card2), var(--card)); }
body.jm-dash .jm-dmedal--badge { background: linear-gradient(135deg, var(--cyan-soft), var(--card)); }
body.jm-dash .jm-dmedal-disc {
    position: relative;
    display: grid;
    place-items: center;
    width: 4rem;
    height: 4rem;
    border-radius: 50%;
    box-shadow: 0 0 0 4px var(--bg2), var(--shadow);
}
body.jm-dash .jm-dmedal-disc svg { width: 2rem; height: 2rem; }
body.jm-dash .jm-dmedal-disc--gold { background: var(--grad); color: var(--btn-text); }
body.jm-dash .jm-dmedal-disc--silver { background: linear-gradient(135deg, var(--faint), var(--muted)); color: var(--bg2); }
body.jm-dash .jm-dmedal-disc--base { background: linear-gradient(135deg, var(--cyan), var(--cyan-border)); color: var(--bg2); }
body.jm-dash .jm-dmedal-cat {
    position: absolute;
    top: 8px;
    inset-inline-end: 8px;
    text-transform: uppercase;
    letter-spacing: .06em;
    font-size: .64rem;
    background: var(--bg2);
    border-color: var(--border);
    color: var(--muted);
}

/* Input with a text addon glued to one side (currency / unit).
   Pages: dashboard/rewards/settings.html, sales/invoices/create.html */
body.jm-dash .jm-dcombo {
    display: flex;
    align-items: stretch;
    border: 1px solid var(--border);
    border-radius: var(--r-sm);
    background: var(--bg2);
    overflow: hidden;
}
body.jm-dash .jm-dcombo:focus-within { border-color: var(--accent); box-shadow: 0 0 0 4px rgba(249, 161, 27, .18); }
body.jm-dash .jm-dcombo-addon {
    display: inline-flex;
    align-items: center;
    padding-inline: 16px;
    background: var(--card);
    color: var(--muted);
    font-size: .88rem;
    font-weight: 600;
    white-space: nowrap;
}
body.jm-dash .jm-dcombo-input {
    flex: 1;
    min-width: 0;
    border: 0;
    background: transparent;
    color: var(--text);
    padding: 12px 16px;
    font-size: 1.05rem;
    font-weight: 700;
    font-family: inherit;
}
body.jm-dash .jm-dcombo-input:focus { outline: none; }

/* Radio "option card" — a selectable block with a semantic tint when chosen.
   Pages: dashboard/rewards/feature.html, dashboard/payments/detail.html */
body.jm-dash .jm-dopt {
    display: flex;
    gap: 16px;
    align-items: flex-start;
    padding: 16px;
    border: 2px solid var(--border);
    border-radius: var(--r-sm);
    background: var(--bg2);
    color: var(--text);
    cursor: pointer;
    transition: border-color .2s, background .2s;
}
body.jm-dash .jm-dopt:hover { border-color: var(--border2); }
body.jm-dash .jm-dopt-radio { width: 16px; height: 16px; margin-top: 4px; flex: none; accent-color: var(--accent); }
body.jm-dash .jm-dopt--on.jm-dopt--success { border-color: var(--success-border); background: var(--success-soft); }
body.jm-dash .jm-dopt--on.jm-dopt--warn { border-color: var(--warn-border); background: var(--warn-soft); }
body.jm-dash .jm-dopt--on.jm-dopt--danger { border-color: var(--danger-border); background: var(--danger-soft); }

/* Semantic icon pill (square 32px, or --lg round 40px).
   Pages: rewards/feature, payments/*, subscriptions/*, tickets/* */
body.jm-dash .jm-dpill {
    display: inline-grid;
    place-items: center;
    width: 32px;
    height: 32px;
    border-radius: 10px;
    flex: none;
    background: var(--card);
    color: var(--muted);
}
body.jm-dash .jm-dpill svg { width: 16px; height: 16px; }
body.jm-dash .jm-dpill--lg { width: 40px; height: 40px; border-radius: 50%; }
body.jm-dash .jm-dpill--lg svg { width: 20px; height: 20px; }
body.jm-dash .jm-dpill--success { background: var(--success-soft); color: var(--success); }
body.jm-dash .jm-dpill--warn { background: var(--warn-soft); color: var(--warn); }
body.jm-dash .jm-dpill--danger { background: var(--danger-soft); color: var(--danger); }
body.jm-dash .jm-dpill--cyan { background: var(--cyan-soft); color: var(--cyan); }
body.jm-dash .jm-dpill--accent { background: rgba(249, 161, 27, .14); color: var(--accent-ink); }

/* Side "summary" panel: accent gradient by default, inverted surface with --dark.
   Pages: dashboard/rewards/settings.html, dashboard/rewards/feature.html */
body.jm-dash .jm-dsummary {
    background: var(--grad);
    color: var(--btn-text);
    border: 1px solid transparent;
    border-radius: var(--r);
    padding: 24px;
    box-shadow: var(--shadow);
}
body.jm-dash .jm-dsummary--dark {
    background: linear-gradient(160deg, var(--bg2), var(--bg));
    border-color: var(--border2);
    color: var(--text);
}
body.jm-dash .jm-dsummary-label {
    font-size: .68rem;
    text-transform: uppercase;
    letter-spacing: .08em;
    font-weight: 800;
    opacity: .75;
    margin: 0;
}
body.jm-dash .jm-dsummary-sep { border-top: 1px solid currentColor; border-top-color: color-mix(in srgb, currentColor 22%, transparent); }

/* Native file input, themed (replaces the file:* utility chain).
   Pages: dashboard/tickets/detail.html, dashboard/sales/invoices/* */
body.jm-dash .jm-dfile { font-size: .78rem; color: var(--muted); max-width: 100%; }
body.jm-dash .jm-dfile::file-selector-button {
    margin-inline-end: 10px;
    padding: 6px 12px;
    border: 1px solid var(--border);
    border-radius: 8px;
    background: var(--card);
    color: var(--text);
    font-size: .78rem;
    font-weight: 700;
    font-family: inherit;
    cursor: pointer;
}
body.jm-dash .jm-dfile::file-selector-button:hover { border-color: var(--border2); background: var(--card2); }

/* Bare icon button inside a table cell (copy-to-clipboard, inline toggles).
   Pages: dashboard/payments/index.html, sales/coupons/index.html */
body.jm-dash .jm-dicon-btn {
    display: inline-grid;
    place-items: center;
    padding: 4px;
    border: 0;
    border-radius: 7px;
    background: transparent;
    color: var(--faint);
    cursor: pointer;
}
body.jm-dash .jm-dicon-btn:hover { background: var(--card); color: var(--text); }

/* Standalone semantic text colours for figures that are not chips
   (a struck-through discount, a negative delta, a success tick).
   Pages: dashboard/payments/*, sales/invoices/view */
body.jm-dash .jm-dok, body.jm-dash .jm-dpos { color: var(--success); }
body.jm-dash .jm-dneg { color: var(--danger); }

/* Fixed backdrop for the hand-rolled (hidden-toggled) modals whose JS
   predates .jm-modal. Pages: dashboard/payments/index.html */
body.jm-dash .jm-dbackdrop {
    position: fixed;
    inset: 0;
    background: rgba(3, 6, 15, .7);
    backdrop-filter: blur(4px);
    -webkit-backdrop-filter: blur(4px);
}

/* Timeline / status dot. Pages: dashboard/payments/detail.html,
   dashboard/subscriptions/view.html, dashboard/follow-ups/index.html */
body.jm-dash .jm-ddot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    margin-top: 6px;
    flex: none;
    display: block;
    background: var(--faint);
}
body.jm-dash .jm-ddot--success { background: var(--success); }
body.jm-dash .jm-ddot--danger { background: var(--danger); }
body.jm-dash .jm-ddot--warn { background: var(--warn); }
body.jm-dash .jm-ddot--cyan { background: var(--cyan); }
body.jm-dash .jm-ddot--accent { background: var(--accent); }

/* Free-standing .jm-dcoin (outside .jm-input-wrap): the points star icon. */
body.jm-dash svg.jm-dcoin { color: var(--accent); }

/* Small 16:9 thumbnail inside a table cell.
   Page: dashboard/subscriptions/index.html */
body.jm-dash .jm-dthumb {
    width: 80px;
    height: 56px;
    border-radius: var(--r-sm);
    overflow: hidden;
    background: var(--thumb-bg);
    color: var(--faint);
}

/* "Popular" marker: corner dot on the thumbnail + tinted row.
   Page: dashboard/subscriptions/index.html
   NOTE: subscription-popular-toggle.js adds/removes .jm-dpop-dot and
   .jm-dpop-row at runtime — keep the names in sync with that file. */
body.jm-dash .jm-dpop-dot {
    position: absolute;
    top: -2px;
    inset-inline-end: -2px;
    width: 10px;
    height: 10px;
    border-radius: 50%;
    background: var(--accent);
    border: 2px solid var(--bg2);
}
body.jm-dash tr.jm-dpop-row > td { background: rgba(249, 161, 27, .07); }
body.jm-dash .popular-toggle .popular-toggle__icon { width: 16px; height: 16px; color: var(--faint); }
body.jm-dash .popular-toggle.is-popular .popular-toggle__icon { color: var(--accent); }

/* Action dropdown menu (the ⋮ menu in list rows).
   Page: dashboard/subscriptions/index.html
   .action-dropdown-menu / .action-dropdown-trigger are bound by
   subscription-actions.js — do not rename them. */
body.jm-dash .jm-dmenu {
    width: 12rem;
    padding: 4px;
    background: var(--bg2);
    border: 1px solid var(--border);
    border-radius: var(--r-sm);
    box-shadow: var(--shadow);
}
body.jm-dash .jm-dmenu-item {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    padding: 8px 12px;
    border: 0;
    border-radius: 8px;
    background: none;
    color: var(--text);
    font-size: .88rem;
    font-family: inherit;
    text-align: start;
    cursor: pointer;
}
body.jm-dash .jm-dmenu-item:hover { background: var(--card); }
body.jm-dash .jm-dmenu-item > svg { width: 16px; height: 16px; flex: none; color: var(--faint); }
body.jm-dash .jm-dmenu-item--danger { color: var(--danger); }
body.jm-dash .jm-dmenu-item--danger > svg { color: var(--danger); }
body.jm-dash .jm-dmenu-item--danger:hover { background: var(--danger-soft); }
body.jm-dash .jm-dmenu-item--success { color: var(--success); }
body.jm-dash .jm-dmenu-item--success > svg { color: var(--success); }
body.jm-dash .jm-dmenu-item--success:hover { background: var(--success-soft); }
body.jm-dash .jm-dmenu-sep { height: 1px; margin: 4px 0; background: var(--border); }

/* A .jm-ddot used as a chip bullet must not carry the timeline top margin. */
body.jm-dash .jm-chip > .jm-ddot { margin-top: 0; }

/* Large overview thumbnail (detail pages).
   Page: dashboard/subscriptions/view.html */
body.jm-dash .jm-dthumb--lg {
    width: 100%;
    height: 11rem;
    border-radius: var(--r-sm);
    overflow: hidden;
    background: var(--thumb-bg);
    color: var(--faint);
}
@media (min-width: 1024px) { body.jm-dash .jm-dthumb--lg { width: 16rem; } }

/* .jm-empty nested inside a card body should not repeat the card surface. */
body.jm-dash .jm-dcard-body > .jm-empty { background: transparent; border: 0; padding: 30px 20px; }

/* Compact variant of the option card, used for checkbox rows in long forms.
   Pages: dashboard/subscriptions/create.html + edit.html */
body.jm-dash .jm-dopt--sm { padding: 12px; border-width: 1px; align-items: center; gap: 12px; }
body.jm-dash .jm-dopt input[type="checkbox"] {
    width: 16px; height: 16px; flex: none; accent-color: var(--accent);
}
body.jm-dash .jm-dopt--sm:hover { background: var(--card); }

/* Currency-prefixed number input.
   Pages: dashboard/subscriptions/create.html + edit.html, sales/coupons/create.html */
body.jm-dash .jm-dmoney { position: relative; }
body.jm-dash .jm-dmoney-sign {
    position: absolute;
    inset-block: 0;
    inset-inline-start: 0;
    display: flex;
    align-items: center;
    padding-inline-start: 16px;
    color: var(--faint);
    font-size: .88rem;
    font-weight: 600;
    pointer-events: none;
}
body.jm-dash .jm-dmoney > .jm-input { padding-inline-start: 34px; }

/* Full-width autocomplete popover under a search field.
   Pages: dashboard/subscriptions/create.html + edit.html */
body.jm-dash .jm-dsearch-pop {
    position: absolute;
    z-index: 10;
    top: 100%;
    inset-inline: 0;
    margin-top: 4px;
    max-height: 14rem;
    overflow-y: auto;
    background: var(--bg2);
    border: 1px solid var(--border);
    border-radius: var(--r-sm);
    box-shadow: var(--shadow);
}

/* Placeholder behind .video-thumb when no poster frame exists.
   Page: dashboard/subscriptions/edit.html */
body.jm-dash .jm-dvideo-ph { background: var(--thumb-bg); color: var(--faint); }

/* Danger variant of the bare icon button (remove-row buttons).
   Pages: dashboard/sales/invoices/create.html */
body.jm-dash .jm-dicon-btn--danger { color: var(--danger); }
body.jm-dash .jm-dicon-btn--danger:hover { background: var(--danger-soft); color: var(--danger); }

/* Input with a trailing unit sign (%, days).
   Pages: dashboard/sales/invoices/create.html */
body.jm-dash .jm-dsuffix { position: relative; }
body.jm-dash .jm-dsuffix-sign {
    position: absolute;
    inset-block: 0;
    inset-inline-end: 0;
    display: flex;
    align-items: center;
    padding-inline-end: 12px;
    color: var(--faint);
    font-size: .88rem;
    pointer-events: none;
}
body.jm-dash .jm-dsuffix > .jm-input { padding-inline-end: 30px; }

/* Read-only computed value styled like a disabled input.
   Pages: dashboard/sales/invoices/create.html */
body.jm-dash .jm-dreadout {
    padding: 7px 11px;
    background: var(--card);
    border: 1px solid var(--border);
    border-radius: var(--r-sm);
    color: var(--muted);
    font-size: .88rem;
    font-weight: 600;
    text-align: center;
}

/* Micro-tag: smaller than .jm-chip, for inline role / duration markers.
   Page: dashboard/sales/invoices/view.html */
body.jm-dash .jm-dtag {
    display: inline-flex;
    align-items: center;
    padding: 0 6px;
    border-radius: 6px;
    font-size: 10px;
    font-weight: 700;
    line-height: 1.6;
    background: var(--card2);
    color: var(--muted);
    border: 1px solid var(--border);
}
body.jm-dash .jm-dtag--cyan { background: var(--cyan-soft); border-color: var(--cyan-border); color: var(--cyan); }
body.jm-dash .jm-dtag--danger { background: var(--danger-soft); border-color: var(--danger-border); color: var(--danger); }
body.jm-dash .jm-dtag--accent { background: var(--warn-soft); border-color: var(--warn-border); color: var(--warn); }
body.jm-dash .jm-dtag--success { background: var(--success-soft); border-color: var(--success-border); color: var(--success); }

/* Table footer summary rows.
   Page: dashboard/sales/invoices/view.html */
body.jm-dash .jm-dtfoot { border-top: 2px solid var(--border); }
body.jm-dash .jm-dtfoot td { background: var(--card); border-bottom: 0; }

/* Borderless input sitting inside a .jm-dwell (read-only payment URL).
   Page: dashboard/sales/invoices/view.html */
body.jm-dash .jm-dbare-input {
    min-width: 0;
    border: 0;
    background: transparent;
    color: var(--muted);
    font-size: .88rem;
    padding: 0;
    font-family: inherit;
}
body.jm-dash .jm-dbare-input:focus { outline: none; }

/* QR code frame — keeps a white plate so the code stays scannable in dark mode.
   Page: dashboard/sales/invoices/view.html */
body.jm-dash .jm-dqr {
    padding: 12px;
    background: #fff;
    border: 1px solid var(--border);
    border-radius: var(--r);
    box-shadow: var(--shadow);
}

/* "Copied!" success state on the copy-link button.
   Page: dashboard/sales/invoices/view.html (toggled by its inline script) */
body.jm-dash .jm-btn.is-copied {
    background: var(--success);
    color: var(--bg2);
    box-shadow: none;
}

/* ---------- admin-marketing ---------- */
/* legal-pages/form.html, blog/form.html, marketing/*/create.html,
   settings/index.html — the red "*" marker next to a required label. */
body.jm-dash .jm-dreq { color: var(--danger); font-weight: 700; }

/* legal-pages/index.html, blog/index.html, monitoring/index.html —
   a whole .jm-dcard that IS a link; picks up the same hover lift the
   .jm-dstat cards have. */
body.jm-dash a.jm-dlink-card {
    display: block;
    transition: transform .25s, border-color .25s, box-shadow .25s;
}
body.jm-dash a.jm-dlink-card:hover {
    transform: translateY(-3px);
    border-color: var(--border2);
    box-shadow: var(--shadow);
}

/* community/index.html (delete + icon-upload confirms), marketing/* —
   a narrow confirm dialog; site.css only ships the default and --lg widths. */
body.jm-dash .jm-modal-panel--sm { max-width: 420px; }

/* community/index.html, community/detail.html, marketing/student-videos —
   square thumbnail for a channel / course icon in a table row or header. */
body.jm-dash .jm-dthumb-sm {
    width: 40px; height: 40px; flex: none;
    border-radius: var(--r-sm);
    object-fit: cover;
    background: var(--thumb-bg);
    border: 1px solid var(--border);
}
body.jm-dash .jm-dthumb-lg {
    width: 64px; height: 64px; flex: none;
    border-radius: var(--r-sm);
    object-fit: cover;
    background: var(--thumb-bg);
    border: 1px solid var(--border);
}

/* community/detail.html, notifications/index.html — destructive variant of
   the shared .jm-icon-btn (row "delete" affordances). */
body.jm-dash .jm-icon-btn--danger { color: var(--faint); }
body.jm-dash .jm-icon-btn--danger:hover { color: var(--danger); border-color: var(--danger-border); }

/* community/index.html, monitoring/index.html — an icon button sized to sit
   inline in a dense table row. */
body.jm-dash .jm-icon-btn--xs { width: 32px; height: 32px; border-radius: 9px; }
body.jm-dash .jm-icon-btn--xs svg { width: 15px; height: 15px; }

/* notifications/index.html — unread accent rail. Driven by :has() on the
   unread dot instead of a class, because notification-page.js marks a card
   read by REMOVING `.notification-unread-dot` (it also removes the old
   `border-s-4 border-s-indigo-500` utilities, which is now a harmless no-op). */
body.jm-dash .jm-dnotif { border-inline-start: 1px solid var(--border); transition: border-color .2s; }
body.jm-dash .jm-dnotif:has(.notification-unread-dot) {
    border-inline-start: 4px solid var(--accent);
}

/* blog/form.html, marketing/* — dashed drop zone for a click-to-upload image.
   Deliberately sets NO `display`, because blog-form.js hides it with
   Tailwind's `.hidden` and dashboard-shell.css is linked after Tailwind. */
body.jm-dash .jm-ddrop {
    position: relative;
    border: 2px dashed var(--border);
    border-radius: var(--r-sm);
    padding: 24px;
    text-align: center;
    cursor: pointer;
    transition: border-color .2s, background .2s;
}
body.jm-dash .jm-ddrop:hover { border-color: var(--border2); background: var(--card); }

/* blog/form.html — the uploaded-image preview frame (no `display`, same
   reason as .jm-ddrop). */
body.jm-dash .jm-dpreview { border: 1px solid var(--border); }

/* blog/form.html — round "remove image" button floating over the preview. */
body.jm-dash .jm-dimg-remove {
    position: absolute;
    top: 8px;
    inset-inline-end: 8px;
    display: grid;
    place-items: center;
    width: 32px;
    height: 32px;
    border-radius: 50%;
    border: 1px solid var(--danger-border);
    background: var(--danger-soft);
    backdrop-filter: blur(6px);
    color: var(--danger);
    cursor: pointer;
}
body.jm-dash .jm-dimg-remove:hover { background: var(--danger); color: var(--bg2); }
body.jm-dash .jm-dimg-remove svg { width: 16px; height: 16px; }

/* blog/form.html, settings/index.html — a hairline rule that separates an
   inline sub-form from the block above it. */
body.jm-dash .jm-dhairline { border-top: 1px solid var(--border); }

/* monitoring/index.html — the traffic-source / device share bars are a
   denser variant of the shared .jm-progress. */
body.jm-dash .jm-progress--thin { height: 6px; }

/* monitoring/index.html, settings/index.html — a plain tinted list row
   (event-type counts, key/value lists) where a table would be overkill. */
body.jm-dash .jm-drow {
    background: var(--card);
    border-radius: var(--r-sm);
    color: var(--text);
}

/* marketing/detail.html, marketing/newsletter — an accent-coloured figure
   (open rate, conversion rate) beside the plain --pos/--neg/--warn ones
   that css-additions-student.css defines. */
body.jm-dash .jm-dnum--accent { color: var(--accent-ink); }
/* --pos was expected from css-additions-student.css but did not survive the
   merge into dashboard-shell.css; marketing/detail.html and
   recording-invites/detail.html need it, so it is declared here. */
body.jm-dash .jm-dnum--pos { color: var(--success); }

/* marketing/*, monitoring — .jm-chip-dot is hardcoded to the gold accent in
   site.css, which fights the semantic chip variants used for campaign and
   recipient status. Inside a coloured chip the dot follows the chip. */
body.jm-dash .jm-chip--success > .jm-chip-dot,
body.jm-dash .jm-chip--danger > .jm-chip-dot,
body.jm-dash .jm-chip--warn > .jm-chip-dot,
body.jm-dash .jm-chip--cyan > .jm-chip-dot,
body.jm-dash .jm-chip--muted > .jm-chip-dot { background: currentColor; box-shadow: none; }

/* marketing/announcements/create.html, marketing/campaigns/create.html —
   bordered, scrollable box holding a list of pickable checkbox rows, and the
   row itself. .jm-dpick sets NO `display`: marketing-announcement.js filters
   rows with `item.style.display = '' | 'none'` and relies on the Tailwind
   `flex` utility for the restored value. */
body.jm-dash .jm-dpicklist {
    border: 1px solid var(--border);
    border-radius: var(--r-sm);
    background: var(--bg2);
}
body.jm-dash .jm-dpick { border-radius: var(--r-sm); color: var(--text); transition: background .15s; }
body.jm-dash .jm-dpick:hover { background: var(--card); }
body.jm-dash .jm-dpick:has(input:checked) { background: rgba(249, 161, 27, .1); }

/* Native checkbox tinted with the accent, for pick lists and option rows
   that are not wrapped in a .jm-check. */
body.jm-dash .jm-dcheckbox { width: 16px; height: 16px; accent-color: var(--accent); flex: none; }

/* marketing/campaigns/create.html — bordered radio "cards" for the campaign
   type. The selected look is driven by :has(input:checked) rather than a
   class, so it survives marketing-campaign.js still adding/removing the old
   `border-indigo-500 / bg-indigo-50/50 / border-gray-200` utilities (now a
   no-op). Sets no `display` — the Tailwind `flex` utility supplies it. */
body.jm-dash .jm-dradio-card {
    border: 2px solid var(--border);
    border-radius: var(--r-sm);
    color: var(--text);
    transition: border-color .2s, background .2s;
}
body.jm-dash .jm-dradio-card:hover { border-color: var(--border2); }
/* The input may be a CHILD of the card (campaigns/create) or a SIBLING of it
   inside a wrapping <label> (recording-invites reward options). */
body.jm-dash .jm-dradio-card:has(input:checked),
body.jm-dash label:has(> input:checked) > .jm-dradio-card {
    border-color: var(--accent);
    background: rgba(249, 161, 27, .1);
}
body.jm-dash label:has(> input:focus-visible) > .jm-dradio-card {
    box-shadow: 0 0 0 4px rgba(249, 161, 27, .18);
}

/* recording-invites/index.html — the status filter pills are .jm-chip--muted
   whose active state recording-invites-management.js toggles at runtime with
   `.is-active`; site.css declares --muted after .is-active, so re-assert it. */
body.jm-dash .jm-chip--muted.is-active {
    background: var(--grad);
    color: var(--btn-text);
    border-color: transparent;
}

/* marketing/campaigns/create.html (user search), settings/index.html —
   floating results panel under an input. No `display`: marketing-campaign.js
   toggles it with Tailwind's `.hidden` and the `absolute` utility positions it. */
body.jm-dash .jm-dpopover {
    background: var(--bg2);
    border: 1px solid var(--border);
    border-radius: var(--r-sm);
    box-shadow: var(--shadow);
}

/* marketing/newsletter/index.html — the send-newsletter dialog has its own
   scrolling body, so the panel drops site.css's padding and overflow and the
   head/foot become full-bleed bars. */
body.jm-dash .jm-modal-panel--flush { padding: 0; overflow: hidden; max-height: 90vh; }
body.jm-dash .jm-dmodal-bar {
    padding: 16px 24px;
    margin: 0;
    border-bottom: 1px solid var(--border);
}
body.jm-dash .jm-dmodal-bar--foot { border-bottom: 0; border-top: 1px solid var(--border); background: var(--card); }

/* marketing/newsletter/index.html, settings/index.html — hairline-separated
   rows in a card list (not a table). */
body.jm-dash .jm-dlistrow { border-bottom: 1px solid var(--border); }
body.jm-dash .jm-dlistrow:last-child { border-bottom: 0; }

/* marketing/student-videos/index.html — tall upload/edit dialogs that must
   scroll the whole overlay instead of the panel (the panel holds a fixed
   head and foot bar). */
body.jm-dash .jm-modal--scroll { align-items: flex-start; overflow-y: auto; }
body.jm-dash .jm-modal--scroll > .jm-modal-panel { margin-block: 32px; }

/* SAFETY: site.css is linked AFTER Tailwind's output.css, so a single-class
   component rule such as `.jm-form-row { display: flex }` out-ranks
   `.hidden { display: none }`. site.css already patches .jm-alert and
   .jm-modal; these are the other components this group toggles with
   Tailwind's `.hidden` (recording-invites reward panels, conditional rows). */
body.jm-dash .jm-form-row.hidden,
body.jm-dash .jm-check.hidden,
body.jm-dash .jm-chip.hidden,
body.jm-dash .jm-btn.hidden,
body.jm-dash .jm-empty.hidden,
body.jm-dash .jm-progress.hidden { display: none; }

/* recording-invites/index.html — accent/cyan tint for a standalone icon that
   is not inside a .jm-dstat-icon or .jm-dbadge-icon pill. */
body.jm-dash .jm-dicon-accent { color: var(--accent-ink); }
body.jm-dash .jm-dicon-cyan { color: var(--cyan); }

/* recording-invites/index.html, settings/index.html — currency/unit prefix
   glued to the start of a .jm-input. */
body.jm-dash .jm-dprefix { position: relative; display: flex; align-items: center; }
body.jm-dash .jm-dprefix > span:first-child {
    position: absolute;
    inset-inline-start: 12px;
    color: var(--faint);
    pointer-events: none;
    font-size: .9rem;
}
body.jm-dash .jm-dprefix > .jm-input { padding-inline-start: 30px; }

/* recording-invites/index.html — read-only box holding a generated link the
   admin copies once. */
body.jm-dash .jm-dcopybox {
    background: var(--cyan-soft);
    border: 1px solid var(--cyan-border);
    border-radius: var(--r-sm);
    color: var(--text);
}

/* ------------------------------------------------------------------
   recording-invites/detail.html (the review page)
   The page used to pull in static/css/recording-invite-review.css, which was
   all hardcoded slate/indigo hex; that file is deleted and the two things it
   provided (the copy button and its "just copied" pulse) live here on tokens.
   ------------------------------------------------------------------ */

/* Small all-caps field label above a value (meta strips, dl terms). */
body.jm-dash .jm-dminilabel {
    font-size: .68rem;
    font-weight: 600;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--faint);
    margin: 0 0 2px;
}

/* 16:9 video surround. Stays near-black in both themes on purpose — it is
   the letterbox behind the player, not a themed surface. */
body.jm-dash .jm-dvideo-frame {
    position: relative;
    width: 100%;
    aspect-ratio: 16 / 9;
    background: #070b17;
    border: 1px solid var(--border);
    border-radius: var(--r);
    overflow: hidden;
}
body.jm-dash .jm-dvideo-missing {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: 24px;
    text-align: center;
    color: rgba(159, 176, 204, .7);
}

/* Change-status dropdown. .jm-dmenu / .jm-dmenu-item are ALREADY defined in
   dashboard-shell.css (by another page's migration) and are reused as-is —
   only the status dot is new. Neither sets `display`, which matters because
   recording-invite-review.js toggles the menu with Tailwind's `.hidden`. */
body.jm-dash .jm-dmenu-dot { width: 8px; height: 8px; border-radius: 50%; flex: none; background: var(--faint); }
body.jm-dash .jm-dmenu-dot--success { background: var(--success); }
body.jm-dash .jm-dmenu-dot--danger { background: var(--danger); }
body.jm-dash .jm-dmenu-dot--warn { background: var(--warn); }
body.jm-dash .jm-dmenu-dot--accent { background: var(--accent); }

/* Copy-to-clipboard pill. recording-invite-review.js finds these by
   [data-rir-copy] and toggles `.is-copied` on them for 1.2s. */
body.jm-dash .jm-dcopy-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 26px;
    height: 26px;
    border-radius: 8px;
    border: 1px solid var(--border);
    background: var(--card);
    color: var(--muted);
    cursor: pointer;
    flex: none;
    transition: background .15s, color .15s, transform .15s;
}
body.jm-dash .jm-dcopy-btn svg { width: 14px; height: 14px; }
body.jm-dash .jm-dcopy-btn:hover { background: var(--card2); color: var(--text); }
body.jm-dash .jm-dcopy-btn:active { transform: scale(.94); }
body.jm-dash .jm-dcopy-btn.is-copied {
    background: var(--success-soft);
    border-color: var(--success-border);
    color: var(--success);
}
body.jm-dash .jm-dcopy-btn.is-copied svg { animation: jm-dcopy-pop .4s ease-out; }
@keyframes jm-dcopy-pop {
    0%   { transform: scale(.8); }
    50%  { transform: scale(1.2); }
    100% { transform: scale(1); }
}

/* ---------- settings-index ---------- */
/* ---------- settings tab rail (left, desktop) ----------
   #panel-* switching is driven by settings.js, which swaps
   bg-indigo-50/text-indigo-700 against text-gray-600/hover:bg-gray-50. */
body.jm-dash .settings-tab,
body.jm-dash .settings-raillink {
    color: var(--muted);
    background: transparent;
    border: 0;
    cursor: pointer;
    font-family: inherit;
}
body.jm-dash .settings-tab:hover,
body.jm-dash .settings-raillink:hover { background: var(--card); color: var(--text); }
body.jm-dash .settings-tab svg,
body.jm-dash .settings-raillink svg { color: var(--faint); }
/* active state written by settings.js */
body.jm-dash .settings-tab.bg-indigo-50 {
    background: rgba(249, 161, 27, .12);
    color: var(--accent-ink);
}
body.jm-dash .settings-tab.bg-indigo-50 svg { color: var(--accent-ink); }

/* ---------- settings tab rail (top, mobile) ---------- */
body.jm-dash .jm-dtabrail { border-bottom: 1px solid var(--border); }
body.jm-dash .settings-tab-mobile,
body.jm-dash .settings-raillink-m {
    color: var(--muted);
    background: transparent;
    border: 0;
    border-bottom: 2px solid transparent;
    cursor: pointer;
    font-family: inherit;
}
body.jm-dash .settings-tab-mobile:hover,
body.jm-dash .settings-raillink-m:hover { color: var(--text); }
/* active state written by settings.js */
body.jm-dash .settings-tab-mobile.border-indigo-600 {
    color: var(--accent-ink);
    border-bottom-color: var(--accent);
}

/* ---------- rules / separators used by the rail and panels ---------- */
body.jm-dash .jm-drule { border-top: 1px solid var(--border); }
body.jm-dash .jm-drule-b { border-bottom: 1px solid var(--border); }
body.jm-dash .jm-drule-v { background: var(--border); }

/* ---------- toggle switch that keeps the Tailwind `peer` markup ----------
   site.css .jm-switch expects <label><input><span>; these settings
   toggles are <label><input class="sr-only peer"><div>, and the input
   ids/names are form data, so the DOM is kept and the track restyled. */
body.jm-dash .jm-switch-track {
    position: relative;
    width: 44px;
    height: 24px;
    border-radius: 999px;
    background: var(--card2);
    border: 1px solid var(--border);
    transition: background .2s, border-color .2s;
}
body.jm-dash .jm-switch-track::after {
    content: "";
    position: absolute;
    width: 18px;
    height: 18px;
    inset-inline-start: 2px;
    top: 2px;
    border-radius: 50%;
    background: var(--faint);
    transition: transform .2s, background .2s;
}
body.jm-dash .peer:checked ~ .jm-switch-track { background: var(--grad); border-color: transparent; }
body.jm-dash .peer:checked ~ .jm-switch-track::after { background: var(--btn-text); transform: translateX(20px); }
[dir="rtl"] body.jm-dash .peer:checked ~ .jm-switch-track::after { transform: translateX(-20px); }
body.jm-dash .peer:checked ~ .jm-switch-track--danger { background: var(--danger); }
body.jm-dash .peer:focus-visible ~ .jm-switch-track { box-shadow: 0 0 0 4px rgba(249, 161, 27, .18); }

/* small inline toggle (translations filter) */
body.jm-dash .jm-switch-track--xs { width: 36px; height: 20px; }
body.jm-dash .jm-switch-track--xs::after { width: 14px; height: 14px; }
body.jm-dash .peer:checked ~ .jm-switch-track--xs::after { transform: translateX(16px); }
[dir="rtl"] body.jm-dash .peer:checked ~ .jm-switch-track--xs::after { transform: translateX(-16px); }

/* ---------- payment / storage test-vs-live mode ----------
   Server renders jm-dmode--*/jm-dmodebox--*; settings.js
   setupModeToggle() then swaps the legacy palette names. */
body.jm-dash .jm-dmode { color: var(--faint); }
body.jm-dash .jm-dmode--off { color: var(--faint); }
body.jm-dash .jm-dmode--test { color: var(--accent-ink); }
body.jm-dash .jm-dmode--live { color: var(--danger); }

body.jm-dash .jm-dmodebox {
    border: 2px solid var(--border);
    background: var(--card);
    transition: border-color .2s, background .2s, opacity .2s;
}
body.jm-dash .jm-dmodebox--dim { border-color: var(--border); background: var(--card); }
body.jm-dash .jm-dmodebox--test { border-color: var(--accent); background: rgba(249, 161, 27, .08); }
body.jm-dash .jm-dmodebox--live { border-color: var(--danger-border); background: var(--danger-soft); }

/* runtime state from settings.js — declared last so it wins */
body.jm-dash .jm-dmode.text-gray-400 { color: var(--faint); }
body.jm-dash .jm-dmode.text-indigo-600 { color: var(--accent-ink); }
body.jm-dash .jm-dmode.text-red-600,
body.jm-dash .jm-dmode.text-red-500 { color: var(--danger); }
body.jm-dash .jm-dmodebox.border-gray-200 { border-color: var(--border); background: var(--card); }
body.jm-dash .jm-dmodebox.border-indigo-200 { border-color: var(--accent); background: rgba(249, 161, 27, .08); }
body.jm-dash .jm-dmodebox.border-red-200 { border-color: var(--danger-border); background: var(--danger-soft); }

/* ---------- radio cards (Templates tab: site theme + course player) ----------
   settings.js drives .tpl-card-selected / inline transform+opacity on
   .tpl-radio-dot, .tpl-card-ring, .tpl-radio and display on
   .tpl-active-badge. Only the colours live here. */
body.jm-dash .jm-dpreview-frame { border: 1px solid var(--border); }
body.jm-dash .tpl-card .jm-dpreview-frame { transition: border-color .2s; }
body.jm-dash .tpl-card:hover .jm-dpreview-frame { border-color: var(--border2); }
body.jm-dash .tpl-card-selected .jm-dpreview-frame { border-color: var(--accent); }
body.jm-dash .tpl-radio { border: 2px solid var(--border2); }
body.jm-dash .tpl-radio-dot { background: var(--accent); }
body.jm-dash .tpl-card-ring { box-shadow: 0 0 0 2px var(--bg), 0 0 0 4px var(--accent); }

/* ---------- segmented-control shell (email-template preview device switch) ----------
   The BUTTONS inside it (.et-preview-device / -tpl, base + .is-active)
   live in css-additions-js-editors.css — email-template-editor.js owns
   that state now and toggles `is-active`. Only the pill that wraps them
   is defined here. */
body.jm-dash .jm-dseg { background: var(--card); border: 1px solid var(--border); border-radius: 10px; }

/* ---------- sub-tabs inside the Email Template panel ----------
   .et-subtab (base / hover / .is-active) also lives in
   css-additions-js-editors.css; only the rail around them is here.
   #et-subtab-global ships with `is-active` in the markup. */
body.jm-dash .jm-dsubtabs { background: var(--bg2); border: 1px solid var(--border); }

/* ---------- free-text editor shell (email body) ----------
   .et-toolbar .et-tool-btn (incl. .active) and .et-editor-area's
   :focus ring / :empty placeholder are in css-additions-js-editors.css.
   The chrome the markup asks for — toolbar surface, editor field
   surface — is here, and the two do not overlap. */
body.jm-dash .jm-deditor-bar { background: var(--card); border: 1px solid var(--border); border-bottom: 0; }
body.jm-dash .jm-deditor-area { background: var(--bg2); border: 1px solid var(--border); color: var(--text); }
body.jm-dash .jm-deditor-area:focus { outline: none; border-color: var(--accent); }
body.jm-dash .et-tool-select { background: var(--bg2); border: 1px solid var(--border); color: var(--text); }

/* ---------- dropzone (homepage hero poster) ---------- */
body.jm-dash .jm-ddrop { border: 2px dashed var(--border2); color: var(--muted); background: var(--card); }
body.jm-dash .jm-ddrop:hover { border-color: var(--accent); background: rgba(249, 161, 27, .06); }
body.jm-dash .jm-dtrack { background: var(--card2); }
body.jm-dash .jm-dtrack > div { background: var(--grad); }

/* ---------- soft note / callout row (storage note, redis hint, legal hint) ---------- */
body.jm-dash .jm-dnote {
    display: flex;
    align-items: flex-start;
    gap: 12px;
    border: 1px solid var(--warn-border);
    background: var(--warn-soft);
    color: var(--warn);
    border-radius: 12px;
}
body.jm-dash .jm-dnote--info { border-color: var(--cyan-border); background: var(--cyan-soft); color: var(--cyan); }
body.jm-dash .jm-dnote--muted { border-color: var(--border); background: var(--card); color: var(--muted); }
body.jm-dash .jm-dnote svg { flex: none; }

/* ---------- mini KPI tile used on the Translations tab ---------- */
body.jm-dash .jm-dtile { border: 1px solid var(--border); background: var(--card); border-radius: 12px; }
body.jm-dash .jm-dtile--warn { border-color: var(--warn-border); background: var(--warn-soft); }
body.jm-dash .jm-dtile--accent { border-color: var(--accent); background: rgba(249, 161, 27, .1); }
body.jm-dash .jm-dtile-label { color: var(--faint); }
body.jm-dash .jm-dtile-value { color: var(--text); }
body.jm-dash .jm-dtile--warn .jm-dtile-label,
body.jm-dash .jm-dtile--warn .jm-dtile-value { color: var(--warn); }
body.jm-dash .jm-dtile--accent .jm-dtile-label,
body.jm-dash .jm-dtile--accent .jm-dtile-value { color: var(--accent-ink); }

/* ---------- list row + table-ish grid header (Translations tab) ---------- */
body.jm-dash .jm-dlisthead { background: var(--card); border-bottom: 1px solid var(--border); color: var(--faint); }
body.jm-dash .jm-dlist-divide > * + * { border-top: 1px solid var(--border); }
body.jm-dash .jm-dtag { background: var(--bg2); border: 1px solid var(--border); color: var(--muted); }

/* ---------- decorative aura behind a panel header ---------- */
body.jm-dash .jm-daura {
    background: radial-gradient(closest-side, rgba(249, 161, 27, .25), transparent);
    filter: blur(60px);
}

/* ---------- gradient badge tile (legal pages / translations hero icons) ---------- */
body.jm-dash .jm-dhero-icon {
    background: var(--grad);
    color: var(--btn-text);
    box-shadow: var(--glow);
}

/* ---------- modal shell (email delivery logs) ---------- */
body.jm-dash .jm-dmodal-panel { background: var(--bg2); border: 1px solid var(--border); box-shadow: var(--shadow); }
body.jm-dash .jm-dmodal-head { border-bottom: 1px solid var(--border); }
body.jm-dash .jm-dmodal-title { color: var(--text); }
body.jm-dash .jm-dmodal-close { color: var(--faint); background: transparent; border: 0; cursor: pointer; }
body.jm-dash .jm-dmodal-close:hover { color: var(--text); background: var(--card); }

/* ---------- spinner ---------- */
body.jm-dash .jm-dspinner { color: var(--accent); }

/* ---------- field-level error text (client-side validation) ---------- */
body.jm-dash .settings-field-error { color: var(--danger); }

/* ---------- colour-only error text ----------
   NOT .jm-field-error: settings.js toggles `hidden` on these nodes, and
   site.css shows .jm-field-error:not(:empty) at a higher specificity
   than .hidden, so the message would never hide again. */
body.jm-dash .jm-derror { color: var(--danger); }

/* ---------- live status pill (Redis) ----------
   redis-config.js swaps three legacy palette trios on the pill and
   rewrites the dot's whole className, so both are styled by the
   runtime names as well as the base class. */
body.jm-dash .jm-dpill { background: var(--card); border: 1px solid var(--border); color: var(--muted); }
body.jm-dash .jm-dpill-dot { background: var(--faint); }
body.jm-dash .jm-dpill.bg-emerald-50 { background: var(--success-soft); border-color: var(--success-border); color: var(--success); }
body.jm-dash .jm-dpill.bg-rose-50 { background: var(--danger-soft); border-color: var(--danger-border); color: var(--danger); }
body.jm-dash .jm-dpill.bg-gray-100 { background: var(--card); border-color: var(--border); color: var(--muted); }
body.jm-dash .jm-dpill .bg-emerald-500 { background: var(--success); }
body.jm-dash .jm-dpill .bg-rose-500 { background: var(--danger); }
body.jm-dash .jm-dpill .bg-gray-400 { background: var(--faint); }

/* ============================================================
   Email-template live preview (#et-preview-frame / #et-tpl-preview-frame)
   ------------------------------------------------------------
   INTENTIONALLY LITERAL. This is a miniature of the HTML email that
   will actually be delivered, so it must keep the light "paper" look
   in both dashboard themes — exactly like the theme preview cards
   under #theme-default-cards. The stage the mock-up sits on IS
   dashboard chrome and stays tokenised.

   email-template-editor.js rewrites #et-tpl-preview-icon-bg and
   #et-tpl-preview-icon-svg className wholesale from a table of
   Tailwind tints, so those tints are pinned here too, scoped inside
   .jm-demail, which also keeps dashboard-bridge.css from theming them.
   ============================================================ */
body.jm-dash .jm-demail-stage { background: var(--card); border: 1px solid var(--border); }

body.jm-dash .jm-demail { background: #f1f5f9; box-shadow: 0 1px 2px rgba(15, 23, 42, .08); }
body.jm-dash .jm-demail-badge { background: rgba(255, 255, 255, .2); color: rgba(255, 255, 255, .9); }
body.jm-dash .jm-demail-company { color: rgba(255, 255, 255, .85); }
body.jm-dash .jm-demail-body { background: #ffffff; }
body.jm-dash .jm-demail-iconring { background: #ffffff; box-shadow: 0 4px 6px -1px rgba(0, 0, 0, .1); }
body.jm-dash .jm-demail-h { color: #111827; }
body.jm-dash .jm-demail-rule { background: #6366f1; }
body.jm-dash .jm-demail-strong { color: #1f2937; }
body.jm-dash .jm-demail-p { color: #4b5563; }
body.jm-dash .jm-demail-sum { background: #f9fafb; border: 1px solid #f3f4f6; }
body.jm-dash .jm-demail-sum-row + .jm-demail-sum-row { border-top: 1px solid #f3f4f6; }
body.jm-dash .jm-demail-sum-k { color: #9ca3af; font-size: .75rem; }
body.jm-dash .jm-demail-sum-v { color: #374151; font-size: .8125rem; font-weight: 600; }
body.jm-dash .jm-demail-foot { background: #f9fafb; border-top: 1px solid #f3f4f6; }
body.jm-dash .jm-demail-foot-t { color: #9ca3af; }
body.jm-dash .jm-demail-foot-l { color: #d1d5db; }
body.jm-dash .jm-demail-foot-l:hover { color: #9ca3af; }

/* icon tints — markup default + every value email-template-editor.js can set */
body.jm-dash .jm-demail-icon--success, body.jm-dash .jm-demail .bg-green-50 { background: #f0fdf4; }
body.jm-dash .jm-demail .bg-red-50 { background: #fef2f2; }
body.jm-dash .jm-demail .bg-amber-50 { background: #fffbeb; }
body.jm-dash .jm-demail .bg-yellow-50 { background: #fefce8; }
body.jm-dash .jm-demail .bg-blue-50 { background: #eff6ff; }
body.jm-dash .jm-demail .bg-indigo-50 { background: #eef2ff; }
body.jm-dash .jm-demail .bg-gray-100 { background: #f3f4f6; }
body.jm-dash .jm-demail-ic--success, body.jm-dash .jm-demail .text-green-500 { color: #22c55e; }
body.jm-dash .jm-demail .text-red-500 { color: #ef4444; }
body.jm-dash .jm-demail .text-amber-500 { color: #f59e0b; }
body.jm-dash .jm-demail .text-yellow-500 { color: #eab308; }
body.jm-dash .jm-demail .text-blue-500 { color: #3b82f6; }
body.jm-dash .jm-demail .text-indigo-500 { color: #6366f1; }
body.jm-dash .jm-demail .text-gray-500 { color: #6b7280; }

/* ---------- nested empty state ----------
   .jm-empty draws its own dashed frame, which double-frames when the
   empty state lives inside a .jm-dcard (#tr-empty) or inside the email
   logs modal (#email-logs-empty). */
body.jm-dash .jm-empty--bare { background: transparent; border: 0; }

/* ---------- clickable card (Legal Pages tiles) ---------- */
body.jm-dash .jm-dcard--link { transition: border-color .2s, box-shadow .2s, transform .2s; }
body.jm-dash .jm-dcard--link:hover { border-color: var(--accent); box-shadow: var(--shadow); }
body.jm-dash .jm-dgo { background: rgba(249, 161, 27, .12); color: var(--accent-ink); }
body.jm-dash .jm-dcard--link:hover .jm-dgo { background: var(--grad); color: var(--btn-text); }

/* ---------- boxed filter control (Translations "overridden only") ---------- */
body.jm-dash .jm-dfilter { background: var(--card); border: 1px solid var(--border); }
body.jm-dash .jm-dfilter:hover { border-color: var(--border2); }

/* ---------- legacy toggle button from dashboard.css ----------
   .settings-toggle-on/-off are hard-coded #6366f1 / #d1d5db there and
   that file is shared, so the dashboard palette is re-applied here. */
body.jm-dash .settings-toggle-on { background: var(--accent); }
body.jm-dash .settings-toggle-off { background: var(--card2); border: 1px solid var(--border); }
body.jm-dash .settings-toggle-thumb { background: var(--btn-text); }
body.jm-dash .settings-toggle-off .settings-toggle-thumb { background: var(--faint); }

/* ---------- colour swatch inputs (email template) ---------- */
body.jm-dash .et-color-swatch { border: 1px solid var(--border); border-radius: 8px; background: var(--bg2); }

/* ---------- jm-dcard-head / -title / -sub modifiers ----------
   A bare Tailwind utility (items-stretch, mb-4, text-lg, …) is (0,1,0)
   and loses to `body.jm-dash .jm-dcard-head` (0,2,0), so the variants
   this page needs are real modifiers. */
/* payment + storage card heads stack a mode description under the row */
body.jm-dash .jm-dcard-head--stack { flex-direction: column; align-items: stretch; gap: 0; }
/* redis card head: icon block + status pill, top-aligned */
body.jm-dash .jm-dcard-head--top { align-items: flex-start; }
/* section title that carries its own bottom margin (cards without a head) */
body.jm-dash .jm-dcard-title--gap { margin-bottom: 14px; }
body.jm-dash .jm-dcard-title--md { font-size: 1rem; }
body.jm-dash .jm-dcard-title--lg { font-size: 1.125rem; letter-spacing: -.01em; }
body.jm-dash .jm-dcard-sub--lg { font-size: .875rem; margin-top: 4px; }
/* compact icon chip for the narrow email-template side panels */
body.jm-dash .jm-dcard-icon--sm { width: 28px; height: 28px; border-radius: 8px; }
body.jm-dash .jm-dcard-icon--sm svg { width: 16px; height: 16px; }

/* ---------- settings-rest ---------- */
/* Centred single-panel form page (forced password change).
   Pages: dashboard/reset-password.html */
body.jm-dash .jm-dauth-head {
    text-align: center;
    padding: 22px 24px;
    border-bottom: 1px solid var(--border);
    background: var(--card);
}
body.jm-dash .jm-dauth-mark {
    display: grid;
    place-items: center;
    width: 56px;
    height: 56px;
    margin: 0 auto 14px;
    border-radius: 16px;
    background: var(--grad);
    color: var(--btn-text);
}
body.jm-dash .jm-dauth-mark svg { width: 26px; height: 26px; }

/* Hairline rule inside a padded card (replaces <hr class="border-gray-100">).
   Pages: dashboard/settings/earn-money.html, settings/pricing.html */
body.jm-dash hr.jm-dhr {
    border: 0;
    border-top: 1px solid var(--border);
    margin: 22px 0;
}
/* Top hairline on a footer/action row inside a padded card. */
body.jm-dash .jm-dhr-top { border-top: 1px solid var(--border); }

/* Framed live-preview box + its caption and "nothing to show" filler.
   The previewed widget keeps its own literal brand colours (.jm-keep);
   only the frame around it is themed.
   Pages: dashboard/settings/announcement.html */
body.jm-dash .jm-dpreview {
    border: 1px solid var(--border);
    border-radius: var(--r-sm);
    overflow: hidden;
}
body.jm-dash .jm-dpreview-label {
    font-size: .72rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .08em;
    color: var(--muted);
    margin: 0;
}
body.jm-dash .jm-dpreview-empty {
    background: var(--card);
    color: var(--faint);
    font-size: .88rem;
    text-align: center;
    padding: 12px 16px;
}

/* Segmented two-state switch driven by aria-pressed (announcement-settings.js
   sets aria-pressed on the active button).
   Pages: dashboard/settings/announcement.html */
body.jm-dash .jm-dseg {
    display: inline-flex;
    gap: 2px;
    padding: 3px;
    border: 1px solid var(--border);
    border-radius: 10px;
    background: var(--card);
}
body.jm-dash .jm-dseg button {
    border: 0;
    background: none;
    cursor: pointer;
    padding: 4px 12px;
    border-radius: 7px;
    font-size: .76rem;
    font-weight: 700;
    color: var(--muted);
    transition: color .2s, background .2s;
}
body.jm-dash .jm-dseg button:hover { color: var(--text); }
body.jm-dash .jm-dseg button[aria-pressed="true"] {
    background: var(--bg2);
    color: var(--accent-ink);
    box-shadow: var(--shadow);
}

/* ------------------------------------------------------------
   dashboard/marketing/recording-invites/detail.html
   ------------------------------------------------------------ */

/* Warning tone for .jm-chip — site.css ships muted/cyan/success/danger
   but no warn, and the SUBMITTED / "reopen" states need it. */
body.jm-dash .jm-chip--warn {
    color: var(--warn);
    background: var(--warn-soft);
    border-color: var(--warn-border);
}

/* Tiny status dot that inherits the chip's own tone, plus explicit tones
   for the change-status menu items. (site.css .jm-chip-dot is fixed accent.) */
body.jm-dash .jm-dot {
    width: 7px;
    height: 7px;
    border-radius: 50%;
    flex: none;
    background: currentColor;
}
body.jm-dash .jm-dot--accent  { background: var(--accent); }
body.jm-dash .jm-dot--success { background: var(--success); }
body.jm-dash .jm-dot--danger  { background: var(--danger); }
body.jm-dash .jm-dot--warn    { background: var(--warn); }
body.jm-dash .jm-dot--pulse   { animation: jm-dot-pulse 1.8s ease-in-out infinite; }
@keyframes jm-dot-pulse { 0%, 100% { opacity: 1; } 50% { opacity: .35; } }

/* Label / value pair used by the meta strips and <dl> blocks. */
body.jm-dash .jm-dkey {
    font-size: .64rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .09em;
    color: var(--faint);
    margin: 0 0 2px;
}
body.jm-dash .jm-dval {
    font-size: .88rem;
    font-weight: 600;
    color: var(--text);
    margin: 0;
}
body.jm-dash .jm-dok { color: var(--success); }

/* Video player surround — always dark so letterboxing reads as the player,
   in both themes. */
body.jm-dash .jm-dvideo {
    background: #000;
    border: 1px solid var(--border);
    border-radius: var(--r);
    overflow: hidden;
}
body.jm-dash .jm-dvideo-empty { color: var(--muted); }

/* Dropdown menu panel + its items (the change-status menu). JS toggles
   `hidden` on the panel, so no display rule here. */
body.jm-dash .jm-dmenu {
    background: var(--bg2);
    border: 1px solid var(--border);
    border-radius: 14px;
    box-shadow: var(--shadow);
    padding: 6px;
}
body.jm-dash .jm-dmenu-item {
    display: flex;
    align-items: center;
    gap: 9px;
    width: 100%;
    padding: 9px 12px;
    border: 0;
    border-radius: 10px;
    background: none;
    color: var(--text);
    font-size: .88rem;
    text-align: start;
    cursor: pointer;
    transition: background .15s, color .15s;
}
body.jm-dash .jm-dmenu-item:hover { background: var(--card); color: var(--accent-ink); }

/* Quiet inset note block (payment notes, coupon issued). */
body.jm-dash .jm-dnote {
    padding: 12px 14px;
    border: 1px solid var(--border);
    border-radius: var(--r-sm);
    background: var(--card);
    color: var(--muted);
    margin: 0;
}
body.jm-dash .jm-dnote--cyan {
    background: var(--cyan-soft);
    border-color: var(--cyan-border);
    color: var(--cyan);
}
body.jm-dash .jm-dnote--cyan .jm-dkey { color: inherit; opacity: .85; }

/* Monospace read-only blob (raw user agent). */
body.jm-dash .jm-dcode {
    font-family: var(--mono);
    direction: ltr;
    font-size: .7rem;
    color: var(--muted);
    background: var(--card);
    border-radius: var(--r-sm);
    padding: 8px 10px;
    margin: 0;
}

/* Static currency prefix inside a .jm-input-wrap (the <span> sits where the
   wrap's icon normally would). */
body.jm-dash .jm-dprefix {
    position: absolute;
    top: 50%;
    inset-inline-start: 13px;
    transform: translateY(-50%);
    color: var(--faint);
    pointer-events: none;
}

/* Size steps for .jm-dval — Tailwind's text-lg/text-xl cannot win against
   `body.jm-dash .jm-dval`, so the emphasis lives on the component. */
body.jm-dash .jm-dval--lg { font-size: 1.1rem; font-weight: 700; }
body.jm-dash .jm-dval--xl {
    font-size: 1.85rem;
    font-weight: 800;
    letter-spacing: -.02em;
    line-height: 1.05;
}

/* The forced-password-change panel title is smaller than a page <h1>. */
body.jm-dash .jm-dauth-head .jm-dhead-title { font-size: 1.15rem; }

/* ---------- followups ---------- */
/* ---------- copy-to-clipboard icon button ----------
   Sits next to a name / e-mail in a table cell or in the modal
   header. JS (.copy-btn handler) swaps the svg path and flips
   .jm-dcopied on for 1.5s as the "copied!" confirmation. */
body.jm-dash .jm-dcopy {
    flex: none;
    display: inline-grid;
    place-items: center;
    padding: 2px;
    border: 0;
    border-radius: 6px;
    background: none;
    color: var(--faint);
    cursor: pointer;
    line-height: 0;
    transition: color .18s;
}
body.jm-dash .jm-dcopy:hover { color: var(--accent-ink); }
body.jm-dash .jm-dcopy svg { width: 14px; height: 14px; }
body.jm-dash .jm-dcopied,
body.jm-dash .jm-dcopy.jm-dcopied:hover { color: var(--success); }

/* ---------- boxed radio / checkbox picker ----------
   Replaces the `has-[:checked]:border-indigo-500` label tiles of
   the "Target type" and "Contact methods" pickers. The native
   control stays in the DOM (it may be .sr-only) so :has() drives
   the selected state. */
body.jm-dash .jm-dpick {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 12px;
    border: 1px solid var(--border);
    border-radius: var(--r-sm);
    background: var(--card);
    color: var(--text);
    font-size: .86rem;
    font-weight: 600;
    cursor: pointer;
    transition: border-color .18s, background .18s, color .18s;
}
body.jm-dash .jm-dpick:hover { border-color: var(--border2); }
body.jm-dash .jm-dpick input { accent-color: var(--accent); flex: none; }
body.jm-dash .jm-dpick:has(:checked) {
    border-color: var(--accent);
    background: rgba(249, 161, 27, .1);
    color: var(--accent-ink);
}
body.jm-dash .jm-dpick:has(:focus-visible) {
    border-color: var(--accent);
    box-shadow: 0 0 0 4px rgba(249, 161, 27, .18);
}
/* stacked icon-over-label variant (target type) */
body.jm-dash .jm-dpick--tile {
    flex-direction: column;
    gap: 6px;
    padding: 14px 10px;
    text-align: center;
}
body.jm-dash .jm-dpick--tile svg { width: 22px; height: 22px; color: var(--muted); transition: color .18s; }
body.jm-dash .jm-dpick--tile:has(:checked) svg { color: var(--accent-ink); }
/* dense variant used for the per-reply contact-method row */
body.jm-dash .jm-dpick--xs {
    gap: 6px;
    padding: 5px 9px;
    border-radius: 9px;
    font-size: .74rem;
}
body.jm-dash .jm-dpick--xs input { width: 13px; height: 13px; }

/* ---------- follow-up thread card ----------
   One conversation: tinted head (status/target/product chips +
   timestamp), body (agent + notes), replies, then either a
   closure banner or the reply/close action foot. */
body.jm-dash .jm-dthreadcard {
    background: var(--bg2);
    border: 1px solid var(--border);
    border-radius: var(--r-sm);
    overflow: hidden;
    margin-bottom: 14px;
}
body.jm-dash .jm-dthreadcard-head {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    padding: 10px 14px;
    background: var(--card);
    border-bottom: 1px solid var(--border);
}
body.jm-dash .jm-dthreadcard-body { padding: 12px 14px; }
body.jm-dash .jm-dthreadcard-foot {
    padding: 12px 14px;
    background: var(--card);
    border-top: 1px solid var(--border);
}
/* hairline above the "next follow-up" line inside a thread body */
body.jm-dash .jm-dthreadcard-note {
    margin-top: 8px;
    padding-top: 8px;
    border-top: 1px solid var(--border);
}
/* a reply, indented from the reading-start edge of the thread */
body.jm-dash .jm-dreply {
    padding: 12px 14px;
    margin-inline-start: 24px;
    border-inline-start: 2px solid var(--border2);
}
body.jm-dash .jm-dreply + .jm-dreply { border-top: 1px solid var(--border); }
body.jm-dash .jm-dreplies { border-top: 1px solid var(--border); }

/* ---------- closure banner (a CLOSED thread) ---------- */
body.jm-dash .jm-dclosure {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 10px 14px;
    border-top: 1px solid var(--border);
    font-weight: 600;
    font-size: .88rem;
}
body.jm-dash .jm-dclosure--success { background: var(--success-soft); color: var(--success); }
body.jm-dash .jm-dclosure--danger { background: var(--danger-soft); color: var(--danger); }

/* ---------- misc text tones ---------- */
/* a scheduled (not yet reached) next-follow-up date */
body.jm-dash .jm-dwarn { color: var(--warn); font-weight: 600; }
/* "no notes were recorded" placeholder */
body.jm-dash .jm-dnone { color: var(--faint); font-style: italic; }

/* ---------- subtle inner panel ----------
   A .jm-dcard inside a .jm-modal-panel is invisible (both are
   --bg2); this is the one-step-in surface for the modal's user
   summary strip. */
body.jm-dash .jm-dsubtle {
    background: var(--card);
    border: 1px solid var(--border);
    border-radius: var(--r-sm);
    padding: 14px 16px;
}

/* ---------- compact textarea ----------
   .jm-textarea is min-height 120px, far too tall for the 2-row
   inline reply box. */
body.jm-dash .jm-dtextarea--sm { min-height: 64px; padding: 9px 12px; font-size: .88rem; }

/* ---------- sticky modal head ----------
   The follow-up modal scrolls a long thread list; its title row
   must stay put. The negative offsets cancel .jm-modal-panel's
   28px padding so the sticky edge sits flush with the panel. */
body.jm-dash .jm-dmodal-head--sticky {
    position: sticky;
    top: -28px;
    z-index: 2;
    margin: -28px 0 16px;
    padding: 28px 0 14px;
    background: var(--bg2);
    border-bottom: 1px solid var(--border);
}

/* ---------- invoices ---------- */
/* ---------- table alignment utilities ----------
   `.jm-table th/td { text-align: start }` in site.css is (0,1,1) and
   therefore outranks Tailwind's single-class `.text-end` / `.text-center`.
   Restore those two utilities inside dashboard tables so money columns can
   be right-aligned (logical `end`, so it mirrors correctly in RTL).
   Pages: sales/invoices/view.html (price columns), sales/invoices/index.html
   (the centred action column). */
body.jm-dash .jm-table th.text-end,
body.jm-dash .jm-table td.text-end { text-align: end; }
body.jm-dash .jm-table th.text-center,
body.jm-dash .jm-table td.text-center { text-align: center; }

/* ---------- KPI card with stacked content ----------
   `.jm-dstat` centres its two children; the "Status / dates" card holds a
   three-line list that must hang off the top of the icon instead.
   Pages: sales/invoices/view.html */
body.jm-dash .jm-dstat--top { align-items: flex-start; }

/* ---------- invoice number in the page title ----------
   Accent-coloured span inside `.jm-dhead-title`.
   Pages: sales/invoices/view.html */
body.jm-dash .jm-dinv-no { color: var(--accent-ink); }

/* ---------- extra-small chip ----------
   dashboard-shell.css stops at `.jm-chip--sm` (.74rem). The activity log
   packs a role tag under a two-line name cell and needs one size smaller.
   Pages: sales/invoices/view.html */
body.jm-dash .jm-chip--xs { font-size: .68rem; font-weight: 600; padding: 1px 7px; gap: 4px; }
body.jm-dash .jm-chip--xs svg { width: 10px; height: 10px; }

/* ---------- pill nested inside a chip ----------
   The "page view" chip carries the dwell time as a second, tighter pill.
   It tints itself from the parent chip's own colour, so it works inside any
   `.jm-chip--*` variant and in both themes.
   Pages: sales/invoices/view.html */
body.jm-dash .jm-dsubpill {
    display: inline-block;
    padding: 0 5px;
    border-radius: 6px;
    font-size: 10px;
    font-weight: 700;
    color: inherit;
    background: color-mix(in srgb, currentColor 16%, transparent);
}

/* ---------- read-only URL field with a leading icon ----------
   The payment link box: a bordered shell holding a borderless, selectable
   input so the admin can still copy by hand.
   Pages: sales/invoices/view.html */
body.jm-dash .jm-durl {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 11px 14px;
    background: var(--card);
    border: 1px solid var(--border);
    border-radius: var(--r-sm);
    color: var(--faint);
}
body.jm-dash .jm-durl-input {
    flex: 1;
    min-width: 0;
    border: 0;
    padding: 0;
    background: transparent;
    color: var(--text);
    font-size: .88rem;
}
body.jm-dash .jm-durl-input:focus { outline: none; }

/* ---------- "copied" state of the copy-link button ----------
   Replaces the old from-/to- gradient class swap done by the inline script
   in view.html: the script toggles this one class instead.
   Three classes deep so it outranks `.jm-btn-p`'s gradient. */
body.jm-dash .jm-btn.jm-dcopy-ok {
    background: var(--success-soft);
    border-color: var(--success-border);
    color: var(--success);
    box-shadow: none;
}

/* ---------- QR frame ----------
   A QR image must sit on a light background to stay scannable, in dark mode
   too. `color-scheme: light` forces the `Canvas` system colour to white
   without hardcoding a hex value.
   Pages: sales/invoices/view.html */
body.jm-dash .jm-dqr {
    color-scheme: light;
    background: Canvas;
    border: 1px solid var(--border);
    border-radius: var(--r);
}

/* ---------- table summary footer ----------
   `.jm-table` styles thead/tbody only; the invoice totals live in a <tfoot>.
   Pages: sales/invoices/view.html */
body.jm-dash .jm-dtfoot { border-top: 2px solid var(--border); }
body.jm-dash .jm-dtfoot td { background: var(--card); border-bottom: 0; }
body.jm-dash .jm-dtfoot tr:hover td { background: var(--card); }

/* ============================================================
   Print — an invoice is a document people put on paper.
   ------------------------------------------------------------
   The canonical printed artefact is the server-rendered PDF behind the
   "Download PDF" button; nothing in the repo ships an @media print block and
   view.html carried no `print:` utilities. Printing the browser page was
   therefore unusable in dark mode (light text on white paper). These rules
   drop the dashboard chrome and force a paper-safe palette using the CSS
   system colours (`Canvas` / `CanvasText` / `GrayText`) under
   `color-scheme: light`, so no hex value is hardcoded and the theme tokens
   are left untouched on screen.
   ============================================================ */
@media print {
    /* Chrome and interactive-only blocks never reach the paper. */
    body.jm-dash .jm-dnoprint { display: none !important; }

    body.jm-dash {
        color-scheme: light;
        background: Canvas;
        color: CanvasText;
    }
    body.jm-dash .jm-dstat,
    body.jm-dash .jm-dcard,
    body.jm-dash .jm-dtfoot td,
    body.jm-dash .jm-table th {
        background: Canvas;
        color: CanvasText;
        box-shadow: none;
    }
    body.jm-dash .jm-dstat::before { display: none; }
    body.jm-dash .jm-dstat,
    body.jm-dash .jm-dcard { break-inside: avoid; border-color: GrayText; }
    body.jm-dash .jm-dcard-title,
    body.jm-dash .jm-dhead-title,
    body.jm-dash .jm-dstat-value,
    body.jm-dash .jm-tcell-title { color: CanvasText; }
    body.jm-dash .jm-muted,
    body.jm-dash .jm-faint,
    body.jm-dash .jm-dstat-label,
    body.jm-dash .jm-table th,
    body.jm-dash .jm-tcell-sub { color: GrayText; }
    body.jm-dash .jm-table td,
    body.jm-dash .jm-table th { border-color: GrayText; }
    /* Chips keep their outline but lose the tinted fill, which print
       colour-adjustment drops anyway. */
    body.jm-dash .jm-chip { background: transparent; color: CanvasText; border-color: GrayText; }
    body.jm-dash .jm-ddot { border: 1px solid CanvasText; background: transparent; }
    /* The md:/lg: money columns are hidden by Tailwind's screen-width media
       queries; print media has no width class, so they render — that is the
       wanted behaviour for a paper invoice. */
}

/* ---------- js-editors ---------- */
/* ---------- DUPLICATE colour utilities (see css-additions-admin-people.css
     / css-additions-student.css / css-additions-admin-marketing.css) ---------- */
body.jm-dash .jm-daccent { color: var(--accent-ink); }
body.jm-dash .jm-dtxt--success { color: var(--success); }
body.jm-dash .jm-dtxt--danger { color: var(--danger); }
body.jm-dash .jm-dtxt--warn { color: var(--warn); }
body.jm-dash .jm-icon-btn--danger { color: var(--faint); }
body.jm-dash .jm-icon-btn--danger:hover { color: var(--danger); border-color: var(--danger-border); }
body.jm-dash .jm-icon-btn--xs { width: 32px; height: 32px; border-radius: 9px; }
body.jm-dash .jm-icon-btn--xs svg { width: 15px; height: 15px; }

/* ============================================================
   curriculum-builder.js
   ============================================================ */

/* Section panel. input.css paints `[dir="rtl"] .section-card` with a 4px
   #111827 rail (specificity 0,2,0); this selector is 0,2,1 so it wins in
   both directions, and border-inline-start puts the rail on the right
   edge in Arabic without a mirror rule. .jm-dcard owns the surface. */
body.jm-dash .jm-dcb-section {
    border-width: 1px;
    border-style: solid;
    border-color: var(--border);
    border-inline-start: 4px solid var(--accent);
    box-shadow: none;
    /* .jm-dcard clips its children; the lecture-type dropdown is absolutely
       positioned near the card's bottom edge and must escape it. */
    overflow: visible;
}
body.jm-dash .jm-dcb-section > .jm-dcard-head { gap: 12px; }

/* "+ Curriculum item" — a dashed ghost button that fills on hover. */
body.jm-dash .jm-dcb-add {
    border-style: dashed;
    border-color: var(--border2);
    color: var(--muted);
    background: transparent;
}
body.jm-dash .jm-dcb-add:hover {
    border-style: solid;
    border-color: var(--accent);
    background: rgba(249, 161, 27, .1);
    color: var(--accent-ink);
}

/* The lecture-type dropdown hanging off that button. .jm-dmenu is shared,
   but two of its declarations pin width: 12rem — this menu is narrower. */
body.jm-dash .jm-dmenu.jm-dcb-menu { width: 11rem; }
body.jm-dash .jm-dmenu-item.jm-dcb-menu-accent { color: var(--accent-ink); }
body.jm-dash .jm-dcb-menu .jm-dmenu-item:hover { background: var(--card); color: var(--accent-ink); }

/* Lecture row shell (was a bare bg-white/border-gray-200 box). */
body.jm-dash .jm-dcb-lecture {
    border: 1px solid var(--border);
    border-radius: var(--r-sm);
    background: var(--bg2);
    transition: border-color .2s, box-shadow .2s;
}
body.jm-dash .jm-dcb-lecture:hover { border-color: var(--border2); box-shadow: var(--shadow); }

/* The inline editor drawer that .lecture-dropdown reveals. */
body.jm-dash .jm-dcb-drawer {
    background: var(--card);
    border-top: 1px solid var(--border);
}

/* "Add lecture" inline form — an accent-tinted strip under the section. */
body.jm-dash .jm-dcb-addform {
    background: rgba(249, 161, 27, .08);
    border-top: 1px solid var(--border2);
    border-end-start-radius: var(--r-sm);
    border-end-end-radius: var(--r-sm);
}
/* The 80-char counter sits inside the input; keep it off the text. */
body.jm-dash .jm-dcb-addform .jm-input { padding-inline-end: 42px; }

/* Hover-to-reveal "add a section here" rail between sections. */
body.jm-dash .jm-dcb-insert { background: rgba(249, 161, 27, .1); }

/* Legacy hooks the script still emits. */
body.jm-dash .inline-editable:focus { outline-color: var(--accent); }
body.jm-dash .sortable-ghost { background: var(--card2); }
body.jm-dash .char-counter-ok { color: var(--success); }
body.jm-dash .char-counter-warn { color: var(--warn); }
body.jm-dash .char-counter-danger { color: var(--danger); }
body.jm-dash .lecture-inline-thumb { background: var(--thumb-bg); border: 1px solid var(--border); }
body.jm-dash .lecture-inline-duration {
    color: var(--muted);
    background: var(--card2);
    font-family: var(--mono);
}

/* ============================================================
   lecture-editor.js
   ============================================================ */

/* The Content / Attachments rail is now .jm-tabs; .inline-tab-btn only has
   to stop the legacy pill padding from coming back. */
body.jm-dash .jm-tabs .inline-tab-btn { padding: 10px 14px; }

/* Upload drop zones (video, slide, attachment) — .drop-zone is the hook
   createDropZone() toggles `.drag-over` on. */
body.jm-dash .drop-zone,
body.jm-dash .batch-upload-drop-zone {
    border: 2px dashed var(--border2);
    border-radius: var(--r-sm);
    background: var(--card);
    color: var(--muted);
    transition: border-color .2s, background .2s;
}
body.jm-dash .drop-zone:hover,
body.jm-dash .batch-upload-drop-zone:hover {
    border-color: var(--accent);
    background: rgba(249, 161, 27, .08);
}
body.jm-dash .drop-zone.drag-over,
body.jm-dash .batch-upload-drop-zone.drag-over {
    border-color: var(--accent);
    background: rgba(249, 161, 27, .14);
}

/* .upload-progress / .upload-progress-bar are the ids the upload callbacks
   write `style.width` to, so they keep their names and borrow .jm-progress. */
body.jm-dash .jm-progress.upload-progress { height: 6px; background: var(--card2); }
body.jm-dash .jm-progress > .upload-progress-bar { background: var(--grad); transition: width .3s; }

/* A file / attachment line: name on the start edge, actions on the end. */
body.jm-dash .jm-dfilerow {
    gap: 12px;
    padding: 10px 12px;
    background: var(--card);
    border: 1px solid var(--border);
    border-radius: var(--r-sm);
}
body.jm-dash .jm-dfilerow + .jm-dfilerow { margin-top: 8px; }

/* The uploaded-video summary card (markup unchanged, palette re-pointed). */
body.jm-dash .video-info-card {
    background: var(--card);
    border: 1px solid var(--border);
    border-radius: var(--r-sm);
}
body.jm-dash .video-info-card .video-thumb { background: var(--thumb-bg); border-color: var(--border); }
body.jm-dash .video-info-card .video-filename { color: var(--text); }
body.jm-dash .video-info-card .video-duration { color: var(--muted); font-family: var(--mono); }
body.jm-dash .video-info-card .video-edit-link { color: var(--accent-ink); cursor: pointer; }
body.jm-dash .video-info-card .video-edit-link:hover { color: var(--accent); }
body.jm-dash .video-info-card .toggle-label { color: var(--muted); }
body.jm-dash .video-info-card .toggle-track { background: var(--card2); border: 1px solid var(--border); }
body.jm-dash .video-info-card input:checked + .toggle-track { background: var(--grad); border-color: transparent; }

/* Quiz question option row — flex layout stays in input.css. */
body.jm-dash .quiz-option-row { gap: 10px; }
body.jm-dash .quiz-option-row:hover { background: var(--card); border-radius: var(--r-sm); }
body.jm-dash .quiz-option-row .jm-check { flex: none; align-items: center; white-space: nowrap; }
body.jm-dash .quiz-option-row .jm-check input { margin-top: 0; }

/* The add/edit question form: a .jm-dwell tinted with the accent so it
   reads as "being edited". */
body.jm-dash .jm-dwell.jm-dle-form {
    background: rgba(249, 161, 27, .08);
    border-color: var(--border2);
}

/* Slide preview dialog. .jm-modal-panel ships 28px of padding and its own
   scroll; this one is a full-bleed head + iframe. */
body.jm-dash .jm-dslidepanel {
    max-width: 64rem;
    padding: 0;
    overflow: hidden;
}
body.jm-dash .jm-dslidepanel > .jm-modal-head {
    margin: 0;
    padding: 14px 20px;
    justify-content: space-between;
    border-bottom: 1px solid var(--border);
}
body.jm-dash .jm-dslidepanel iframe { background: var(--bg2); }

/* ============================================================
   batch-video-upload.js
   ============================================================ */

body.jm-dash .batch-upload-overlay {
    background: rgba(3, 6, 15, .7);
    backdrop-filter: blur(4px);
    -webkit-backdrop-filter: blur(4px);
}
body.jm-dash .batch-upload-modal {
    background: var(--bg2);
    color: var(--text);
    border: 1px solid var(--border);
    border-radius: var(--r);
    box-shadow: var(--shadow);
}
body.jm-dash .batch-upload-file-item {
    background: var(--card);
    border: 1px solid var(--border);
    border-radius: var(--r-sm);
}

/* Per-file progress: .jm-progress plus a span fill, keeping the two class
   names the row updater queries. */
body.jm-dash .jm-progress.batch-progress-bar { height: 5px; background: var(--card2); }
body.jm-dash .jm-progress > .batch-progress-fill {
    display: block;
    height: 100%;
    border-radius: 999px;
    background: var(--grad);
    transition: width .3s ease;
}

/* Per-file status pill. The chip is icon-only, so trim the pill padding and
   drop the legacy .batch-status-* colours in favour of the chip modifier. */
body.jm-dash .jm-chip.batch-status-icon { padding: 4px; gap: 0; }
body.jm-dash .jm-chip.batch-status-icon svg { width: 16px; height: 16px; }
body.jm-dash .jm-chip.batch-status-queued { color: var(--muted); }
body.jm-dash .jm-chip.batch-status-uploading { color: var(--accent-ink); }
body.jm-dash .jm-chip.batch-status-processing { color: var(--warn); }
body.jm-dash .jm-chip.batch-status-success { color: var(--success); }
body.jm-dash .jm-chip.batch-status-error { color: var(--danger); }

/* The per-row lecture-title field: dense, and read-only while its file is
   in flight (`is-locked` replaces the old bg-gray-50/border-transparent
   class juggling). */
body.jm-dash .jm-dbv-title { padding: 6px 10px; font-size: .88rem; }
body.jm-dash .jm-input.is-locked {
    background: var(--card2);
    border-color: transparent;
    color: var(--muted);
}

body.jm-dash .batch-processing-label { color: var(--accent-ink); }

/* ============================================================
   email-template-editor.js
   ------------------------------------------------------------
   ONLY the editor chrome. Everything inside #et-preview-frame /
   #et-tpl-preview-frame is a rendering of the real email and keeps
   its own literal colours — do not add rules for it here.
   ============================================================ */

/* Global Style / Per-Template sub-tabs. The script now toggles `is-active`
   instead of bg-indigo-50 + text-indigo-700.
   NOTE for the settings/index.html rewrite: #et-subtab-global must ship
   `is-active` in the markup, and neither button should keep a palette class. */
body.jm-dash .et-subtab {
    border: 1px solid transparent;
    background: transparent;
    color: var(--muted);
    cursor: pointer;
}
body.jm-dash .et-subtab:hover { color: var(--text); }
body.jm-dash .et-subtab.is-active {
    background: rgba(249, 161, 27, .12);
    border-color: var(--border2);
    color: var(--accent-ink);
}

/* Desktop / Mobile preview-size switch (both the global and the
   per-template copy). Same note: the Desktop button starts `is-active`. */
body.jm-dash .et-preview-device,
body.jm-dash .et-preview-device-tpl {
    background: transparent;
    border: 0;
    color: var(--faint);
    cursor: pointer;
}
body.jm-dash .et-preview-device:hover,
body.jm-dash .et-preview-device-tpl:hover { color: var(--text); }
body.jm-dash .et-preview-device.is-active,
body.jm-dash .et-preview-device-tpl.is-active {
    background: var(--bg2);
    color: var(--text);
    box-shadow: var(--shadow);
}

/* Rich-text toolbar of the body editor (dashboard.css pins .active to
   #ffffff / #4338ca). */
body.jm-dash .et-toolbar .et-tool-btn { color: var(--muted); }
body.jm-dash .et-toolbar .et-tool-btn:hover { background: var(--card2); color: var(--text); }
body.jm-dash .et-toolbar .et-tool-btn.active {
    background: var(--card2);
    box-shadow: none;
    color: var(--accent-ink);
}
body.jm-dash .et-editor-area:empty::before { color: var(--faint); }
body.jm-dash .et-editor-area:focus { box-shadow: 0 0 0 4px rgba(249, 161, 27, .18); }

/* ---------- js-admin-tools ---------- */
/* ============================================================
   roadmap-builder.js — dashboard/roadmaps/builder.html
   ============================================================ */

/* The builder renders the same tree as roadmaps/preview.html, so it reuses
   .jm-droadmap-item and friends. A SECTION is the default gold tone; naming
   it explicitly keeps the JS symmetrical with the four leaf types. */
body.jm-dash .jm-droadmap-item--section { --tone: var(--accent); }

/* Leaf rows lift on hover the way every other list card does; sections are
   containers and stay put. */
body.jm-dash .jm-droadmap-item { transition: border-color .2s, box-shadow .2s; }
body.jm-dash .jm-droadmap-item:not(.jm-droadmap-item--section):hover {
    border-color: var(--border2);
    box-shadow: var(--shadow);
}

/* SortableJS `chosenClass` — the row under the pointer while dragging. */
body.jm-dash .jm-dchosen {
    border-color: var(--accent);
    box-shadow: 0 0 0 3px rgba(249, 161, 27, .22);
}

/* Double-clicking the page title swaps the <h1> for this input in place, so
   it has to keep the heading's size and sit on the same baseline. */
body.jm-dash .jm-dinline-title {
    background: transparent;
    border: 0;
    border-bottom: 2px solid var(--accent);
    outline: none;
    color: var(--text);
    font-family: inherit;
    letter-spacing: -.02em;
    padding: 0 0 2px;
}

/* Course / article picker rows inside the builder's modals. `--tone` feeds
   the leading .jm-droadmap-item-icon so the picker matches the tree colour
   of the item it is about to add. */
body.jm-dash .jm-dpickbtn {
    --tone: var(--accent);
    background: none;
    border: 0;
    border-radius: var(--r-sm);
    color: var(--text);
    cursor: pointer;
    font-family: inherit;
    transition: background .18s;
}
body.jm-dash .jm-dpickbtn:hover { background: var(--card); }
body.jm-dash .jm-dpickbtn--course  { --tone: var(--cyan); }
body.jm-dash .jm-dpickbtn--article { --tone: var(--success); }

/* ============================================================
   translations-admin.js — settings/index.html #panel-translations
   ============================================================ */

/* One row per message key. The stripe and the category chip both read
   --cat-tone, which .jm-dcat-1…-5 set; the script hashes the category name
   onto one of the five so related keys group visually. Five tokens, not
   nine hexes: every extra "hue" collapses onto the same gold in dark mode. */
body.jm-dash .jm-dtr-row { --cat-tone: var(--accent); transition: background .18s; }
body.jm-dash .jm-dtr-row:hover { background: var(--card); }
body.jm-dash .jm-dtr-stripe { width: 2px; background: var(--cat-tone); }

body.jm-dash .jm-dcat-1 { --cat-tone: var(--accent-ink); }
body.jm-dash .jm-dcat-2 { --cat-tone: var(--cyan); }
body.jm-dash .jm-dcat-3 { --cat-tone: var(--success); }
body.jm-dash .jm-dcat-4 { --cat-tone: var(--warn); }
body.jm-dash .jm-dcat-5 { --cat-tone: var(--muted); }

/* The category chip tints itself from the row's tone, so it needs no
   per-tone variant of its own. */
body.jm-dash .jm-dcat-chip {
    color: var(--cat-tone);
    background: color-mix(in srgb, var(--cat-tone) 12%, transparent);
    border-color: color-mix(in srgb, var(--cat-tone) 32%, transparent);
    font-family: inherit;
}

/* The edit textareas are .jm-textarea .jm-dtextarea--sm; both scripts render
   from the one --font-ui stack. */
body.jm-dash .tr-input { line-height: 1.6; }

/* ============================================================
   settings.js — settings/index.html
   ============================================================ */

/* The tab rail's active state. css-additions-settings-index.css styles the
   resting/hover state and keys "active" off the legacy Tailwind classes the
   script used to write; it now writes `is-active` instead. */
body.jm-dash .settings-tab.is-active {
    background: rgba(249, 161, 27, .12);
    color: var(--accent-ink);
}
body.jm-dash .settings-tab.is-active svg { color: var(--accent-ink); }
body.jm-dash .settings-tab-mobile.is-active {
    color: var(--accent-ink);
    border-bottom-color: var(--accent);
}

/* ============================================================
   course-stats-admin.js — dashboard/courses/view.html
   ============================================================ */

/* The star picker paints with `is-active` now (css-additions-admin-people.css
   still keys the same rule off .text-amber-400, which the script no longer
   writes — that rule is inert and can be dropped when the sheets are merged). */
body.jm-dash .jm-dstars .star-btn.is-active { color: var(--accent2); opacity: 1; }

/* Ditto the mandatory-reviewer-name flag: `is-invalid` is site.css's own
   input error state, so .jm-input.border-red-400 over there is now inert. */

/* ---------- js-tail ---------- */
/* ---------- notifications.js — bell dropdown + toasts ---------- */

/* Unread row in the bell sheet (was `bg-indigo-50/50`). */
body.jm-dash .notification-item.is-unread { background: rgba(249, 161, 27, .09); }

/* dashboard.css paints .notif-toast__icon a fixed mint; tone it by token. */
body.jm-dash .notif-toast__icon { background: var(--card); color: var(--muted); }
body.jm-dash .notif-toast__icon--accent { background: rgba(249, 161, 27, .14); color: var(--accent-ink); }
body.jm-dash .notif-toast__icon--success { background: var(--success-soft); color: var(--success); }
body.jm-dash .notif-toast__icon--danger { background: var(--danger-soft); color: var(--danger); }
body.jm-dash .notif-toast__icon--cyan { background: var(--cyan-soft); color: var(--cyan); }
body.jm-dash .notif-toast {
    background: var(--bg2);
    border: 1px solid var(--border);
    box-shadow: var(--shadow);
    color: var(--text);
}
body.jm-dash .notif-toast__title { color: var(--text); }
body.jm-dash .notif-toast__msg { color: var(--muted); }
body.jm-dash .notif-toast__close { color: var(--faint); }
body.jm-dash .notif-toast__close:hover { color: var(--text); background: var(--card); }

/* ---------- dashboard-reviews.js — edit-history rows ---------- */
body.jm-dash .jm-dhistrow {
    background: var(--card);
    border-radius: var(--r-sm);
    padding: 8px 12px;
    color: var(--muted);
}

/* ---------- redis-config.js — connection status pill ----------
   The pill in settings/index.html is `.jm-dpill` + `.jm-dpill-dot`; the script
   now only toggles a state class, so the tone lives here. These replace the
   `.jm-dpill.bg-emerald-50` / `.bg-rose-50` / `.bg-gray-100` bridge rules in
   css-additions-settings-index.css, which can be deleted. */
body.jm-dash .jm-dpill.is-success { background: var(--success-soft); border-color: var(--success-border); color: var(--success); }
body.jm-dash .jm-dpill.is-danger  { background: var(--danger-soft);  border-color: var(--danger-border);  color: var(--danger); }
body.jm-dash .jm-dpill.is-muted   { background: var(--card);         border-color: var(--border);         color: var(--muted); }
/* Dashboard-wide mandatory-outage banner (fragments/health-alert.html). The base .jm-alert is already
   a flex row; this just keeps the action button vertically centred and the text from crowding it. */
body.jm-dash .jm-dhealth-alert { align-items: center; }
body.jm-dash .jm-dhealth-alert p { margin: 0; font-size: .88rem; }
body.jm-dash .jm-dhealth-alert .jm-btn { flex: none; }

/* is-warn = DEGRADED and is-checking = probe in flight, both added for monitoring-health.js */
body.jm-dash .jm-dpill.is-warn    { background: var(--warn-soft);    border-color: var(--warn-border);    color: var(--warn); }
body.jm-dash .jm-dpill.is-checking { background: var(--cyan-soft);   border-color: var(--cyan-border);    color: var(--cyan); }
body.jm-dash .jm-dpill.is-checking .jm-dpill-dot { animation: jm-dpill-blink 1s ease-in-out infinite; }
@keyframes jm-dpill-blink { 0%, 100% { opacity: 1; } 50% { opacity: .25; } }
html.no-animations body.jm-dash .jm-dpill.is-checking .jm-dpill-dot { animation: none; }
@media (prefers-reduced-motion: reduce) { body.jm-dash .jm-dpill.is-checking .jm-dpill-dot { animation: none; } }
body.jm-dash .jm-dpill .jm-dpill-dot { background: currentColor; }

/* ---------- coupon-create.js — user picker ---------- */

/* Row inside #user-search-results (a .jm-dsearch-pop). */
body.jm-dash .user-search-item { color: var(--text); }
body.jm-dash .user-search-item + .user-search-item { border-top: 1px solid var(--border); }
body.jm-dash .user-search-item:hover { background: var(--card); }

/* Dismiss "x" inside a .jm-chip — inherits the chip's own tone.
   Also used by any other script that puts a remove button in a chip. */
body.jm-dash .jm-chip .jm-dchip-x {
    display: inline-grid;
    place-items: center;
    background: none;
    border: 0;
    padding: 0;
    color: inherit;
    opacity: .65;
    cursor: pointer;
    transition: opacity .2s;
}
body.jm-dash .jm-chip .jm-dchip-x:hover { opacity: 1; }
body.jm-dash .jm-chip .jm-dchip-x svg { width: 14px; height: 14px; }

/* ---------- subscription-manage.js — bottom toast stack ----------
   student/subscriptions/index.html stacks these in #toast-container; the
   script only picks the tone. */
body.jm-dash .jm-dtoast {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 12px 20px;
    border-radius: 14px;
    border: 1px solid var(--border);
    background: var(--bg2);
    color: var(--text);
    box-shadow: var(--shadow);
    font-size: .88rem;
    font-weight: 600;
}
body.jm-dash .jm-dtoast--success { background: var(--success-soft); border-color: var(--success-border); color: var(--success); }
body.jm-dash .jm-dtoast--danger  { background: var(--danger-soft);  border-color: var(--danger-border);  color: var(--danger); }

/* ---------- marketing-campaign.js — user picker ---------- */

/* Same row as coupon-create's, inside #user-search-results (a .jm-dpopover). */
body.jm-dash .jm-dpopover .user-search-item:hover { background: var(--card); }

/* Explicit hook for the checked campaign-type card; .jm-dradio-card already
   reacts to :has(input:checked), this keeps the two in step. */
body.jm-dash .jm-dradio-card.is-active { border-color: var(--accent); background: rgba(249, 161, 27, .1); }

/* ---------- subscription-form.js — bundle picker + feature rows ----------
   Mirrors the .course-* rules the bundle-form rewrite already added; the
   bundle selector is a second copy of the same widget with its own classes. */
body.jm-dash .bundle-search-result { color: var(--text); border-bottom: 1px solid var(--border); }
body.jm-dash .bundle-search-result:last-child { border-bottom: 0; }
body.jm-dash .bundle-search-result:hover { background: var(--card); }
body.jm-dash .bundle-chip { background: var(--card); border: 1px solid var(--border); color: var(--text); }
body.jm-dash .bundle-chip-remove { color: var(--faint); }
body.jm-dash .bundle-chip-remove:hover { color: var(--danger); background: var(--danger-soft); }

/* The EN/AR feature rows are the multi-text widget with a second column. */
body.jm-dash .bilingual-feature-row input {
    background: var(--bg2);
    border: 1px solid var(--border);
    color: var(--text);
}
body.jm-dash .bilingual-feature-row input::placeholder { color: var(--faint); }
body.jm-dash .bilingual-feature-row input:focus {
    outline: none;
    border-color: var(--accent);
    box-shadow: 0 0 0 4px rgba(249, 161, 27, .18);
}
/* ==== END page components ==== */

/* ---------- link performance list (fragments/affiliate-link-stats.html) ---------- */
body.jm-dash .jm-dlinkstats { list-style: none; margin: 0; padding: 0; }
body.jm-dash .jm-dlinkstats > li { padding: 12px 24px; border-top: 1px solid var(--border); }
body.jm-dash .jm-dlinkstats > li:first-child { border-top: 0; }
body.jm-dash .jm-dlinkstats-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 7px;
    font-size: .85rem;
    color: var(--text);
}
body.jm-dash .jm-dlinkstats-count {
    flex: none;
    display: inline-flex;
    align-items: center;
    gap: 5px;
    font-size: .78rem;
    font-weight: 700;
    color: var(--muted);
}

/* ============================================================
   Native form controls
   ------------------------------------------------------------
   Most dashboard fields carry .jm-input / .jm-select / .jm-textarea,
   but bare controls (a range slider, a checkbox in a table row) still
   need to follow the theme — this is what the deleted bridge used to
   do for them.
   ============================================================ */
body.jm-dash input[type="checkbox"],
body.jm-dash input[type="radio"],
body.jm-dash input[type="range"],
body.jm-dash progress { accent-color: var(--accent); }
body.jm-dash input:not([class*="jm-"]):not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="file"]):not([type="hidden"]),
body.jm-dash select:not([class*="jm-"]),
body.jm-dash textarea:not([class*="jm-"]) {
    background-color: var(--bg2);
    border-color: var(--border);
    color: var(--text);
}
body.jm-dash input::placeholder,
body.jm-dash textarea::placeholder { color: var(--faint); }
body.jm-dash input:not([class*="jm-"]):focus,
body.jm-dash select:not([class*="jm-"]):focus,
body.jm-dash textarea:not([class*="jm-"]):focus { border-color: var(--accent); }

/* ============================================================
   Text-align utilities win
   ------------------------------------------------------------
   site.css sets `.jm-table th, .jm-table td { text-align: start }`
   at (0,1,1), which silently beats Tailwind's single-class
   `.text-end` / `.text-center`. Restore them for dashboards so a
   money column can right-align and an action column can centre.
   ============================================================ */
body.jm-dash .text-start { text-align: start; }
body.jm-dash .text-end { text-align: end; }
body.jm-dash .text-center { text-align: center; }

/* ============================================================
   Display utilities win
   ------------------------------------------------------------
   The component rules above set `display`, which outranks
   Tailwind's single-class utilities. Restore them here, last in
   the file, so `hidden` still hides a component AND a responsive
   `md:table-cell` / `sm:flex` still un-hides it at its breakpoint.
   Order matters: `hidden` first, then the breakpoint overrides.
   ============================================================ */
body.jm-dash .hidden { display: none; }

@media (min-width: 640px) { body.jm-dash .sm\:hidden { display: none; } }
@media (min-width: 640px) { body.jm-dash .sm\:block { display: block; } body.jm-dash .sm\:inline-block { display: inline-block; } body.jm-dash .sm\:flex { display: flex; } body.jm-dash .sm\:inline-flex { display: inline-flex; } body.jm-dash .sm\:grid { display: grid; } body.jm-dash .sm\:table-cell { display: table-cell; } body.jm-dash .sm\:table-row { display: table-row; } body.jm-dash .sm\:inline { display: inline; } body.jm-dash .sm\:contents { display: contents; } }
@media (min-width: 768px) { body.jm-dash .md\:hidden { display: none; } }
@media (min-width: 768px) { body.jm-dash .md\:block { display: block; } body.jm-dash .md\:inline-block { display: inline-block; } body.jm-dash .md\:flex { display: flex; } body.jm-dash .md\:inline-flex { display: inline-flex; } body.jm-dash .md\:grid { display: grid; } body.jm-dash .md\:table-cell { display: table-cell; } body.jm-dash .md\:table-row { display: table-row; } body.jm-dash .md\:inline { display: inline; } body.jm-dash .md\:contents { display: contents; } }
@media (min-width: 1024px) { body.jm-dash .lg\:hidden { display: none; } }
@media (min-width: 1024px) { body.jm-dash .lg\:block { display: block; } body.jm-dash .lg\:inline-block { display: inline-block; } body.jm-dash .lg\:flex { display: flex; } body.jm-dash .lg\:inline-flex { display: inline-flex; } body.jm-dash .lg\:grid { display: grid; } body.jm-dash .lg\:table-cell { display: table-cell; } body.jm-dash .lg\:table-row { display: table-row; } body.jm-dash .lg\:inline { display: inline; } body.jm-dash .lg\:contents { display: contents; } }
@media (min-width: 1280px) { body.jm-dash .xl\:hidden { display: none; } }
@media (min-width: 1280px) { body.jm-dash .xl\:block { display: block; } body.jm-dash .xl\:inline-block { display: inline-block; } body.jm-dash .xl\:flex { display: flex; } body.jm-dash .xl\:inline-flex { display: inline-flex; } body.jm-dash .xl\:grid { display: grid; } body.jm-dash .xl\:table-cell { display: table-cell; } body.jm-dash .xl\:table-row { display: table-row; } body.jm-dash .xl\:inline { display: inline; } body.jm-dash .xl\:contents { display: contents; } }

/* ============================================================
   Course trash (dashboard/courses/trash.html)
   Rows are not links, so no hover lift; they stack on mobile and
   the thumbnail is greyed out to read as "set aside".
   ============================================================ */
body.jm-dash .jm-drow--trashed { align-items: stretch; }
body.jm-dash .jm-drow--trashed:hover { transform: none; box-shadow: none; background: var(--bg2); }
body.jm-dash .jm-drow--trashed .jm-drow-thumb img { filter: grayscale(1); opacity: .7; }
body.jm-dash .jm-trash-note { color: var(--danger); }
@media (min-width: 640px) {
    body.jm-dash .jm-drow--trashed { align-items: center; }
}

/* ============================================================
   Category picker — fragments/category-picker.html + category-picker.js
   A <select data-category-picker> upgraded to chips + search + inline
   "new category". The native select stays in the DOM (hidden) and keeps
   the form value. Tokens only, logical properties for RTL.
   ============================================================ */
body.jm-dash .jm-dcat-native { display: none; }
body.jm-dash .jm-dcat { position: relative; }
body.jm-dash .jm-dcat-control {
    display: flex; flex-wrap: wrap; align-items: center; gap: 6px;
    min-height: 47px; padding: 6px 8px;
    background: var(--bg2); border: 1px solid var(--border); border-radius: var(--r-sm);
    cursor: text; transition: border-color .18s, box-shadow .18s;
}
body.jm-dash .jm-dcat-control:focus-within { border-color: var(--accent); box-shadow: 0 0 0 4px rgba(249, 161, 27, .18); }
body.jm-dash .jm-dcat.is-invalid .jm-dcat-control { border-color: var(--danger); box-shadow: 0 0 0 4px var(--danger-soft); }
body.jm-dash .jm-dcat-chips { display: contents; }
body.jm-dash .jm-dcat-chip {
    display: inline-flex; align-items: center; gap: 4px; max-width: 100%;
    padding-block: 3px; padding-inline: 10px 4px;
    font-size: .84rem; font-weight: 700; line-height: 1.5;
    color: var(--text); background: var(--card2); border: 1px solid var(--border); border-radius: 999px;
}
body.jm-dash .jm-dcat-chip > span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* The first chip is the course's main category — the one the public card shows. */
body.jm-dash .jm-dcat-chip:first-child { color: var(--accent-ink); background: var(--warn-soft); border-color: var(--warn-border); }
body.jm-dash .jm-dcat-chip-x {
    display: grid; place-items: center; flex: none; width: 22px; height: 22px;
    border: 0; border-radius: 50%; background: none; color: inherit; opacity: .65; cursor: pointer;
}
body.jm-dash .jm-dcat-chip-x:hover, body.jm-dash .jm-dcat-chip-x:focus-visible { opacity: 1; background: var(--danger-soft); color: var(--danger); }
body.jm-dash .jm-dcat-chip-x:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
body.jm-dash .jm-dcat-chip-x svg { width: 13px; height: 13px; }
body.jm-dash .jm-dcat-input {
    flex: 1 1 120px; min-width: 120px; padding: 6px;
    border: 0; outline: 0; background: none; color: var(--text); font: inherit; font-size: .95rem;
}
body.jm-dash .jm-dcat-input::placeholder { color: var(--faint); }

body.jm-dash .jm-dcat-pop {
    position: absolute; z-index: 40; inset-inline: 0; top: calc(100% + 6px);
    padding: 6px; background: var(--bg2); color: var(--text);
    border: 1px solid var(--border); border-radius: var(--r-sm); box-shadow: var(--shadow);
}
body.jm-dash .jm-dcat-pop[hidden], body.jm-dash .jm-dcat-pop [hidden] { display: none; }
body.jm-dash .jm-dcat-list { max-height: 232px; margin: 0; padding: 0; overflow-y: auto; list-style: none; }
body.jm-dash .jm-dcat-option {
    display: flex; align-items: center; gap: 10px; padding: 9px 12px;
    border-radius: 9px; font-size: .9rem; font-weight: 600; cursor: pointer;
}
body.jm-dash .jm-dcat-option.is-active { background: var(--card2); }
body.jm-dash .jm-dcat-option-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
body.jm-dash .jm-dcat-option-alt { margin-inline-start: auto; color: var(--faint); font-size: .82rem; font-weight: 400; white-space: nowrap; }
body.jm-dash .jm-dcat-option svg { flex: none; width: 16px; height: 16px; color: var(--accent-ink); visibility: hidden; }
body.jm-dash .jm-dcat-option-name + svg { margin-inline-start: auto; }
body.jm-dash .jm-dcat-option[aria-selected="true"] svg { visibility: visible; }
body.jm-dash .jm-dcat-empty { margin: 0; padding: 12px; color: var(--faint); font-size: .88rem; }
body.jm-dash .jm-dcat-add {
    display: flex; align-items: center; gap: 8px; width: 100%; margin-top: 6px; padding: 10px 12px;
    border: 0; border-top: 1px solid var(--border); border-radius: 0 0 9px 9px;
    background: none; color: var(--accent-ink); font: inherit; font-size: .88rem; font-weight: 700;
    text-align: start; cursor: pointer;
}
body.jm-dash .jm-dcat-add:hover, body.jm-dash .jm-dcat-add:focus-visible { background: var(--card); outline: none; }
body.jm-dash .jm-dcat-add svg { flex: none; width: 16px; height: 16px; }
body.jm-dash .jm-dcat-add span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
body.jm-dash .jm-dcat-quick { margin-top: 6px; padding: 12px 8px 6px; border-top: 1px solid var(--border); }
body.jm-dash .jm-dcat-quick-row { display: flex; flex-direction: column; gap: 5px; margin-bottom: 12px; }
body.jm-dash .jm-dcat-quick-row .jm-input { padding: 9px 12px; }
body.jm-dash .jm-dcat-quick-actions { display: flex; justify-content: flex-end; gap: 8px; }

/* ---------- course landing form: AJAX save (course-form.js) ---------- */
body.jm-dash .jm-dsave { display: flex; flex-wrap: wrap; align-items: center; justify-content: flex-end; gap: 14px; }
body.jm-dash .jm-dsave-status { margin-inline-end: auto; color: var(--faint); font-size: .86rem; }
body.jm-dash .jm-dsave-status.is-saved { color: var(--success); font-weight: 700; }
body.jm-dash .jm-dsave-status.is-error { color: var(--danger); font-weight: 700; }
body.jm-dash .jm-btn[aria-busy="true"] { opacity: .7; cursor: progress; }

/* The category popover must be able to leave its card (cards clip by default). */
body.jm-dash .jm-dcard:has(.jm-dcat) { overflow: visible; }
body.jm-dash .jm-dcat.is-open { z-index: 41; }

/* ============================================================
   Rich editor — rich-editor.js (JmEditor). Toolbar + contenteditable
   surface that replaces a <textarea>; the textarea stays in the DOM
   (hidden) and keeps the form value. Lives in the page, not an iframe,
   so it follows the theme tokens in light and dark.
   ============================================================ */
body.jm-dash .jm-ded-native { display: none; }
body.jm-dash .jm-ded {
    display: flex; flex-direction: column;
    background: var(--bg2); border: 1px solid var(--border); border-radius: var(--r-sm);
    transition: border-color .18s, box-shadow .18s;
}
body.jm-dash .jm-ded:focus-within { border-color: var(--accent); box-shadow: 0 0 0 4px rgba(249, 161, 27, .18); }
body.jm-dash .jm-ded.is-invalid { border-color: var(--danger); box-shadow: 0 0 0 4px var(--danger-soft); }
body.jm-dash .jm-ded [hidden] { display: none; }

body.jm-dash .jm-ded-bar {
    display: flex; flex-wrap: wrap; align-items: center; gap: 4px 0; padding: 6px 4px;
    background: var(--card); border-bottom: 1px solid var(--border);
    border-radius: var(--r-sm) var(--r-sm) 0 0;
}
body.jm-dash .jm-ded-group { display: flex; align-items: center; gap: 2px; padding-inline: 6px; border-inline-end: 1px solid var(--border); }
body.jm-dash .jm-ded-group:last-child { border-inline-end: 0; }
body.jm-dash .jm-ded-btn {
    display: grid; place-items: center; width: 34px; height: 34px; padding: 0;
    border: 0; border-radius: 8px; background: none; color: var(--muted); cursor: pointer;
    transition: background .15s, color .15s;
}
body.jm-dash .jm-ded-btn:hover { background: var(--card2); color: var(--text); }
body.jm-dash .jm-ded-btn:focus-visible, body.jm-dash .jm-ded-select:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
body.jm-dash .jm-ded-btn[aria-pressed="true"], body.jm-dash .jm-ded-btn[aria-expanded="true"] { background: var(--warn-soft); color: var(--accent-ink); }
body.jm-dash .jm-ded-btn:disabled, body.jm-dash .jm-ded-select:disabled { opacity: .4; cursor: not-allowed; }
body.jm-dash .jm-ded-btn svg { width: 18px; height: 18px; }
body.jm-dash .jm-ded-glyph { font-family: Georgia, "Times New Roman", serif; font-size: 1.05rem; line-height: 1; }
body.jm-dash .jm-ded-glyph--bold { font-weight: 700; }
body.jm-dash .jm-ded-glyph--italic { font-style: italic; }
body.jm-dash .jm-ded-glyph--underline { text-decoration: underline; }
body.jm-dash .jm-ded-glyph--strikethrough { text-decoration: line-through; }
body.jm-dash .jm-ded-select {
    height: 34px; max-width: 150px; padding-block: 0; padding-inline: 10px 8px;
    border: 1px solid var(--border); border-radius: 8px; background: var(--bg2); color: var(--text);
    font: inherit; font-size: .86rem; cursor: pointer;
}

body.jm-dash .jm-ded-panel { padding: 14px; background: var(--card); border-bottom: 1px solid var(--border); }
body.jm-dash .jm-ded-field { display: flex; flex-direction: column; gap: 5px; margin-bottom: 12px; }
body.jm-dash .jm-ded-field .jm-input { padding: 9px 12px; }
body.jm-dash .jm-ded-pair { display: grid; grid-template-columns: repeat(2, minmax(0, 160px)); gap: 12px; }
body.jm-dash .jm-ded-actions { display: flex; flex-wrap: wrap; align-items: center; justify-content: flex-end; gap: 8px; }
body.jm-dash .jm-ded-actions > :first-child:not(:nth-last-child(2)) { margin-inline-end: auto; }
body.jm-dash .jm-ded-upload { position: relative; cursor: pointer; }
body.jm-dash .jm-ded-upload input { position: absolute; inset: 0; width: 100%; opacity: 0; cursor: pointer; }
body.jm-dash .jm-ded-swatches { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
body.jm-dash .jm-ded-swatch { width: 26px; height: 26px; padding: 0; border: 1px solid var(--border); border-radius: 50%; cursor: pointer; }
body.jm-dash .jm-ded-swatch:hover, body.jm-dash .jm-ded-swatch:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
body.jm-dash .jm-ded-swatch--none { background: linear-gradient(135deg, transparent 45%, var(--danger) 45%, var(--danger) 55%, transparent 55%), var(--bg2); }
body.jm-dash .jm-ded-custom { display: inline-flex; align-items: center; gap: 8px; margin-inline-start: 8px; color: var(--muted); font-size: .84rem; cursor: pointer; }
body.jm-dash .jm-ded-custom input { width: 34px; height: 28px; padding: 0; border: 1px solid var(--border); border-radius: 6px; background: none; cursor: pointer; }

body.jm-dash .jm-ded-surface {
    min-height: 140px; padding: 16px 18px; overflow-y: auto; resize: vertical;
    color: var(--prose); font-size: 1rem; line-height: 1.75; outline: none; overflow-wrap: anywhere;
}
body.jm-dash .jm-ded-surface > :first-child { margin-top: 0; }
body.jm-dash .jm-ded-surface p { margin: 0 0 .9em; }
body.jm-dash .jm-ded-surface h1, body.jm-dash .jm-ded-surface h2, body.jm-dash .jm-ded-surface h3,
body.jm-dash .jm-ded-surface h4, body.jm-dash .jm-ded-surface h5, body.jm-dash .jm-ded-surface h6 { margin: 1.2em 0 .45em; color: var(--text); font-weight: 700; line-height: 1.35; }
body.jm-dash .jm-ded-surface h1 { font-size: 1.8rem; }
body.jm-dash .jm-ded-surface h2 { font-size: 1.5rem; }
body.jm-dash .jm-ded-surface h3 { font-size: 1.25rem; }
body.jm-dash .jm-ded-surface h4 { font-size: 1.1rem; }
body.jm-dash .jm-ded-surface h5, body.jm-dash .jm-ded-surface h6 { font-size: 1rem; }
body.jm-dash .jm-ded-surface ul { list-style: disc; }
body.jm-dash .jm-ded-surface ol { list-style: decimal; }
body.jm-dash .jm-ded-surface ul, body.jm-dash .jm-ded-surface ol { margin: 0 0 .9em; padding-inline-start: 1.6rem; }
body.jm-dash .jm-ded-surface a { color: var(--cyan); text-decoration: underline; }
body.jm-dash .jm-ded-surface blockquote { margin: 1em 0; padding: .75rem 1.25rem; background: var(--card); border-inline-start: 4px solid var(--accent); font-style: italic; }
body.jm-dash .jm-ded-surface pre { margin: 1em 0; padding: 1rem; overflow-x: auto; direction: ltr; text-align: left; white-space: pre-wrap; background: var(--code-bg); border: 1px solid var(--code-border); border-radius: 8px; font-family: var(--mono); font-size: .88rem; line-height: 1.6; }
body.jm-dash .jm-ded-surface code { padding: 2px 6px; background: var(--code-bg); border-radius: 4px; font-family: var(--mono); font-size: .875em; }
body.jm-dash .jm-ded-surface img { max-width: 100%; height: auto; border-radius: 8px; }
body.jm-dash .jm-ded-surface hr { margin: 1.4em 0; border: 0; border-top: 1px solid var(--border); }
body.jm-dash .jm-ded-surface table { width: 100%; margin: 1em 0; border-collapse: collapse; }
body.jm-dash .jm-ded-surface th, body.jm-dash .jm-ded-surface td { min-width: 40px; padding: .5rem .75rem; border: 1px solid var(--border); text-align: start; vertical-align: top; }
body.jm-dash .jm-ded-surface th { background: var(--card); font-weight: 700; }
body.jm-dash .jm-ded-surface [dir="rtl"], body.jm-dash .jm-ded-surface[dir="rtl"] { letter-spacing: 0; }

body.jm-dash .jm-ded-source {
    width: 100%; padding: 16px 18px; border: 0; outline: none; resize: vertical;
    background: var(--code-bg); color: var(--text); font-family: var(--mono); font-size: .86rem; line-height: 1.6;
}
body.jm-dash .jm-ded-foot { display: flex; justify-content: flex-end; padding: 6px 12px; border-top: 1px solid var(--border); color: var(--faint); font-size: .78rem; }

body.jm-dash .jm-ded.is-fullscreen { position: fixed; inset: 0; z-index: 200; border-radius: 0; border: 0; box-shadow: none; }
body.jm-dash .jm-ded.is-fullscreen .jm-ded-bar { border-radius: 0; }
body.jm-dash .jm-ded.is-fullscreen .jm-ded-surface, body.jm-dash .jm-ded.is-fullscreen .jm-ded-source { flex: 1; height: auto !important; resize: none; }
html.jm-ded-lock { overflow: hidden; }

/* ---------- multi-text list: drag handle + AJAX errors (multi-text-list.js) ---------- */
body.jm-dash .multi-text-handle {
    display: grid; place-items: center; flex: none; width: 30px; height: 36px; padding: 0;
    border: 0; border-radius: 8px; background: none; color: var(--faint);
    cursor: grab; touch-action: none;
}
body.jm-dash .multi-text-handle:hover { background: var(--card2); color: var(--text); }
body.jm-dash .multi-text-handle:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
body.jm-dash .multi-text-handle svg { width: 16px; height: 16px; }
body.jm-dash .multi-text-item.is-dragging { background: var(--warn-soft); border-radius: var(--r-sm); box-shadow: var(--shadow); }
body.jm-dash .multi-text-item.is-dragging .multi-text-handle { cursor: grabbing; color: var(--accent-ink); }
body.jm-dash .multi-text-item input.is-invalid { border-color: var(--danger); box-shadow: 0 0 0 4px var(--danger-soft); }
body.jm-dash .jm-dmulti.is-sorting { user-select: none; }

/* ------------------------------------------------------------
   AI assist (static/js/ai-assist.js, fragments/ai-assist.html)
   One shared dialog: options step → result step. The trigger sits
   on the label row of the field it writes into.
   Pages: dashboard/courses/create.html, edit.html (+ any page that
   includes the fragment).
   ------------------------------------------------------------ */
body.jm-dash .jm-ai-labelrow { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 6px 12px; }

body.jm-dash .jm-ai-btn {
    display: inline-flex; align-items: center; gap: 6px; flex: none;
    padding: 4px 10px; border: 1px solid var(--border2); border-radius: 999px;
    background: transparent; color: var(--accent-ink);
    font: inherit; font-size: .8rem; font-weight: 700; line-height: 1.4; cursor: pointer;
    transition: background .2s, border-color .2s;
}
body.jm-dash .jm-ai-btn:hover { background: color-mix(in srgb, var(--accent) 12%, transparent); border-color: var(--accent); }
body.jm-dash .jm-ai-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
body.jm-dash .jm-ai-btn:disabled { opacity: .55; cursor: not-allowed; }
body.jm-dash .jm-ai-spark { flex: none; width: 15px; height: 15px; }

html.jm-ai-lock { overflow: hidden; }
body.jm-dash .jm-ai-modal [hidden] { display: none !important; }
body.jm-dash .jm-ai-panel { max-width: 620px; }
body.jm-dash .jm-ai-panel:focus { outline: none; }
body.jm-dash .jm-ai-mark {
    display: grid; place-items: center; flex: none; width: 36px; height: 36px; border-radius: 10px;
    background: color-mix(in srgb, var(--accent) 14%, transparent); color: var(--accent-ink);
}
body.jm-dash .jm-ai-mark .jm-ai-spark { width: 18px; height: 18px; }
body.jm-dash .jm-ai-title { min-width: 0; overflow-wrap: anywhere; }
body.jm-dash .jm-ai-error { margin-bottom: 16px; }
body.jm-dash .jm-ai-error-link { color: inherit; font-weight: 700; text-decoration: underline; white-space: nowrap; }

body.jm-dash .jm-ai-fields { display: grid; gap: 18px; }
body.jm-dash .jm-ai-field { display: flex; flex-direction: column; gap: 6px; min-width: 0; margin: 0; padding: 0; border: 0; }
body.jm-dash .jm-ai-field > legend { padding: 0; margin-bottom: 6px; }
body.jm-dash .jm-ai-field > .jm-help { margin: 0; }
body.jm-dash .jm-ai-field-meta { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; }
body.jm-dash .jm-ai-counter { margin-inline-start: auto; flex: none; font-variant-numeric: tabular-nums; }
body.jm-dash .jm-ai-count { max-width: 120px; }
body.jm-dash .jm-ai-details { min-height: 88px; }

/* Segmented choice: real radios, so arrow keys and form semantics come for free. */
body.jm-dash .jm-ai-seg {
    display: grid; grid-auto-flow: column; grid-auto-columns: 1fr; gap: 3px;
    padding: 3px; border: 1px solid var(--border); border-radius: 12px; background: var(--card);
}
body.jm-dash .jm-ai-seg.is-invalid { border-color: var(--danger); box-shadow: 0 0 0 4px var(--danger-soft); }
body.jm-dash .jm-ai-seg-opt { position: relative; display: block; cursor: pointer; }
body.jm-dash .jm-ai-seg-opt input { position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; opacity: 0; cursor: pointer; }
body.jm-dash .jm-ai-seg-opt span {
    display: block; padding: 8px 10px; border-radius: 9px; text-align: center;
    font-size: .88rem; font-weight: 700; color: var(--muted);
    transition: color .2s, background .2s;
}
body.jm-dash .jm-ai-seg-opt:hover span { color: var(--text); }
body.jm-dash .jm-ai-seg-opt input:checked + span { background: var(--bg2); color: var(--accent-ink); box-shadow: var(--shadow); }
body.jm-dash .jm-ai-seg-opt input:focus-visible + span { outline: 2px solid var(--accent); outline-offset: 1px; }
body.jm-dash .jm-ai-seg-opt input:disabled + span { opacity: .55; }
body.jm-dash .jm-ai-seg-opt input:disabled { cursor: not-allowed; }

body.jm-dash .jm-ai-foot { align-items: center; }
body.jm-dash .jm-ai-foot-gap { flex: 1; }
body.jm-dash .jm-ai-modal .jm-btn[aria-busy="true"] .jm-ai-spark { animation: jm-ai-pulse 1.1s ease-in-out infinite; }
@keyframes jm-ai-pulse { 50% { opacity: .35; transform: scale(.82); } }
body.jm-dash .jm-ai-status { min-height: 1.3em; margin: 12px 0 0; color: var(--muted); font-size: .85rem; text-align: end; }
body.jm-dash .jm-ai-status:empty { min-height: 0; margin: 0; }

body.jm-dash .jm-ai-block { display: flex; flex-direction: column; gap: 6px; }
body.jm-dash .jm-ai-block > .jm-label { margin: 0; }
body.jm-dash .jm-ai-text { min-height: 150px; line-height: 1.7; }
body.jm-dash .jm-ai-preview {
    max-height: min(46vh, 420px); overflow: auto; padding: 16px 18px;
    border: 1px solid var(--border); border-radius: 12px; background: var(--card);
    color: var(--text); font-size: .95rem; line-height: 1.7; overflow-wrap: anywhere;
}
body.jm-dash .jm-ai-preview:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
body.jm-dash .jm-ai-preview > :first-child { margin-top: 0; }
body.jm-dash .jm-ai-preview > :last-child { margin-bottom: 0; }
body.jm-dash .jm-ai-preview :is(h1, h2, h3, h4) { margin: 1.1em 0 .45em; font-weight: 700; line-height: 1.3; }
body.jm-dash .jm-ai-preview h1 { font-size: 1.35rem; }
body.jm-dash .jm-ai-preview h2 { font-size: 1.2rem; }
body.jm-dash .jm-ai-preview :is(h3, h4) { font-size: 1.05rem; }
body.jm-dash .jm-ai-preview p { margin: 0 0 .9em; }
body.jm-dash .jm-ai-preview ul { list-style: disc; }
body.jm-dash .jm-ai-preview ol { list-style: decimal; }
body.jm-dash .jm-ai-preview :is(ul, ol) { margin: 0 0 .9em; padding-inline-start: 1.6rem; }
body.jm-dash .jm-ai-preview a { color: var(--cyan); text-decoration: underline; pointer-events: none; }
body.jm-dash .jm-ai-preview img { max-width: 100%; height: auto; }
body.jm-dash .jm-ai-preview pre { overflow-x: auto; padding: 12px; direction: ltr; text-align: left; background: var(--code-bg); border: 1px solid var(--code-border); border-radius: 8px; font-family: var(--mono); font-size: .86rem; }

body.jm-dash .jm-ai-list { display: flex; flex-direction: column; gap: 8px; min-width: 0; margin: 0; padding: 0; border: 0; max-height: min(52vh, 460px); overflow-y: auto; }
body.jm-dash .jm-ai-list > legend { padding: 0; margin-bottom: 8px; }
body.jm-dash .jm-ai-item {
    display: flex; align-items: flex-start; gap: 10px; padding: 12px 14px;
    border: 1px solid var(--border); border-radius: 12px; background: var(--card); cursor: pointer;
    transition: border-color .2s, background .2s;
}
body.jm-dash .jm-ai-item:hover { border-color: var(--border2); }
body.jm-dash .jm-ai-item:has(input:checked) { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 8%, transparent); }
body.jm-dash .jm-ai-item:has(input:focus-visible) { outline: 2px solid var(--accent); outline-offset: 1px; }
body.jm-dash .jm-ai-item input { flex: none; width: 18px; height: 18px; margin: 3px 0 0; accent-color: var(--accent); }
body.jm-dash .jm-ai-item-text { flex: 1; min-width: 0; overflow-wrap: anywhere; line-height: 1.6; font-weight: 700; }
body.jm-dash .jm-ai-result > .jm-field-error { margin-top: 8px; }

@media (max-width: 560px) {
    body.jm-dash .jm-ai-modal { padding: 10px; align-items: flex-end; }
    body.jm-dash .jm-ai-panel { padding: 20px 16px; max-height: calc(100dvh - 20px); border-radius: 18px; }
    body.jm-dash .jm-ai-foot-gap { display: none; }
    body.jm-dash .jm-ai-foot .jm-btn { flex: 1 1 calc(50% - 5px); }
    body.jm-dash .jm-ai-foot .jm-ai-apply, body.jm-dash .jm-ai-foot .jm-ai-generate { order: 9; flex-basis: 100%; }
}
@media (prefers-reduced-motion: reduce) {
    body.jm-dash .jm-ai-modal .jm-btn[aria-busy="true"] .jm-ai-spark { animation: none; }
    body.jm-dash .jm-ai-btn, body.jm-dash .jm-ai-seg-opt span, body.jm-dash .jm-ai-item { transition: none; }
}

/* ---------- AI quiz generator dialog (quiz-ai.js, courses/curriculum.html) ----------
   Built on .jm-modal / .jm-modal-panel--lg. The panel is a flex column so the
   head and the action bar stay put while the form / question list scrolls. */
html.jm-qai-lock { overflow: hidden; }
body.jm-dash .jm-qai [hidden] { display: none; }
body.jm-dash .jm-qai *, body.jm-dash .jm-qai *::before { box-sizing: border-box; }
body.jm-dash .jm-qai-trigger { margin-top: .75rem; margin-inline-start: 8px; padding-block: 7px; vertical-align: top; }

body.jm-dash .jm-qai-panel { display: flex; flex-direction: column; padding: 0; overflow: hidden; }
body.jm-dash .jm-qai-head { align-items: flex-start; margin: 0; padding: 22px 24px 16px; border-bottom: 1px solid var(--border); }
body.jm-dash .jm-qai-mark {
    display: grid; place-items: center; flex: none; width: 40px; height: 40px;
    border-radius: 12px; background: var(--warn-soft); border: 1px solid var(--warn-border); color: var(--accent-ink);
}
body.jm-dash .jm-qai-mark svg { width: 20px; height: 20px; }
body.jm-dash .jm-qai-headtext { flex: 1; min-width: 0; }
body.jm-dash .jm-qai-lead { margin: 4px 0 0; color: var(--muted); font-size: .9rem; line-height: 1.5; outline: none; }
body.jm-dash .jm-qai-body { flex: 1; min-height: 0; overflow-y: auto; padding: 20px 24px; }

/* step 1 — options */
body.jm-dash .jm-qai-grid { display: grid; gap: 18px 20px; grid-template-columns: minmax(0, 1fr); }
body.jm-dash .jm-qai-grid .jm-form-row { margin-bottom: 0; }
body.jm-dash .jm-qai-group { display: flex; flex-direction: column; gap: 6px; min-width: 0; margin: 0; padding: 0; border: 0; }
body.jm-dash .jm-qai-group > legend { padding: 0; margin-bottom: 6px; }
body.jm-dash .jm-qai-checks { display: flex; flex-wrap: wrap; gap: 10px 22px; padding: 11px 14px; border: 1px solid var(--border); border-radius: var(--r-sm); background: var(--bg2); }
body.jm-dash .jm-qai-checks .jm-check { align-items: center; color: var(--text); }
body.jm-dash .jm-qai-checks .jm-check input { margin-top: 0; }
body.jm-dash .jm-qai-seg { display: inline-flex; flex-wrap: wrap; align-self: flex-start; gap: 4px; padding: 4px; border: 1px solid var(--border); border-radius: var(--r-sm); background: var(--card); }
body.jm-dash .jm-qai-segitem { position: relative; cursor: pointer; }
body.jm-dash .jm-qai-segitem input { position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; opacity: 0; cursor: pointer; }
body.jm-dash .jm-qai-segitem span { display: block; padding: 8px 18px; border-radius: 8px; color: var(--muted); font-size: .88rem; font-weight: 700; transition: background .18s, color .18s; }
body.jm-dash .jm-qai-segitem:hover span { color: var(--text); }
body.jm-dash .jm-qai-segitem input:checked + span { background: var(--grad); color: var(--btn-text); }
body.jm-dash .jm-qai-segitem input:focus-visible + span { outline: 2px solid var(--accent); outline-offset: 2px; }
body.jm-dash .jm-qai-group.is-invalid .jm-qai-checks,
body.jm-dash .jm-qai-group.is-invalid .jm-qai-seg { border-color: var(--danger); box-shadow: 0 0 0 4px var(--danger-soft); }
body.jm-dash .jm-qai-details { min-height: 110px; }
body.jm-dash .jm-qai-meta { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; }
body.jm-dash .jm-qai-meta p { margin: 0; }
body.jm-dash .jm-qai-counter { flex: none; font-variant-numeric: tabular-nums; }
body.jm-dash .jm-qai-counter.is-over { color: var(--danger); font-weight: 700; }
@media (min-width: 640px) {
    body.jm-dash .jm-qai-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    body.jm-dash .jm-qai-wide { grid-column: 1 / -1; }
}

/* step 2 — review cards */
body.jm-dash .jm-qai-review { display: flex; flex-direction: column; gap: 14px; }
body.jm-dash .jm-qai-card { padding: 14px 16px 16px; border: 1px solid var(--border); border-radius: var(--r); background: var(--card); transition: border-color .18s, box-shadow .18s; }
body.jm-dash .jm-qai-card.is-invalid { border-color: var(--danger); box-shadow: 0 0 0 4px var(--danger-soft); }
body.jm-dash .jm-qai-card.is-skipped > :not(.jm-qai-cardhead) { opacity: .45; }
body.jm-dash .jm-qai-card.is-skipped .jm-qai-cardtitle { color: var(--faint); text-decoration: line-through; }
body.jm-dash .jm-qai-cardhead { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; margin-bottom: 10px; }
body.jm-dash .jm-qai-cardtitle { flex: 1; min-width: 0; margin: 0; font-size: .95rem; font-weight: 700; color: var(--text); }
body.jm-dash .jm-qai-keep { align-items: center; padding: 5px 10px; border: 1px solid var(--border); border-radius: 9px; background: var(--bg2); color: var(--text); font-size: .84rem; font-weight: 700; }
body.jm-dash .jm-qai-keep input { margin-top: 0; }
body.jm-dash .jm-qai-remove { display: grid; place-items: center; flex: none; width: 32px; height: 32px; padding: 0; border: 1px solid transparent; border-radius: 9px; background: none; color: var(--faint); cursor: pointer; }
body.jm-dash .jm-qai-remove:hover { background: var(--danger-soft); border-color: var(--danger-border); color: var(--danger); }
body.jm-dash .jm-qai-remove:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
body.jm-dash .jm-qai-remove svg { width: 16px; height: 16px; }
body.jm-dash .jm-qai-qtext { min-height: 0; font-weight: 700; }
body.jm-dash .jm-qai-options { display: flex; flex-direction: column; gap: 8px; margin-top: 10px; }
body.jm-dash .jm-qai-option { display: flex; align-items: center; gap: 10px; }
body.jm-dash .jm-qai-option .jm-input { padding-block: 9px; }
body.jm-dash .jm-qai-option input.jm-qai-correct { flex: none; width: 20px; height: 20px; margin: 0; accent-color: var(--success); cursor: pointer; }
body.jm-dash .jm-qai-card > .jm-field-error { margin: 10px 0 0; }

/* alert, live status, action bar */
body.jm-dash .jm-qai-alert { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 14px; margin: 0 24px 14px; padding: 11px 14px; border: 1px solid var(--danger-border); border-radius: var(--r-sm); background: var(--danger-soft); color: var(--danger); font-size: .9rem; font-weight: 700; }
body.jm-dash .jm-qai-alertlink { color: inherit; text-decoration: underline; text-underline-offset: 3px; }
body.jm-dash .jm-qai-foot { align-items: center; margin: 0; padding: 14px 24px 18px; border-top: 1px solid var(--border); }
body.jm-dash .jm-qai-status { display: flex; align-items: center; gap: 10px; flex: 1 1 200px; min-width: 0; margin: 0; color: var(--muted); font-size: .88rem; }
body.jm-dash .jm-qai.is-busy .jm-qai-status::before {
    content: ""; flex: none; width: 16px; height: 16px; border-radius: 50%;
    border: 2px solid var(--border); border-top-color: var(--accent); animation: jm-qai-spin .8s linear infinite;
}
body.jm-dash .jm-qai.is-busy .jm-qai-body { opacity: .6; pointer-events: none; }
@keyframes jm-qai-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
    body.jm-dash .jm-qai.is-busy .jm-qai-status::before { animation-duration: 2.4s; }
}
@media (max-width: 639px) {
    body.jm-dash .jm-qai { padding: 10px; }
    body.jm-dash .jm-qai-head { padding: 16px 16px 14px; }
    body.jm-dash .jm-qai-body { padding: 16px; }
    body.jm-dash .jm-qai-alert { margin-inline: 16px; }
    body.jm-dash .jm-qai-foot { padding: 12px 16px 14px; }
    body.jm-dash .jm-qai-foot .jm-btn { flex: 1 1 auto; justify-content: center; }
}

/* ============================================================
   T1b — settings/ai-models.html (AI models APIs) and the course
   URL field on courses/edit.html.
   ============================================================ */

/* settings/ai-models.html — one .jm-dcard per configured API: details at the
   start, actions at the end; stacks on narrow screens. */
body.jm-dash .jm-aip-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 14px; }
body.jm-dash .jm-aip-list.hidden { display: none; }
body.jm-dash .jm-aip-row { display: flex; flex-direction: column; gap: 16px; padding: 20px 22px; }
body.jm-dash .jm-aip-row.is-default { border-color: var(--border2); }
body.jm-dash .jm-aip-main { min-width: 0; flex: 1; }
body.jm-dash .jm-aip-meta { display: grid; grid-template-columns: 1fr; gap: 10px 24px; margin: 14px 0 0; }
body.jm-dash .jm-aip-meta > div { min-width: 0; }
body.jm-dash .jm-aip-meta > div.hidden { display: none; }
body.jm-dash .jm-aip-meta dt { font-size: .76rem; color: var(--faint); margin: 0 0 2px; }
body.jm-dash .jm-aip-meta dd { margin: 0; font-size: .9rem; color: var(--text); overflow-wrap: anywhere; }
/* dd values are LTR tokens (model ids, keys, URLs); keep them on the reading side in Arabic. */
[dir="rtl"] body.jm-dash .jm-aip-meta dd[dir="ltr"] { text-align: end; }
body.jm-dash .jm-aip-test { margin: 14px 0 0; font-size: .82rem; color: var(--faint); }
body.jm-dash .jm-aip-test.is-ok { color: var(--success); }
body.jm-dash .jm-aip-test.is-failed { color: var(--danger); }
body.jm-dash .jm-aip-actions { display: flex; flex-wrap: wrap; gap: 8px; align-content: flex-start; }
@media (min-width: 640px) {
    body.jm-dash .jm-aip-meta { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (min-width: 1024px) {
    body.jm-dash .jm-aip-row { flex-direction: row; align-items: flex-start; }
    body.jm-dash .jm-aip-actions { flex: none; max-width: 260px; justify-content: flex-end; }
}

/* settings/ai-models.html — API key input with a Show/Hide text button at its end. */
body.jm-dash .jm-aip-secret { position: relative; display: flex; align-items: center; }
body.jm-dash .jm-aip-secret > .jm-input { padding-right: 76px; }
body.jm-dash .jm-aip-reveal {
    position: absolute;
    right: 6px;
    padding: 6px 10px;
    border: 0;
    border-radius: 8px;
    background: transparent;
    color: var(--accent-ink);
    font-size: .82rem;
    font-weight: 700;
    cursor: pointer;
}
body.jm-dash .jm-aip-reveal:hover { background: var(--card2); }
body.jm-dash .jm-aip-reveal:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }

/* settings/ai-models.html — related-page links under the header. */
body.jm-dash .jm-aip-links { display: flex; flex-wrap: wrap; gap: 8px 22px; margin: -6px 0 20px; font-size: .85rem; }
body.jm-dash .jm-aip-links a { display: inline-flex; align-items: center; gap: 6px; font-weight: 700; }
body.jm-dash .jm-aip-links svg { width: 16px; height: 16px; flex: none; }

/* System health: the AI providers page links to #health-ai-provider; keep the card clear of the
   sticky top bar and show which card the link meant. */
body.jm-dash [data-health-card] { scroll-margin-top: 88px; }
body.jm-dash [data-health-card]:target { border-color: var(--accent); box-shadow: 0 0 0 3px var(--warn-soft); }

/* Row: the model in use is the most prominent fact, set apart in its own well. On wide screens the row
   is a flex row; wrapping lets the quick-switch panel drop below details + actions. (Never wrap the
   narrow-screen column: a wrapping column grows sideways.) */
@media (min-width: 1024px) {
    body.jm-dash .jm-aip-row { flex-wrap: wrap; }
}
body.jm-dash .jm-aip-current {
    margin: 14px 0 0;
    padding: 12px 14px;
    border: 1px solid var(--border);
    border-radius: var(--r-sm);
    background: var(--card);
}
body.jm-dash .jm-aip-row.is-default .jm-aip-current { border-color: var(--border2); }
body.jm-dash .jm-aip-current-label { margin: 0; font-size: .76rem; color: var(--faint); }
body.jm-dash .jm-aip-current-name { margin: 2px 0 0; font-size: 1.08rem; font-weight: 700; color: var(--text); overflow-wrap: anywhere; }
body.jm-dash .jm-aip-current-id { margin: 0; font-size: .8rem; color: var(--muted); overflow-wrap: anywhere; }
body.jm-dash .jm-aip-current-id.hidden { display: none; }
body.jm-dash .jm-aip-current .jm-aip-badges:not(:empty) { margin-top: 8px; }
body.jm-dash .jm-aip-row.is-switching .jm-aip-current { opacity: .7; }

/* Row: quick switch panel spans the full card width below details + actions. */
body.jm-dash .jm-aip-switch { flex: 1 1 100%; min-width: 0; border-top: 1px solid var(--border); padding-top: 18px; }
body.jm-dash .jm-aip-switch.hidden { display: none; }
body.jm-dash .jm-aip-switch-title { margin: 0 0 12px; font-size: .95rem; font-weight: 700; color: var(--text); }
body.jm-dash .jm-aip-switch-foot { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 10px; margin-top: 16px; }

/* Model picker. */
body.jm-dash .jm-aip-picker { display: grid; gap: 12px; min-width: 0; }
body.jm-dash .jm-aip-picker-tools { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; }
body.jm-dash .jm-aip-search { position: relative; flex: 1 1 220px; min-width: 0; }
body.jm-dash .jm-aip-search.hidden { display: none; }
body.jm-dash .jm-aip-search svg {
    position: absolute; inset-inline-start: 12px; top: 50%; width: 16px; height: 16px;
    transform: translateY(-50%); color: var(--faint); pointer-events: none;
}
body.jm-dash .jm-aip-search .jm-input { padding-inline-start: 36px; }
body.jm-dash .jm-aip-picker-tools [data-aip-fetch].hidden { display: none; }
body.jm-dash .jm-aip-fetch-hint { margin: -4px 0 0; }
body.jm-dash .jm-aip-fetch-hint:empty { display: none; }
body.jm-dash .jm-aip-groups { display: grid; gap: 16px; }
body.jm-dash .jm-aip-group { border: 0; margin: 0; padding: 0; min-width: 0; }
body.jm-dash .jm-aip-group.hidden { display: none; }
body.jm-dash .jm-aip-group-title { padding: 0; margin: 0 0 8px; font-size: .82rem; font-weight: 700; color: var(--muted); }
body.jm-dash .jm-aip-options { display: grid; gap: 10px; grid-template-columns: minmax(0, 1fr); }
body.jm-dash .jm-aip-nomatch.hidden { display: none; }

/* One option: a label around a visually hidden native radio, so arrow keys, focus order and RTL
   come from the browser. */
body.jm-dash .jm-aip-opt {
    position: relative;
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    gap: 12px;
    align-items: start;
    padding: 12px 14px;
    border: 1px solid var(--border);
    border-radius: var(--r-sm);
    background: var(--card);
    cursor: pointer;
    transition: border-color .15s ease, background-color .15s ease;
}
body.jm-dash .jm-aip-opt.hidden { display: none; }
body.jm-dash .jm-aip-opt:hover { background: var(--card2); }
body.jm-dash .jm-aip-opt-input { position: absolute; opacity: 0; width: 1px; height: 1px; margin: 0; pointer-events: none; }
body.jm-dash .jm-aip-opt:has(.jm-aip-opt-input:focus-visible) { outline: 2px solid var(--accent); outline-offset: 2px; }
body.jm-dash .jm-aip-opt-mark {
    width: 18px; height: 18px; margin-top: 2px; border-radius: 50%;
    border: 2px solid var(--faint); background: var(--bg2);
    transition: border-color .15s ease, box-shadow .15s ease;
}
/* The recommended model carries an accent edge on the reading-start side: the eye lands there first. */
body.jm-dash .jm-aip-opt.is-recommended { border-inline-start: 3px solid var(--accent); padding-inline-start: 12px; }
body.jm-dash .jm-aip-opt.is-checked { border-color: var(--accent); background: var(--card2); box-shadow: 0 0 0 1px var(--accent); }
body.jm-dash .jm-aip-opt.is-checked .jm-aip-opt-mark { border-color: var(--accent); box-shadow: inset 0 0 0 4px var(--bg2); background: var(--accent); }
body.jm-dash .jm-aip-opt.is-unlisted { border-style: dashed; }
body.jm-dash .jm-aip-opt.is-unlisted .jm-aip-opt-name { color: var(--muted); }
body.jm-dash .jm-aip-opt-body { display: grid; gap: 4px; min-width: 0; }
body.jm-dash .jm-aip-opt-head { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 8px; }
body.jm-dash .jm-aip-opt-name { font-weight: 700; color: var(--text); font-size: .95rem; }
body.jm-dash .jm-aip-opt-id { font-family: var(--mono); font-size: .76rem; color: var(--muted); overflow-wrap: anywhere; justify-self: start; }
body.jm-dash .jm-aip-opt-id:empty { display: none; }
body.jm-dash .jm-aip-opt-desc { font-size: .85rem; color: var(--muted); line-height: 1.5; }
body.jm-dash .jm-aip-opt-desc:empty { display: none; }
body.jm-dash .jm-aip-opt-note { font-size: .76rem; color: var(--faint); }
body.jm-dash .jm-aip-opt-note:empty { display: none; }
body.jm-dash .jm-aip-badges { display: inline-flex; flex-wrap: wrap; gap: 4px; }
body.jm-dash .jm-aip-badges:empty { display: none; }
body.jm-dash .jm-aip-facts { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 2px; }
body.jm-dash .jm-aip-facts:empty { display: none; }
body.jm-dash .jm-aip-fact {
    display: inline-flex; align-items: center; padding: 2px 8px; border-radius: 6px;
    background: var(--bg2); border: 1px solid var(--border); font-size: .74rem; color: var(--muted); white-space: nowrap;
}
body.jm-dash .jm-aip-fact--price { color: var(--text); font-weight: 700; }
body.jm-dash .jm-aip-opt--custom { margin-top: 2px; }
body.jm-dash .jm-aip-custom-field.hidden,
body.jm-dash .jm-aip-custom-row.hidden { display: none; }
body.jm-dash .jm-aip-custom-row { display: grid; gap: 6px; }

/* Placeholder cards while the provider's list loads. */
body.jm-dash .jm-aip-opt--skel { display: grid; grid-template-columns: minmax(0, 1fr); gap: 8px; cursor: default; }
body.jm-dash .jm-aip-skel { display: grid; gap: 14px; }
body.jm-dash .jm-aip-skel.hidden { display: none; }
body.jm-dash .jm-aip-skel-row { display: grid; gap: 10px; padding: 20px 22px; }
body.jm-dash .jm-aip-skel-line,
body.jm-dash .jm-aip-skel-block {
    display: block; height: 11px; width: 62%; border-radius: 6px; background: var(--card2);
    animation: jm-aip-pulse 1.3s ease-in-out infinite;
}
body.jm-dash .jm-aip-skel-line--title { width: 34%; height: 15px; }
body.jm-dash .jm-aip-skel-line--short { width: 28%; height: 9px; }
body.jm-dash .jm-aip-skel-block { width: 100%; height: 64px; border-radius: var(--r-sm); }
@keyframes jm-aip-pulse { 50% { opacity: .45; } }

/* Add/edit modal: provider + name side by side when there is room. */
body.jm-dash .jm-aip-form-grid { display: grid; gap: 0 16px; grid-template-columns: minmax(0, 1fr); }
@media (min-width: 640px) {
    body.jm-dash .jm-aip-form-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (min-width: 768px) {
    body.jm-dash .jm-aip-options { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (prefers-reduced-motion: reduce) {
    body.jm-dash .jm-aip-skel-line,
    body.jm-dash .jm-aip-skel-block { animation: none; }
    body.jm-dash .jm-aip-opt,
    body.jm-dash .jm-aip-opt-mark { transition: none; }
}

/* courses/edit.html — course URL: a fixed, non-editable path prefix joined to
   the slug input. Always LTR (it is a URL), also on Arabic pages. */
body.jm-dash .jm-dslug { display: flex; align-items: stretch; direction: ltr; }
body.jm-dash .jm-dslug-prefix {
    display: flex;
    align-items: center;
    flex: none;
    padding: 0 12px;
    border: 1px solid var(--border);
    border-right: 0;
    border-radius: var(--r-sm) 0 0 var(--r-sm);
    background: var(--card2);
    color: var(--muted);
    font-family: var(--mono);
    font-size: .9rem;
    user-select: none;
}
body.jm-dash .jm-dslug > .jm-input {
    flex: 1;
    min-width: 0;
    border-top-left-radius: 0;
    border-bottom-left-radius: 0;
    font-family: var(--mono);
    text-align: left;
}
/* AI assist: the dialog is appended to <body> by script, so it sizes itself rather than
   relying on a page reset; the "12 / 2000" counter reads left to right in Arabic too. */
body.jm-dash .jm-ai-panel, body.jm-dash .jm-ai-panel * { box-sizing: border-box; }
body.jm-dash .jm-ai-counter { direction: ltr; unicode-bidi: isolate; }

/* course URL: "Generate from title" sits at the end of the slug row and drops below it on phones. */
body.jm-dash .jm-dslug { flex-wrap: wrap; gap: 8px 0; }
body.jm-dash .jm-dslug > .jm-input { flex: 1 1 180px; }
body.jm-dash .jm-dslug-btn { flex: none; margin-left: 8px; white-space: nowrap; }
@media (max-width: 520px) {
    body.jm-dash .jm-dslug-btn { margin-left: 0; width: 100%; }
}

/* AI quiz dialog: "Generate from titles" — pick sections and lectures as the quiz scope. */
body.jm-dash .jm-qai-source-toggle { align-self: flex-start; }
body.jm-dash .jm-qai-source-toggle[aria-expanded="true"] { background: var(--warn-soft); color: var(--accent-ink); }
body.jm-dash .jm-qai-source-panel { margin-top: 10px; padding: 14px; background: var(--card); border: 1px solid var(--border); border-radius: var(--r-sm); }
body.jm-dash .jm-qai-source-panel[hidden] { display: none; }
body.jm-dash .jm-qai-source-panel.is-invalid { border-color: var(--danger); box-shadow: 0 0 0 4px var(--danger-soft); }
body.jm-dash .jm-qai-source-list { max-height: 280px; margin-top: 10px; overflow-y: auto; }
body.jm-dash .jm-qai-source-group { margin: 0 0 12px; padding: 0; border: 0; min-width: 0; }
body.jm-dash .jm-qai-source-legend { padding: 0; font-weight: 700; color: var(--text); }
body.jm-dash .jm-qai-source-legend .jm-check { color: var(--text); }
body.jm-dash .jm-qai-source-items { display: grid; gap: 6px; margin-top: 8px; padding-inline-start: 28px; }
body.jm-dash .jm-qai-source-count { margin: 8px 0 0; font-weight: 700; }

/* ============================================================
   Ratings admin — rating-admin.js: bulk bar for external ratings,
   inline edit of a student rating and the "student's original" block.
   Pages: dashboard/courses/view.html, dashboard/reviews/index.html
   ============================================================ */
body.jm-dash .jm-rae-bulk { display: flex; flex-wrap: wrap; align-items: center; gap: 10px 14px; margin-bottom: 10px; padding: 8px 12px; background: var(--card); border: 1px solid var(--border); border-radius: var(--r-sm); }
body.jm-dash .jm-rae-bulk[hidden] { display: none; }
body.jm-dash .jm-rae-bulk .jm-btn { margin-inline-start: auto; }
body.jm-dash .jm-rae-bulk .jm-check { align-items: center; color: var(--text); font-weight: 700; }
body.jm-dash .jm-rae-bulk .jm-check input { margin-top: 0; }
body.jm-dash .jm-rae-select { flex: none; width: 18px; height: 18px; accent-color: var(--accent); cursor: pointer; }
body.jm-dash .jm-rae-edit { margin-inline-start: auto; }
body.jm-dash .jm-rae-edit[hidden], body.jm-dash .jm-rae-extra:empty, body.jm-dash .review-admin-extra:empty { display: none; }
body.jm-dash .jm-rae-extra, body.jm-dash .review-admin-extra { margin-top: 10px; }
body.jm-dash .jm-rae { padding: 14px; background: var(--bg2); border: 1px solid var(--border); border-radius: var(--r-sm); }
body.jm-dash .jm-rae-stars { margin: 0 0 12px; padding: 0; border: 0; min-width: 0; }
body.jm-dash .jm-rae-stars legend { padding: 0; margin-bottom: 6px; }
body.jm-dash .jm-rae-starrow { display: inline-flex; gap: 2px; padding: 2px; border-radius: 9px; }
body.jm-dash .jm-rae-stars.is-invalid .jm-rae-starrow { box-shadow: 0 0 0 4px var(--danger-soft); outline: 1px solid var(--danger); }
body.jm-dash .jm-rae-star { display: grid; place-items: center; width: 34px; height: 34px; border-radius: 8px; color: var(--faint); font-size: 1.45rem; line-height: 1; cursor: pointer; }
body.jm-dash .jm-rae-star.is-on { color: var(--accent); }
body.jm-dash .jm-rae-star:hover { background: var(--card2); }
body.jm-dash .jm-rae-star:focus-within { outline: 2px solid var(--accent); outline-offset: 1px; }
body.jm-dash .jm-rae .jm-form-row { margin-bottom: 12px; }
body.jm-dash .jm-rae .jm-textarea { min-height: 84px; }
body.jm-dash .jm-rae-actions { display: flex; justify-content: flex-end; gap: 8px; }
body.jm-dash .jm-rae-original { padding: 10px 12px; background: var(--card); border: 1px dashed var(--border); border-radius: var(--r-sm); }
body.jm-dash .jm-rae-original-head { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; }
body.jm-dash .jm-rae-original-head .jm-btn { margin-inline-start: auto; }
body.jm-dash .jm-rae-original-label { color: var(--muted); font-size: .8rem; font-weight: 700; }
body.jm-dash .jm-rae-original-text { margin: 6px 0 0; color: var(--muted); font-size: .88rem; white-space: pre-wrap; overflow-wrap: anywhere; }

/* AI trigger button: always one line, and its icon is sized even without the .jm-ai-spark class
   (the guide page's buttons carry a bare <svg>, which otherwise grows and squeezes the label). */
body.jm-dash .jm-ai-btn { white-space: nowrap; }
body.jm-dash .jm-ai-btn svg { flex: none; width: 15px; height: 15px; }
body.jm-dash .jm-dcard-head .jm-dcard-title { min-width: 0; }
body.jm-dash .jm-dcard-head .jm-dcard-actions { flex: none; }

/* Curriculum: keep the "add section here" strip open while its section is being added, so the
   "Adding section…" label stays visible after the pointer moves away; other strips look inactive. */


/* Curriculum: a section or lecture being deleted — dimmed, locked, with a "Deleting…" badge. */
body.jm-dash .is-deleting { position: relative; pointer-events: none; user-select: none; }
body.jm-dash .is-deleting > :not(.jm-dcb-deleting) { opacity: .35; }
body.jm-dash .jm-dcb-deleting {
    position: absolute; inset: 0; z-index: 5; display: flex; align-items: center; justify-content: center; gap: 10px;
    color: var(--danger); font-size: .9rem; font-weight: 700;
    background: color-mix(in srgb, var(--bg2) 55%, transparent); border-radius: inherit;
}
body.jm-dash .jm-dcb-spinner {
    width: 18px; height: 18px; border: 2px solid var(--danger-border); border-top-color: var(--danger);
    border-radius: 50%; animation: jm-dcb-spin .8s linear infinite;
}
@keyframes jm-dcb-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
    body.jm-dash .jm-dcb-spinner { animation-duration: 2.4s; }
}

/* ---------- Curriculum: undo snackbar + deleted items (trash) drawer (H-B2) ---------- */
/* One snackbar at a time, bottom-centre, clear of the toasts that stack in the bottom end corner. */
body.jm-dash .jm-dcb-snack {
    position: fixed; inset-block-end: 20px; inset-inline: 16px; z-index: 45;
    display: flex; align-items: center; gap: 6px;
    width: fit-content; max-width: min(560px, calc(100vw - 32px)); margin-inline: auto;
    padding: 8px 8px 8px 16px; padding-inline: 16px 8px;
    background: var(--bg2); color: var(--text);
    border: 1px solid var(--border2); border-radius: 14px; box-shadow: var(--shadow);
    font-size: .9rem; line-height: 1.4;
    animation: jm-dcb-snack-in .22s ease-out;
}
body.jm-dash .jm-dcb-snack-text { flex: 1 1 auto; min-width: 0; padding-inline-end: 8px; overflow-wrap: anywhere; }
body.jm-dash .jm-dcb-snack-action {
    flex: none; min-height: 36px; padding: 6px 14px; border-radius: 9px;
    background: transparent; border: 1px solid transparent; color: var(--accent-ink);
    font: inherit; font-weight: 700; cursor: pointer;
}
body.jm-dash .jm-dcb-snack-action:hover { background: var(--card); border-color: var(--border); }
body.jm-dash .jm-dcb-snack-action:disabled { opacity: .6; cursor: progress; }
body.jm-dash .jm-dcb-snack-close {
    flex: none; display: grid; place-items: center; width: 36px; height: 36px; border-radius: 9px;
    background: transparent; border: 0; color: var(--faint); cursor: pointer;
}
body.jm-dash .jm-dcb-snack-close:hover { color: var(--text); background: var(--card); }
body.jm-dash .jm-dcb-snack-close svg { width: 16px; height: 16px; }
body.jm-dash .jm-dcb-snack-action:focus-visible,
body.jm-dash .jm-dcb-snack-close:focus-visible,
body.jm-dash .jm-dcb-trash-panel:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
@keyframes jm-dcb-snack-in { from { opacity: 0; transform: translateY(12px); } to { opacity: 1; transform: none; } }

/* Header trigger: the count rides inside the button and is hidden while the trash is empty. */
body.jm-dash .jm-dcb-trash-count {
    display: inline-flex; align-items: center; justify-content: center;
    min-width: 20px; height: 20px; padding: 0 6px; border-radius: 999px;
    background: var(--danger-soft); border: 1px solid var(--danger-border); color: var(--danger);
    font-size: .72rem; font-weight: 700; line-height: 1;
}
body.jm-dash .jm-dcb-trash [hidden],
body.jm-dash .jm-dcb-trash[hidden],
body.jm-dash .jm-dcb-trash-count[hidden] { display: none; }

body.jm-dash.jm-dcb-trash-open { overflow: hidden; }
body.jm-dash .jm-dcb-trash { position: fixed; inset: 0; z-index: 48; display: flex; justify-content: flex-end; }
body.jm-dash .jm-dcb-trash-scrim {
    position: absolute; inset: 0;
    background: color-mix(in srgb, var(--bg) 72%, transparent);
    backdrop-filter: blur(4px); -webkit-backdrop-filter: blur(4px);
}
body.jm-dash .jm-dcb-trash-panel {
    position: relative; display: flex; flex-direction: column;
    width: min(460px, 100%); height: 100%; max-height: 100dvh;
    background: var(--bg2); color: var(--text);
    border-inline-start: 1px solid var(--border); box-shadow: var(--shadow);
    animation: jm-dcb-trash-in .24s ease-out;
}
[dir="rtl"] body.jm-dash .jm-dcb-trash-panel { animation-name: jm-dcb-trash-in-rtl; }
@keyframes jm-dcb-trash-in { from { opacity: 0; transform: translateX(24px); } to { opacity: 1; transform: none; } }
@keyframes jm-dcb-trash-in-rtl { from { opacity: 0; transform: translateX(-24px); } to { opacity: 1; transform: none; } }

body.jm-dash .jm-dcb-trash-top {
    display: flex; align-items: flex-start; justify-content: space-between; gap: 12px;
    padding: 20px 20px 16px; border-bottom: 1px solid var(--border);
}
body.jm-dash .jm-dcb-trash-heading { margin: 0; font-size: 1.15rem; font-weight: 700; color: var(--text); }
body.jm-dash .jm-dcb-trash-hint { margin: 4px 0 0; font-size: .85rem; color: var(--muted); }
body.jm-dash .jm-dcb-trash-body { flex: 1 1 auto; min-height: 0; overflow-y: auto; overscroll-behavior: contain; padding: 16px 20px 24px; }

body.jm-dash .jm-dcb-trash-state {
    display: flex; flex-direction: column; align-items: center; gap: 10px;
    padding: 48px 16px; text-align: center; color: var(--muted); font-size: .9rem;
}
body.jm-dash .jm-dcb-trash-state > svg { width: 40px; height: 40px; color: var(--faint); }
body.jm-dash .jm-dcb-trash-state[role="alert"] > svg { color: var(--danger); }
body.jm-dash .jm-dcb-trash-state h3 { margin: 0; font-size: 1rem; font-weight: 700; color: var(--text); }
body.jm-dash .jm-dcb-trash-state p { margin: 0; }
body.jm-dash .jm-dcb-trash-spinner {
    width: 28px; height: 28px; border-radius: 50%;
    border: 3px solid var(--border); border-top-color: var(--accent);
    animation: jm-dcb-spin .8s linear infinite;
}

body.jm-dash .jm-dcb-trash-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 10px; }
body.jm-dash .jm-dcb-trash-row {
    display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 4px 12px;
    padding: 14px; background: var(--card); border: 1px solid var(--border); border-radius: var(--r-sm);
    transition: opacity .18s, border-color .18s;
}
body.jm-dash .jm-dcb-trash-row:hover { border-color: var(--border2); }
body.jm-dash .jm-dcb-trash-row.is-busy { opacity: .6; }
body.jm-dash .jm-dcb-trash-icon {
    display: grid; place-items: center; width: 34px; height: 34px; border-radius: 10px;
    background: var(--card2); color: var(--muted);
}
body.jm-dash .jm-dcb-trash-icon svg { width: 17px; height: 17px; }
body.jm-dash .jm-dcb-trash-main { min-width: 0; }
body.jm-dash .jm-dcb-trash-head { display: flex; align-items: center; flex-wrap: wrap; gap: 6px 8px; }
body.jm-dash .jm-dcb-trash-title { font-weight: 700; font-size: .95rem; color: var(--text); overflow-wrap: anywhere; }
body.jm-dash .jm-dcb-trash-meta { margin: 3px 0 0; font-size: .8rem; color: var(--muted); overflow-wrap: anywhere; }
body.jm-dash .jm-dcb-trash-actions { grid-column: 2; display: flex; flex-wrap: wrap; gap: 8px; margin-block-start: 8px; }
body.jm-dash .jm-dcb-trash-actions .jm-btn[aria-busy="true"] { cursor: progress; }

@media (max-width: 639px) {
    body.jm-dash .jm-dcb-trash-top { padding: 16px 16px 12px; }
    body.jm-dash .jm-dcb-trash-body { padding: 12px 16px 20px; }
}
@media (prefers-reduced-motion: reduce) {
    body.jm-dash .jm-dcb-snack,
    body.jm-dash .jm-dcb-trash-panel { animation: none; }
    body.jm-dash .jm-dcb-trash-row { transition: none; }
    body.jm-dash .jm-dcb-trash-spinner { animation-duration: 2.4s; }
}

/* ---------- Change history (H-A2: fragments/history.html + history-list.js) ----------
   A filter bar over one timeline surface. The rail and its dot carry the meaning of the action
   (green = something came into being, red = something was taken away, amber = everything else),
   so the sentence beside it can stay plain text. Logical properties throughout: the rail sits on
   the inline-start edge in both directions. */
body.jm-dash .jm-hist { display: flex; flex-direction: column; gap: 14px; max-width: 980px; }
body.jm-dash .jm-hist-filters {
    display: grid; grid-template-columns: 1fr; gap: 12px 14px; align-items: end;
    background: var(--card); border: 1px solid var(--border); border-radius: var(--r); padding: 16px;
}
@media (min-width: 560px) { body.jm-dash .jm-hist-filters { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 1100px) { body.jm-dash .jm-hist-filters { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
body.jm-dash .jm-hist-field { display: flex; flex-direction: column; gap: 5px; min-width: 0; }
body.jm-dash .jm-hist-field .jm-label { font-size: .8rem; color: var(--muted); }
body.jm-dash .jm-hist-field .jm-input,
body.jm-dash .jm-hist-field .jm-select { padding: 8px 11px; font-size: .88rem; min-height: 38px; }
body.jm-dash .jm-hist-field .jm-select { padding-inline-end: 34px; }
body.jm-dash .jm-hist-dates { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 5px 10px; }
body.jm-dash .jm-hist-dates .jm-field-error { grid-column: 1 / -1; }
@media (min-width: 560px) { body.jm-dash .jm-hist-dates { grid-column: span 2; } }
body.jm-dash .jm-hist-reset { justify-self: start; }
@media (min-width: 1100px) { body.jm-dash .jm-hist-reset { grid-column: 4; justify-self: end; } }

body.jm-dash .jm-hist-bar { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: 4px 16px; }
body.jm-dash .jm-hist-hint { margin: 0; color: var(--muted); font-size: .85rem; max-width: 62ch; }
body.jm-dash .jm-hist-status { margin: 0; color: var(--faint); font-size: .82rem; font-variant-numeric: tabular-nums; }
body.jm-dash .jm-hist-status:focus { outline: none; }

body.jm-dash .jm-hist-list {
    list-style: none; margin: 0; padding: 0;
    background: var(--card); border: 1px solid var(--border); border-radius: var(--r);
}
body.jm-dash .jm-hist-list:empty { display: none; }
body.jm-dash .jm-hist-item {
    position: relative; padding-block: 16px; padding-inline: 44px 18px;
    --jm-hist-tone: var(--accent); --jm-hist-tone-soft: var(--warn-soft);
}
body.jm-dash .jm-hist-item + .jm-hist-item { border-top: 1px solid var(--border); }
body.jm-dash .jm-hist-item--ok { --jm-hist-tone: var(--success); --jm-hist-tone-soft: var(--success-soft); }
body.jm-dash .jm-hist-item--bad { --jm-hist-tone: var(--danger); --jm-hist-tone-soft: var(--danger-soft); }
/* the rail: one line per item, so it runs unbroken down the surface */
body.jm-dash .jm-hist-item::before {
    content: ""; position: absolute; inset-block: 0; inset-inline-start: 21px; width: 2px; background: var(--border);
}
body.jm-dash .jm-hist-item:first-child::before { inset-block-start: 22px; }
body.jm-dash .jm-hist-item:last-child::before { inset-block-end: calc(100% - 22px); }
body.jm-dash .jm-hist-dot {
    position: absolute; inset-block-start: 20px; inset-inline-start: 16px; width: 12px; height: 12px; border-radius: 50%;
    background: var(--jm-hist-tone); box-shadow: 0 0 0 4px var(--card), 0 0 0 5px var(--jm-hist-tone-soft);
}
body.jm-dash .jm-hist-item.is-reverted .jm-hist-dot { background: var(--card); border: 2px solid var(--faint); box-shadow: 0 0 0 4px var(--card); }

body.jm-dash .jm-hist-row { display: flex; flex-wrap: wrap; align-items: flex-start; gap: 8px 14px; }
body.jm-dash .jm-hist-what {
    flex: 1 1 240px; min-width: 0; margin: 0; color: var(--text); font-size: .95rem; line-height: 1.5; overflow-wrap: anywhere;
}
body.jm-dash .jm-hist-what strong { font-weight: 700; }
body.jm-dash .jm-hist-item.is-reverted .jm-hist-what { color: var(--muted); }
body.jm-dash .jm-hist-actions { display: flex; align-items: center; gap: 8px; margin-inline-start: auto; }
body.jm-dash .jm-hist-undo[aria-busy="true"] { cursor: progress; }
body.jm-dash .jm-hist-undo svg { width: 14px; height: 14px; }
[dir="rtl"] body.jm-dash .jm-hist-undo svg { transform: scaleX(-1); }

body.jm-dash .jm-hist-meta {
    display: flex; flex-wrap: wrap; align-items: center; gap: 2px 14px; margin-top: 4px;
    color: var(--faint); font-size: .82rem;
}
body.jm-dash .jm-hist-actor { color: var(--muted); overflow-wrap: anywhere; }
body.jm-dash .jm-hist-time { font-variant-numeric: tabular-nums; }
body.jm-dash .jm-hist-course { color: var(--accent-ink); font-weight: 700; text-decoration: none; overflow-wrap: anywhere; }
body.jm-dash .jm-hist-course:hover { text-decoration: underline; }

body.jm-dash .jm-hist-toggle {
    display: inline-flex; align-items: center; gap: 5px; margin-top: 8px; padding: 3px 0;
    background: none; border: 0; color: var(--accent-ink); font: inherit; font-size: .82rem; font-weight: 700; cursor: pointer;
}
body.jm-dash .jm-hist-toggle:hover { text-decoration: underline; }
body.jm-dash .jm-hist-toggle svg { width: 13px; height: 13px; transition: transform .18s; }
body.jm-dash .jm-hist-toggle[aria-expanded="true"] svg { transform: rotate(180deg); }
body.jm-dash .jm-hist-toggle:focus-visible,
body.jm-dash .jm-hist-course:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 4px; }

body.jm-dash .jm-hist-details {
    margin-top: 8px; padding: 12px 14px; background: var(--bg2); border: 1px solid var(--border); border-radius: var(--r-sm);
}
body.jm-dash .jm-hist-details[hidden] { display: none; }
body.jm-dash .jm-hist-note { margin: 0; color: var(--muted); font-size: .86rem; white-space: pre-wrap; overflow-wrap: anywhere; }
body.jm-dash .jm-hist-note + .jm-hist-changes { margin-top: 10px; }
body.jm-dash .jm-hist-changes { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 10px; }
body.jm-dash .jm-hist-change { display: grid; grid-template-columns: 1fr; gap: 4px 14px; align-items: start; }
@media (min-width: 720px) { body.jm-dash .jm-hist-change { grid-template-columns: minmax(110px, 190px) minmax(0, 1fr); } }
body.jm-dash .jm-hist-key {
    justify-self: start; max-width: 100%; padding: 2px 7px; direction: ltr; unicode-bidi: isolate;
    font-family: var(--mono); font-size: .76rem; color: var(--muted); overflow-wrap: anywhere;
    background: var(--code-bg); border: 1px solid var(--code-border); border-radius: 6px;
}
body.jm-dash .jm-hist-vals { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 8px; min-width: 0; font-size: .86rem; }
body.jm-dash .jm-hist-before,
body.jm-dash .jm-hist-after {
    min-width: 0; max-height: 9.5em; overflow: auto; white-space: pre-wrap; overflow-wrap: anywhere; unicode-bidi: plaintext;
}
body.jm-dash .jm-hist-before { color: var(--faint); text-decoration: line-through; text-decoration-color: var(--danger); }
body.jm-dash .jm-hist-after { color: var(--text); text-decoration: none; }
body.jm-dash .jm-hist-arrow { flex: none; color: var(--faint); }
[dir="rtl"] body.jm-dash .jm-hist-arrow { transform: scaleX(-1); }
body.jm-dash .jm-hist-none { font-style: italic; color: var(--faint); text-decoration: none; }

body.jm-dash .jm-hist-state:empty { display: none; }
body.jm-dash .jm-hist-state .jm-btn { margin-top: 14px; }
body.jm-dash .jm-hist-skel {
    background: var(--card); border: 1px solid var(--border); border-radius: var(--r); padding: 6px 18px;
}
body.jm-dash .jm-hist-skel-row { padding-block: 14px; display: flex; flex-direction: column; gap: 9px; }
body.jm-dash .jm-hist-skel-row + .jm-hist-skel-row { border-top: 1px solid var(--border); }
body.jm-dash .jm-hist-skel-line {
    display: block; height: 11px; width: 58%; border-radius: 6px; background: var(--card2);
    animation: jm-hist-pulse 1.3s ease-in-out infinite;
}
body.jm-dash .jm-hist-skel-line--short { width: 26%; height: 9px; }
@keyframes jm-hist-pulse { 50% { opacity: .45; } }
body.jm-dash .jm-hist-more { display: flex; justify-content: center; }
body.jm-dash .jm-hist-more[hidden] { display: none; }
@media (prefers-reduced-motion: reduce) {
    body.jm-dash .jm-hist-skel-line { animation: none; }
    body.jm-dash .jm-hist-toggle svg { transition: none; }
}
body.jm-dash .jm-hist-reverted { cursor: help; white-space: nowrap; }
body.jm-dash .jm-hist-field .jm-input,
body.jm-dash .jm-hist-field .jm-select { box-sizing: border-box; }

/* Curriculum trash: "Delete permanently" sits at the far end of a row's actions, away from Restore. */
body.jm-dash .jm-dcb-trash-purge { margin-inline-start: auto; }

/* Curriculum: batch upload progress drawn under a section's lectures (JmBatchProgress). */
body.jm-dash .jm-dcb-uploading { margin: 0 20px 12px; padding: 12px 14px; background: var(--card); border: 1px dashed var(--border2); border-radius: var(--r-sm); }
body.jm-dash .jm-dcb-uploading-title { margin: 0 0 10px; color: var(--accent-ink); font-size: .84rem; font-weight: 700; }
body.jm-dash .jm-dcb-uploading-head { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-bottom: 10px; }
body.jm-dash .jm-dcb-uploading-head .jm-dcb-uploading-title { flex: 1 1 auto; margin: 0; }
body.jm-dash .jm-dcb-uploading.is-failed { border-style: solid; border-color: var(--danger-border); background: var(--danger-soft); }
body.jm-dash .jm-dcb-uploading.is-failed .jm-dcb-uploading-title { color: var(--danger); }
body.jm-dash .jm-dcb-uprow-retry { flex: none; }
body.jm-dash .jm-dcb-uprow-retry[hidden] { display: none; }
body.jm-dash .jm-dcb-uprow-top { align-items: center; }
body.jm-dash .jm-dcb-uprow { padding: 6px 0; }
body.jm-dash .jm-dcb-uprow + .jm-dcb-uprow { border-top: 1px solid var(--border); }
body.jm-dash .jm-dcb-uprow-top { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; margin-bottom: 5px; font-size: .86rem; }
body.jm-dash .jm-dcb-uprow-title { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 600; color: var(--text); }
body.jm-dash .jm-dcb-uprow-status { flex: none; color: var(--muted); font-size: .8rem; font-variant-numeric: tabular-nums; }
body.jm-dash .jm-dcb-uprow .jm-progress { height: 6px; }
body.jm-dash .jm-dcb-uprow .jm-progress > span { width: 0; transition: width .2s linear; }
body.jm-dash .jm-dcb-uprow.is-queued .jm-dcb-uprow-title { color: var(--muted); }
body.jm-dash .jm-dcb-uprow.is-success .jm-dcb-uprow-status { color: var(--success); font-weight: 700; }
body.jm-dash .jm-dcb-uprow.is-success .jm-progress > span { background: var(--success); }
body.jm-dash .jm-dcb-uprow.is-error .jm-dcb-uprow-status { color: var(--danger); font-weight: 700; }
body.jm-dash .jm-dcb-uprow.is-error .jm-progress > span { width: 100% !important; background: var(--danger); }
@media (prefers-reduced-motion: reduce) {
    body.jm-dash .jm-dcb-uprow .jm-progress > span { transition: none; }
}

/* Curriculum: skeleton cards shown until the sections arrive (first visit in a tab). */
body.jm-dash .jm-dcb-skeleton { display: grid; gap: 12px; padding: 20px 24px; }
body.jm-dash .jm-dcb-skeleton-line {
    display: block; height: 14px; border-radius: 7px;
    background: linear-gradient(90deg, var(--card) 25%, var(--card2) 37%, var(--card) 63%);
    background-size: 400% 100%; animation: jm-dcb-shimmer 1.4s ease infinite;
}
body.jm-dash .jm-dcb-skeleton-line--head { width: 42%; height: 18px; }
body.jm-dash .jm-dcb-skeleton-line:nth-child(3) { width: 86%; }
body.jm-dash .jm-dcb-skeleton-line:nth-child(4) { width: 68%; }
@keyframes jm-dcb-shimmer { 0% { background-position: 100% 50%; } 100% { background-position: 0 50%; } }
@media (prefers-reduced-motion: reduce) {
    body.jm-dash .jm-dcb-skeleton-line { animation: none; }
}
/* While a cached copy is being refreshed, the list is marked busy but stays fully usable. */
body.jm-dash #sections-container[aria-busy="true"] { cursor: progress; }

/* Quick link from a form field to the settings that control it; and the card such a link lands on. */
body.jm-dash .jm-quicklink { display: inline-flex; align-items: center; gap: 6px; width: fit-content; font-size: .84rem; font-weight: 700; }
body.jm-dash .jm-quicklink svg { flex: none; width: 15px; height: 15px; }
body.jm-dash .jm-deeplink-target { outline: 2px solid var(--accent); outline-offset: 3px; scroll-margin-top: 90px; }

/* ============================================================
   Dashboard — My profile (dashboard/profile/index.html)
   ============================================================ */
body.jm-dash .jm-dprofile { display: grid; gap: 22px; max-width: 760px; }
body.jm-dash .jm-dprofile-photo { display: flex; flex-wrap: wrap; align-items: center; gap: 20px; }
body.jm-dash .jm-dprofile-avatar {
    display: grid; place-items: center; flex: none; width: 96px; height: 96px; overflow: hidden;
    border-radius: 50%; background: var(--card2); border: 1px solid var(--border);
    color: var(--accent-ink); font-size: 2.2rem; font-weight: 700; transition: opacity .2s;
}
body.jm-dash .jm-dprofile-avatar img { width: 100%; height: 100%; object-fit: cover; }
body.jm-dash .jm-dprofile-avatar.is-busy { opacity: .55; }
body.jm-dash .jm-dprofile-photo-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; min-width: 0; flex: 1 1 260px; }
body.jm-dash .jm-dprofile-photo-actions .jm-help, body.jm-dash .jm-dprofile-photo-actions .jm-field-error { flex-basis: 100%; margin: 0; }
body.jm-dash .jm-dprofile-photo-actions label.jm-btn { cursor: pointer; }
body.jm-dash .jm-dprofile-photo-actions input:focus-visible + .jm-btn,
body.jm-dash #profile-photo-input:focus-visible ~ #profile-photo-remove { outline: none; }
body.jm-dash .jm-dprofile-photo-actions:has(#profile-photo-input:focus-visible) label.jm-btn { outline: 2px solid var(--accent); outline-offset: 2px; }
body.jm-dash .jm-dprofile-pw { display: flex; align-items: center; gap: 8px; }
body.jm-dash .jm-dprofile-pw .jm-input { flex: 1; min-width: 0; }
body.jm-dash .jm-dprofile-pw .jm-btn { flex: none; }

/* ---------- community: "Public community" switch ----------
   dashboard/community/index.html #community-public-setting. Text on the
   start side, state label + .jm-dswitch on the end side; stacks on phones. */
body.jm-dash .jm-dcomm-public {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 16px;
    margin-bottom: 20px;
}
body.jm-dash .jm-dcomm-public-text { min-width: 0; }
body.jm-dash .jm-dcomm-public-title { font-size: .95rem; font-weight: 700; color: var(--text); margin: 0; }
body.jm-dash .jm-dcomm-public-help { color: var(--muted); font-size: .85rem; margin: 4px 0 8px; max-width: 62ch; }
body.jm-dash .jm-dcomm-public-link { font-size: .85rem; font-weight: 700; }
body.jm-dash .jm-dcomm-public-control { display: flex; align-items: center; gap: 10px; flex: none; }
body.jm-dash .jm-dcomm-public-state { color: var(--muted); font-size: .8rem; font-weight: 700; white-space: nowrap; }
body.jm-dash .jm-dswitch[aria-busy="true"] { opacity: .6; cursor: progress; }
body.jm-dash .jm-dswitch:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
@media (max-width: 560px) {
    body.jm-dash .jm-dcomm-public { flex-direction: column; }
}
@media (prefers-reduced-motion: reduce) {
    body.jm-dash .jm-dswitch,
    body.jm-dash .jm-dswitch-knob { transition: none; }
}

/* ---------- community: "Community permissions" card ----------
   dashboard/community/index.html #community-permissions. One row per
   switch, same text/control split as the public switch above it. */
body.jm-dash .jm-dcomm-perms { margin-bottom: 20px; }
body.jm-dash .jm-dcomm-perm-list { list-style: none; margin: 12px 0 0; padding: 0; }
body.jm-dash .jm-dcomm-perm-row {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 16px;
    padding: 12px 0;
    border-top: 1px solid var(--border);
}
body.jm-dash .jm-dcomm-perm-label { font-size: .9rem; font-weight: 700; color: var(--text); margin: 0; }
body.jm-dash .jm-dcomm-perm-help { color: var(--muted); font-size: .82rem; margin: 2px 0 0; max-width: 62ch; }
body.jm-dash .jm-dcomm-perm-note { color: var(--accent-ink); }
body.jm-dash .jm-dcomm-perm-note.hidden { display: none; }
@media (max-width: 560px) {
    body.jm-dash .jm-dcomm-perm-row { flex-direction: column; gap: 8px; }
}

/* ── Curriculum: "Import from another course" dialog (curriculum-import.js) ── */
html.jm-dci-lock { overflow: hidden; }
body.jm-dash .jm-dci-panel { display: flex; flex-direction: column; padding: 0; overflow: hidden; }
body.jm-dash .jm-dci-head { align-items: flex-start; margin: 0; padding: 22px 24px 16px; border-bottom: 1px solid var(--border); }
body.jm-dash .jm-dci-headtext { flex: 1; min-width: 0; }
body.jm-dash .jm-dci-lead { margin: 4px 0 0; color: var(--muted); font-size: .92rem; }
body.jm-dash .jm-dci-body { flex: 1; min-height: 260px; overflow-y: auto; padding: 18px 24px; }
body.jm-dash .jm-dci-search { margin-bottom: 12px; }
body.jm-dash .jm-dci-courses { display: grid; gap: 6px; margin: 0; padding: 0; list-style: none; }
body.jm-dash .jm-dci-course { display: flex; align-items: center; justify-content: space-between; gap: 12px; width: 100%; padding: 12px 14px; border: 1px solid var(--border); border-radius: var(--r-sm); background: var(--card); color: var(--text); font: inherit; text-align: start; cursor: pointer; transition: border-color .15s, background .15s; }
body.jm-dash .jm-dci-course:hover:not(:disabled), body.jm-dash .jm-dci-course:focus-visible { border-color: var(--accent); background: var(--card2); outline: none; }
body.jm-dash .jm-dci-course:disabled { opacity: .55; cursor: not-allowed; }
body.jm-dash .jm-dci-course-title { flex: 1; min-width: 0; font-weight: 700; overflow-wrap: anywhere; }
body.jm-dash .jm-dci-course-meta { flex: none; color: var(--muted); font-size: .85rem; }
body.jm-dash .jm-dci-none { margin: 18px 0; color: var(--muted); text-align: center; }
body.jm-dash .jm-dci-none[hidden] { display: none; }
body.jm-dash .jm-dci-bar { display: flex; flex-wrap: wrap; align-items: center; gap: 10px 14px; margin-bottom: 16px; }
body.jm-dash .jm-dci-back svg { width: 14px; height: 14px; }
[dir="rtl"] body.jm-dash .jm-dci-back svg { transform: scaleX(-1); }
body.jm-dash .jm-dci-source { min-width: 0; color: var(--text); overflow-wrap: anywhere; }
body.jm-dash .jm-dci-dest { margin-bottom: 16px; }
body.jm-dash .jm-dci-all { margin-bottom: 10px; font-weight: 700; color: var(--text); }
body.jm-dash .jm-dci-tree { padding: 14px; border: 1px solid var(--border); border-radius: var(--r-sm); background: var(--card); }
body.jm-dash .jm-dci-tree.is-invalid { border-color: var(--danger); box-shadow: 0 0 0 4px var(--danger-soft); }
body.jm-dash .jm-dci-group { margin: 0 0 14px; padding: 0; border: 0; min-width: 0; }
body.jm-dash .jm-dci-group:last-child { margin-bottom: 0; }
body.jm-dash .jm-dci-legend { padding: 0; font-weight: 700; color: var(--text); }
body.jm-dash .jm-dci-legend .jm-check { color: var(--text); }
body.jm-dash .jm-dci-items { display: grid; gap: 6px; margin-top: 8px; padding-inline-start: 28px; }
body.jm-dash .jm-dci-lecture { align-items: flex-start; }
body.jm-dash .jm-dci-lecture-title { flex: 1; min-width: 0; overflow-wrap: anywhere; }
body.jm-dash .jm-dci-alert { margin: 0 24px 14px; padding: 11px 14px; border: 1px solid var(--danger-border); border-radius: var(--r-sm); background: var(--danger-soft); color: var(--danger); font-size: .9rem; font-weight: 700; }
body.jm-dash .jm-dci-alert[hidden] { display: none; }
body.jm-dash .jm-dci-foot { align-items: center; margin: 0; padding: 14px 24px 18px; border-top: 1px solid var(--border); }
body.jm-dash .jm-dci-status { flex: 1 1 160px; min-width: 0; margin: 0; color: var(--muted); font-size: .88rem; }
body.jm-dash .jm-dci.is-busy .jm-dci-body { opacity: .6; pointer-events: none; }
body.jm-dash .jm-dci-skel { display: grid; gap: 8px; }
body.jm-dash .jm-dci-skel-row { display: block; height: 44px; border-radius: var(--r-sm); background: var(--card2); animation: jm-dci-pulse 1.4s ease-in-out infinite; }
@keyframes jm-dci-pulse { 0%, 100% { opacity: 1; } 50% { opacity: .45; } }
@media (prefers-reduced-motion: reduce) {
    body.jm-dash .jm-dci-skel-row { animation: none; }
    body.jm-dash .jm-dci-course { transition: none; }
}
@media (max-width: 640px) {
    body.jm-dash .jm-dci-head { padding: 16px 16px 14px; }
    body.jm-dash .jm-dci-body { padding: 16px; }
    body.jm-dash .jm-dci-alert { margin-inline: 16px; }
    body.jm-dash .jm-dci-foot { padding: 12px 16px 14px; }
    body.jm-dash .jm-dci-foot .jm-btn { flex: 1 1 auto; justify-content: center; }
    body.jm-dash .jm-dci-items { padding-inline-start: 16px; }
}

/* ── Curriculum: "add section here" / "add lecture here" insert zones ──
   A zone is a fixed-height strip in the gap between two cards. On hover or keyboard focus a
   hairline is drawn across it and a pill appears on top, so the page never shifts. */
body.jm-dash #sections-container > .section-card,
body.jm-dash #sections-container > .jm-dcb-gap { margin-block: 0; }
body.jm-dash .jm-dcb-gap { position: relative; display: flex; align-items: center; justify-content: center; }
body.jm-dash .jm-dcb-gap::before {
    content: "";
    position: absolute;
    inset-inline: 0;
    top: 50%;
    height: 2px;
    border-radius: 2px;
    background: linear-gradient(90deg, transparent, var(--accent) 18%, var(--accent) 82%, transparent);
    opacity: 0;
    transform: scaleX(.6);
    transition: opacity .16s ease, transform .2s ease;
    pointer-events: none;
}
body.jm-dash .jm-dcb-gap-btn {
    position: relative;
    z-index: 1;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 4px 12px 4px 8px;
    border: 1px solid var(--accent);
    border-radius: 999px;
    background: var(--bg2);
    color: var(--accent-ink);
    font: inherit;
    font-size: .78rem;
    font-weight: 700;
    line-height: 1.2;
    white-space: nowrap;
    cursor: pointer;
    box-shadow: 0 4px 14px rgba(249, 161, 27, .22);
    opacity: 0;
    transform: scale(.92);
    transition: opacity .16s ease, transform .16s ease, background .16s ease, color .16s ease;
}
[dir="rtl"] body.jm-dash .jm-dcb-gap-btn { padding: 4px 8px 4px 12px; }
body.jm-dash .jm-dcb-gap-btn svg { width: 14px; height: 14px; flex: none; }
body.jm-dash .jm-dcb-gap-label { display: inline-block; }
body.jm-dash .jm-dcb-gap:hover::before,
body.jm-dash .jm-dcb-gap:focus-within::before { opacity: 1; transform: none; }
body.jm-dash .jm-dcb-gap:hover .jm-dcb-gap-btn,
body.jm-dash .jm-dcb-gap:focus-within .jm-dcb-gap-btn,
body.jm-dash .jm-dcb-gap-btn[aria-busy="true"] { opacity: 1; transform: none; }
body.jm-dash .jm-dcb-gap-btn:hover,
body.jm-dash .jm-dcb-gap-btn:focus-visible { background: var(--accent); color: var(--btn-text); outline: none; }
body.jm-dash .jm-dcb-gap-btn:focus-visible { box-shadow: 0 0 0 4px rgba(249, 161, 27, .28); }
body.jm-dash .jm-dcb-gap-btn[aria-busy="true"] { cursor: progress; }
body.jm-dash .jm-dcb-gap-btn:disabled:not([aria-busy]) { cursor: not-allowed; }

/* Between sections */
body.jm-dash .jm-dcb-gap--section { height: 28px; }
/* The last one is always there: a dashed bar with room under it. */
body.jm-dash .jm-dcb-gap--last { height: auto; margin-block: 14px 56px !important; }
body.jm-dash .jm-dcb-gap--last::before { display: none; }
body.jm-dash .jm-dcb-gap--last .jm-dcb-gap-btn {
    width: 100%;
    justify-content: center;
    padding: 12px 16px;
    border-style: dashed;
    border-color: var(--border2);
    border-radius: var(--r-sm);
    background: transparent;
    color: var(--muted);
    font-size: .88rem;
    box-shadow: none;
    opacity: 1;
    transform: none;
}
body.jm-dash .jm-dcb-gap--last .jm-dcb-gap-btn:hover,
body.jm-dash .jm-dcb-gap--last .jm-dcb-gap-btn:focus-visible {
    border-style: solid;
    border-color: var(--accent);
    background: rgba(249, 161, 27, .1);
    color: var(--accent-ink);
}

/* Between lectures: the zone belongs to the card under it and covers the 12px gap above that card. */
body.jm-dash .jm-dcb-lecture { position: relative; }
body.jm-dash .jm-dcb-gap--lecture { position: absolute; inset-inline: 0; top: -15px; height: 18px; z-index: 2; }
body.jm-dash .jm-dcb-gap--lecture .jm-dcb-gap-btn { font-size: .74rem; padding-block: 3px; }
/* After the last lecture: a strip of its own under the list, with room around it. */
body.jm-dash .jm-dcb-gap--lecture.jm-dcb-gap--tail { position: relative; inset: auto; top: auto; height: 30px; margin: 2px 20px 12px; }
/* Hovering (or tabbing into) a zone opens the gap up, so the pill gets room of its own instead of
   sitting on the cards. The zone grows with the gap, so the pointer never falls out of it. */
body.jm-dash .jm-dcb-gap--section { transition: height .18s ease; }
body.jm-dash .jm-dcb-gap--section:not(.jm-dcb-gap--last):hover,
body.jm-dash .jm-dcb-gap--section:not(.jm-dcb-gap--last):focus-within { height: 52px; }
body.jm-dash .jm-dcb-lecture { transition: border-color .2s, box-shadow .2s, margin-top .18s ease; }
body.jm-dash .lectures-list > .jm-dcb-lecture:has(> .jm-dcb-gap--lecture:hover),
body.jm-dash .lectures-list > .jm-dcb-lecture:has(> .jm-dcb-gap--lecture:focus-within) { margin-top: 36px !important; }
body.jm-dash .lectures-list > .jm-dcb-lecture:first-child:has(> .jm-dcb-gap--lecture:hover),
body.jm-dash .lectures-list > .jm-dcb-lecture:first-child:has(> .jm-dcb-gap--lecture:focus-within) { margin-top: 24px !important; }
body.jm-dash .jm-dcb-lecture > .jm-dcb-gap--lecture:hover,
body.jm-dash .jm-dcb-lecture > .jm-dcb-gap--lecture:focus-within { top: -39px; height: 42px; }
body.jm-dash .jm-dcb-gap--lecture.jm-dcb-gap--tail { transition: height .18s ease; }
body.jm-dash .jm-dcb-gap--lecture.jm-dcb-gap--tail:hover,
body.jm-dash .jm-dcb-gap--lecture.jm-dcb-gap--tail:focus-within { height: 48px; }
@media (prefers-reduced-motion: reduce) {
    body.jm-dash .jm-dcb-gap--section,
    body.jm-dash .jm-dcb-lecture,
    body.jm-dash .jm-dcb-gap--lecture.jm-dcb-gap--tail { transition: none; }
}

/* While a card is being dragged the zones would only get in the way. */
body.jm-dash .sortable-chosen .jm-dcb-gap--lecture,
body.jm-dash .sortable-ghost .jm-dcb-gap--lecture { display: none; }

/* The form that opens at the chosen position */
body.jm-dash .jm-dcb-insertform {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    gap: 10px;
    padding: 12px;
    border: 1px dashed var(--accent);
    border-radius: var(--r-sm);
    background: rgba(249, 161, 27, .08);
    animation: jm-dcb-insert-in .18s ease-out;
}
body.jm-dash .jm-dcb-insertform[aria-busy="true"] { opacity: .7; cursor: progress; }
body.jm-dash .jm-dcb-insertform-types { display: inline-flex; gap: 4px; padding: 4px; border: 1px solid var(--border); border-radius: var(--r-sm); background: var(--card); }
body.jm-dash .jm-dcb-insertform-type { position: relative; cursor: pointer; }
body.jm-dash .jm-dcb-insertform-type input { position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; opacity: 0; cursor: pointer; }
body.jm-dash .jm-dcb-insertform-type span { display: block; padding: 6px 12px; border-radius: 8px; color: var(--muted); font-size: .84rem; font-weight: 700; transition: background .16s, color .16s; }
body.jm-dash .jm-dcb-insertform-type:hover span { color: var(--text); }
body.jm-dash .jm-dcb-insertform-type input:checked + span { background: var(--accent); color: var(--btn-text); }
body.jm-dash .jm-dcb-insertform-type input:focus-visible + span { box-shadow: 0 0 0 3px rgba(249, 161, 27, .35); }
body.jm-dash .jm-dcb-insertform-field { flex: 1 1 220px; min-width: 0; }
body.jm-dash .jm-dcb-insertform-field .jm-field-error:empty { display: none; }
body.jm-dash .jm-dcb-insertform-actions { display: flex; gap: 8px; align-items: center; padding-top: 3px; }
@keyframes jm-dcb-insert-in { from { opacity: 0; transform: translateY(-4px); } to { opacity: 1; transform: none; } }

/* Touch screens have no hover: keep the pills faintly visible so they can be tapped. */
@media (hover: none) {
    body.jm-dash .jm-dcb-gap-btn { opacity: .75; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
    body.jm-dash .jm-dcb-gap::before,
    body.jm-dash .jm-dcb-gap-btn { transition: none; }
    body.jm-dash .jm-dcb-insertform { animation: none; }
}
@media (max-width: 640px) {
    body.jm-dash .jm-dcb-insertform-actions { width: 100%; justify-content: flex-end; }
}

/* ── Curriculum: "video is still being encoded" chip next to a lecture title ── */
body.jm-dash .jm-dcb-vstate { display: inline-flex; align-items: center; gap: 6px; white-space: nowrap; font-variant-numeric: tabular-nums; }
body.jm-dash .jm-dcb-vstate-text { display: inline-block; }
body.jm-dash .jm-dcb-vstate-spin { width: 11px; height: 11px; flex: none; border-radius: 50%; border: 2px solid currentColor; border-inline-end-color: transparent; opacity: .8; animation: jm-spin .9s linear infinite; }
body.jm-dash .jm-dcb-vstate.is-failed .jm-dcb-vstate-spin { display: none; }
@media (prefers-reduced-motion: reduce) {
    body.jm-dash .jm-dcb-vstate-spin { animation: none; border-inline-end-color: currentColor; opacity: .5; }
}

/* ============================================================
   Video usage (dashboard/monitoring/bunny.html)
   Bunny balance, charges and traffic. The balance is the one large
   figure on the page; everything else uses the shared KPI/card kit.
   ============================================================ */
body.jm-dash .jm-dbn { display: grid; gap: 22px; }
body.jm-dash .jm-dbn > .jm-dgrid { margin: 0; }
body.jm-dash .jm-dbn-money { display: grid; gap: 22px; grid-template-columns: minmax(0, 1fr); }
@media (min-width: 1024px) {
    body.jm-dash .jm-dbn-money { grid-template-columns: minmax(0, 5fr) minmax(0, 4fr); }
}
body.jm-dash .jm-dbn-balance { display: flex; flex-direction: column; align-items: flex-start; }
body.jm-dash .jm-dbn-balance > .flex { align-self: stretch; }
body.jm-dash .jm-dbn-figure {
    margin: 14px 0 6px;
    font-size: clamp(2.6rem, 7vw, 4.2rem);
    font-weight: 700;
    line-height: 1;
    letter-spacing: -.03em;
    color: var(--text);
    font-variant-numeric: tabular-nums;
}
html[lang="ar"] body.jm-dash .jm-dbn-figure { letter-spacing: 0; }
body.jm-dash .jm-dbn-runway { margin: 0; color: var(--muted); font-size: 1rem; min-height: 1.5em; }
body.jm-dash .jm-dbn-meta { margin: 10px 0 0; display: flex; flex-wrap: wrap; gap: 6px 16px; color: var(--faint); font-size: .86rem; }
body.jm-dash .jm-dbn-link { margin-top: auto; padding-top: 18px; font-weight: 700; font-size: .92rem; }
/* Low balance: the whole panel takes the warning tint and the sentence carries the reason. */
body.jm-dash .jm-dbn-balance.is-low { background: var(--warn-soft); border-color: var(--warn-border); }
body.jm-dash .jm-dbn-balance.is-low .jm-dbn-runway { color: var(--warn); font-weight: 700; }
body.jm-dash .jm-dbn-charges { margin-top: 8px; }
body.jm-dash .jm-dbn-charges-empty { margin: 12px 0; color: var(--muted); font-size: .9rem; }
body.jm-dash .jm-dbn-scope { margin: -10px 0 0; }
body.jm-dash .jm-dbn-scope:empty { display: none; }
body.jm-dash .jm-dbn-setup-text { margin: 6px 0 14px; max-width: 68ch; }
body.jm-dash .jm-dbn-subtitle { margin: 22px 0 10px; font-size: .9rem; font-weight: 700; color: var(--text); }
body.jm-dash .jm-dbn-countries { list-style: none; margin: 0; padding: 0; display: grid; gap: 10px; }
body.jm-dash .jm-dbn-country { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 4px 12px; font-size: .9rem; color: var(--text); }
body.jm-dash .jm-dbn-country > .jm-progress { grid-column: 1 / -1; }
/* The fill grows from the reading-start edge in both directions. */
body.jm-dash .jm-dbn-country > .jm-progress > span { margin-inline: 0 auto; }
body.jm-dash .jm-dbn-country-count { color: var(--muted); font-weight: 700; font-variant-numeric: tabular-nums; }
body.jm-dash .jm-dbn-countries-empty { color: var(--muted); font-size: .9rem; }
body.jm-dash .jm-dbn-links { list-style: none; margin: 20px 0 0; padding: 16px 0 0; border-top: 1px solid var(--border); display: grid; gap: 8px; font-size: .9rem; font-weight: 700; }
/* Summary card on the dashboard home (dashboard/index.html): four figures and a way in. */
body.jm-dash .jm-dbn-home.is-low { background: var(--warn-soft); border-color: var(--warn-border); }
body.jm-dash .jm-dbn-home.is-low .jm-dbn-runway { color: var(--warn); font-weight: 700; }
body.jm-dash .jm-dbn-home-link { font-weight: 700; font-size: .9rem; }
body.jm-dash .jm-dbn-home-figures { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px 24px; margin: 18px 0 12px; }
@media (min-width: 1024px) {
    body.jm-dash .jm-dbn-home-figures { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}
body.jm-dash .jm-dbn-home-figures dt { color: var(--muted); font-size: .82rem; font-weight: 700; margin: 0 0 4px; }
body.jm-dash .jm-dbn-home-figures dd { margin: 0; color: var(--text); font-size: 1.5rem; font-weight: 700; line-height: 1.15; font-variant-numeric: tabular-nums; }
body.jm-dash .jm-dbn-home .jm-dbn-runway:empty { display: none; }
body.jm-dash .jm-dbn-processing { list-style: none; margin: 16px 0 0; padding: 0; display: grid; gap: 10px; }
body.jm-dash .jm-dbn-collections { margin-top: 16px; }
body.jm-dash .jm-dbn .is-unavailable .jm-dbn-processing,
body.jm-dash .jm-dbn .is-unavailable .jm-dbn-collections { display: none; }
body.jm-dash #bunny-videos.has-failed [data-bn="failed"] { color: var(--danger); }
/* A figure that has not arrived yet: a shimmer bar where the number will be. */
body.jm-dash .jm-dbn-val.is-loading {
    display: inline-block; min-width: 4.5ch; border-radius: 7px; color: transparent; user-select: none;
    background: linear-gradient(90deg, var(--card) 25%, var(--card2) 37%, var(--card) 63%);
    background-size: 400% 100%; animation: jm-dcb-shimmer 1.4s ease infinite;
}
body.jm-dash .jm-dbn[aria-busy="true"] .jm-dchart { opacity: .55; }
/* A block that did not load shows its note in place of the chart and list. */
body.jm-dash .jm-dbn .is-unavailable .jm-dchart,
body.jm-dash .jm-dbn .is-unavailable .jm-dbn-subtitle,
body.jm-dash .jm-dbn .is-unavailable .jm-dbn-countries { display: none; }
@media (prefers-reduced-motion: reduce) {
    body.jm-dash .jm-dbn-val.is-loading { animation: none; }
}

/* ============================================================
   Video management (dashboard/videos/*.html)
   A tab bar shared by the library and the provider pages, and the
   library list itself. Provider figures reuse the .jm-dbn-* kit.
   ============================================================ */
body.jm-dash .jm-dvm-tabs { margin: 0 0 22px; }
body.jm-dash .jm-dvm-toolbar {
    display: grid; grid-template-columns: minmax(0, 1fr); gap: 14px 18px; align-items: end;
    padding: 20px 24px; border-bottom: 1px solid var(--border);
}
@media (min-width: 768px) {
    body.jm-dash .jm-dvm-toolbar { grid-template-columns: minmax(0, 2fr) minmax(0, 1fr) auto; }
}
body.jm-dash .jm-dvm-field { display: grid; gap: 6px; min-width: 0; }
body.jm-dash .jm-dvm-field .jm-field-error { margin: 0; }
body.jm-dash .jm-dvm-field--narrow { max-width: 22rem; }
body.jm-dash .jm-dvm-count { margin: 0; padding-bottom: 12px; white-space: nowrap; font-variant-numeric: tabular-nums; }
body.jm-dash .jm-dvm-table td { vertical-align: middle; }
body.jm-dash .jm-dvm-video { display: flex; align-items: center; gap: 12px; min-width: 240px; }
body.jm-dash .jm-dvm-thumb {
    flex: none; width: 96px; height: 54px; border-radius: 8px; overflow: hidden;
    background: var(--card2); border: 1px solid var(--border);
}
body.jm-dash .jm-dvm-thumb img { display: block; width: 100%; height: 100%; object-fit: cover; }
body.jm-dash .jm-dvm-video-text { display: grid; gap: 2px; min-width: 0; }
body.jm-dash .jm-dvm-title { color: var(--text); font-weight: 700; overflow-wrap: anywhere; }
body.jm-dash .jm-dvm-meta { display: block; color: var(--faint); font-size: .82rem; }
body.jm-dash .jm-dvm-unused { color: var(--faint); }
body.jm-dash .jm-dvm-actions { display: flex; gap: 6px; justify-content: flex-end; flex-wrap: wrap; }
/* A row whose delete is on its way: dimmed until the server answers. */
body.jm-dash .jm-dvm-table tr.is-leaving { opacity: .45; }
body.jm-dash .jm-dvm-table tr[aria-busy="true"] { cursor: progress; }
body.jm-dash .jm-dvm-message { margin: 0; padding: 34px 24px; text-align: center; color: var(--muted); }
body.jm-dash .jm-dvm-pager {
    display: flex; align-items: center; justify-content: space-between; gap: 12px;
    padding: 14px 24px; border-top: 1px solid var(--border);
}
body.jm-dash .jm-dvm-dialog {
    width: min(460px, calc(100vw - 32px)); padding: 24px; border-radius: var(--r);
    border: 1px solid var(--border2); background: var(--bg2); color: var(--text); box-shadow: var(--shadow);
}
body.jm-dash .jm-dvm-dialog::backdrop { background: rgba(3, 6, 15, .7); }
body.jm-dash .jm-dvm-dialog .jm-input { width: 100%; }
body.jm-dash .jm-dvm-dialog-actions { display: flex; justify-content: flex-end; gap: 8px; margin-top: 22px; flex-wrap: wrap; }
/* Billing history on the Bunny tab: the note sits inside the card padding when the block failed. */
body.jm-dash .jm-dbn-history-msg { margin: 16px 24px; }
body.jm-dash .jm-dbn .is-unavailable > .jm-dtable-wrap { display: none; }

/* ============================================================
   Udemy (dashboard/udemy/index.html, dashboard/udemy/course.html)
   The instructor's Udemy account, read-only. KPIs, bars and the
   pager reuse the .jm-dbn-* and .jm-dvm-* kits; this block adds
   the tab panels, the state a block shows when Udemy gave nothing,
   the course rows, the review / question feed and the curriculum
   page. Udemy text is often English inside an Arabic page: it sits
   in <bdi dir="auto"> while its block keeps the page's alignment.
   ============================================================ */
body.jm-dash .jm-dud-panel { display: grid; gap: 22px; grid-template-columns: minmax(0, 1fr); }
body.jm-dash .jm-dud-panel:focus-visible { outline: 2px solid var(--accent); outline-offset: 6px; border-radius: var(--r-sm); }
/* Blocks toggled by script carry the hidden attribute; several of them set their own display. */
body.jm-dash .jm-dud [hidden] { display: none; }
/* .jm-tabs scrolls sideways and would clip an outside ring. */
body.jm-dash .jm-dud .jm-tabs button:focus-visible { outline: 2px solid var(--accent); outline-offset: -3px; border-radius: 8px; }
body.jm-dash .jm-dud-panel > .jm-dgrid,
body.jm-dash .jm-dud-kpis { margin: 0; }
body.jm-dash .jm-dud-kpi-note { margin: 6px 0 0; color: var(--faint); font-size: .78rem; font-weight: 600; }
body.jm-dash .jm-dud-truncated { margin: -10px 0 0; }
/* Shown while the public course details (students, price, image, lectures) are still being read. */
body.jm-dash .jm-dud-pending { margin: 0; color: var(--muted); font-size: .85rem; }
body.jm-dash .jm-dud-panel > .jm-dud-pending { margin-top: -10px; }
body.jm-dash .jm-dud-textbtn { padding: 0; border: 0; background: none; font: inherit; font-size: .9rem; font-weight: 700; cursor: pointer; }
body.jm-dash .jm-dud-textbtn:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; border-radius: 4px; }
body.jm-dash .jm-dud-earnings { max-width: 760px; }
body.jm-dash .jm-dud-num { font-variant-numeric: tabular-nums; white-space: nowrap; }

/* A block Udemy gave nothing for: what happened, then the one thing to do about it. */
body.jm-dash .jm-dud-state { margin-top: 16px; padding: 16px 18px; border: 1px dashed var(--border2); border-radius: var(--r-sm); background: var(--card); }
body.jm-dash .jm-dud-state--pad { margin: 20px 24px; }
body.jm-dash .jm-dud-state-text { margin: 0; max-width: 68ch; color: var(--text); font-size: .95rem; }
body.jm-dash .jm-dud-state-actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px; }
body.jm-dash .jm-dud-state-actions:empty { display: none; }

/* Search and sort above the course list; the filter above the curriculum. Labels sit on one line,
   controls on the next, so both columns line up whatever the label length. */
body.jm-dash .jm-dud-toolbar { display: grid; grid-template-columns: minmax(0, 1fr); gap: 14px 18px; align-items: start; padding: 20px 24px 16px; }
body.jm-dash .jm-dud-toolbar .jm-field-error { margin: 0; }
body.jm-dash .jm-dud-toolbar-actions { display: flex; flex-wrap: wrap; gap: 8px; }
@media (min-width: 768px) {
    body.jm-dash .jm-dud-toolbar { grid-template-columns: minmax(0, 1fr) minmax(200px, 260px); }
    body.jm-dash .jm-dud-toolbar--filter { grid-template-columns: minmax(0, 1fr) auto; align-items: end; }
}
/* A slim line under the toolbar: how many are listed, and whether details are still arriving. */
body.jm-dash .jm-dud-listbar {
    display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 4px 16px;
    min-height: 40px; padding: 8px 24px; border-block: 1px solid var(--border); background: var(--card);
}
body.jm-dash .jm-dud-listbar-count { margin: 0; color: var(--muted); font-size: .85rem; font-weight: 700; font-variant-numeric: tabular-nums; }

/* ---- course rows: cover, what it is, labelled figures, then one filled action and quiet links ---- */
body.jm-dash .jm-dud-courses { list-style: none; margin: 0; padding: 0; }
body.jm-dash .jm-dud-course {
    display: grid; grid-template-columns: minmax(0, 1fr); gap: 12px 20px; align-items: start;
    padding: 18px 16px; border-bottom: 1px solid var(--border);
}
body.jm-dash .jm-dud-course:last-child { border-bottom: 0; }
body.jm-dash .jm-dud-thumb {
    display: block; width: 128px; aspect-ratio: 16 / 9; border-radius: 10px; overflow: hidden;
    background: var(--card2); border: 1px solid var(--border);
}
body.jm-dash .jm-dud-thumb img { display: block; width: 100%; height: 100%; object-fit: cover; }
body.jm-dash .jm-dud-course-main { display: grid; gap: 6px; min-width: 0; justify-items: start; }
body.jm-dash .jm-dud-course-top { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 12px; min-height: 22px; }
body.jm-dash .jm-dud-price { color: var(--text); font-size: .92rem; font-weight: 700; font-variant-numeric: tabular-nums; }
body.jm-dash .jm-dud-course-title { margin: 0; max-width: 100%; color: var(--text); font-size: 1.02rem; font-weight: 700; line-height: 1.45; overflow-wrap: anywhere; }
/* Two lines at most; the ellipsis comes from the clamp, never from cutting a word. */
body.jm-dash .jm-dud-course-headline {
    margin: 0; max-width: 72ch; color: var(--muted); font-size: .9rem; line-height: 1.55; overflow-wrap: anywhere;
    display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; line-clamp: 2; overflow: hidden;
}
body.jm-dash .jm-dud-stats { list-style: none; margin: 4px 0 0; padding: 0; display: flex; flex-wrap: wrap; gap: 6px 20px; }
body.jm-dash .jm-dud-stat { display: inline-flex; align-items: center; gap: 6px; color: var(--muted); font-size: .86rem; }
body.jm-dash .jm-dud-stat-label { color: var(--muted); }
body.jm-dash .jm-dud-stat svg { flex: none; width: 16px; height: 16px; color: var(--faint); }
body.jm-dash .jm-dud-stat .jm-dud-num { color: var(--text); font-weight: 700; }
body.jm-dash .jm-dud-stat--rating svg { color: var(--accent-ink); fill: currentColor; }
body.jm-dash .jm-dud-course-hint { margin: 2px 0 0; color: var(--faint); font-size: .84rem; }
/* A draft is not on sale: same row, turned down. */
body.jm-dash .jm-dud-course.is-draft .jm-dud-thumb,
body.jm-dash .jm-dud-coursepage.is-draft .jm-dud-thumb { opacity: .55; }
body.jm-dash .jm-dud-course.is-draft .jm-dud-course-title { color: var(--muted); }
body.jm-dash .jm-dud-course-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 14px; }
body.jm-dash .jm-dud-course-links { display: flex; flex-wrap: wrap; gap: 2px 14px; }
/* Icon + label, no frame: a link or a button, large enough to tap. */
body.jm-dash .jm-dud-act {
    display: inline-flex; align-items: center; gap: 6px; min-height: 44px; padding: 0 2px;
    border: 0; background: none; color: var(--cyan); font: inherit; font-size: .88rem; font-weight: 700;
    text-decoration: none; cursor: pointer; white-space: nowrap;
}
body.jm-dash .jm-dud-act svg { flex: none; width: 16px; height: 16px; }
body.jm-dash .jm-dud-act:hover { color: var(--accent-ink); }
body.jm-dash .jm-dud-act:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 6px; }
body.jm-dash .jm-dud-course-actions > .jm-btn { min-height: 44px; }
@media (min-width: 640px) {
    body.jm-dash .jm-dud-course { grid-template-columns: 160px minmax(0, 1fr); padding: 20px 24px; }
    body.jm-dash .jm-dud-thumb { width: 160px; }
    body.jm-dash .jm-dud-course-actions { grid-column: 2; }
}
@media (min-width: 1100px) {
    body.jm-dash .jm-dud-course { grid-template-columns: 160px minmax(0, 1fr) auto; }
    body.jm-dash .jm-dud-course-actions { grid-column: 3; flex-direction: column; align-items: stretch; gap: 4px; min-width: 168px; }
    body.jm-dash .jm-dud-course-actions > .jm-btn { justify-content: center; min-height: 0; }
    body.jm-dash .jm-dud-course-links { flex-direction: column; gap: 0; }
    body.jm-dash .jm-dud-act { min-height: 32px; }
    body.jm-dash .jm-dud-hero-links { flex-direction: row; gap: 2px 24px; }
}

/* ---- reviews and questions: one entry per row, the text first, the details quiet underneath ---- */
body.jm-dash .jm-dud-feed { list-style: none; margin: 0; padding: 0; }
body.jm-dash .jm-dud-entry { padding: 18px 24px; border-bottom: 1px solid var(--border); border-inline-start: 3px solid transparent; }
body.jm-dash .jm-dud-entry:last-child { border-bottom: 0; }
body.jm-dash .jm-dud-entry.is-unread { border-inline-start-color: var(--warn); background: var(--warn-soft); }
body.jm-dash .jm-dud-entry-head { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 12px; }
body.jm-dash .jm-dud-entry-title { margin: 0; font-size: 1rem; font-weight: 700; color: var(--text); overflow-wrap: anywhere; }
body.jm-dash .jm-dud-entry-author { color: var(--text); font-weight: 700; font-size: .9rem; }
body.jm-dash .jm-dud-entry-body { margin: 8px 0 0; max-width: 76ch; color: var(--text); font-size: .95rem; line-height: 1.6; white-space: pre-line; overflow-wrap: anywhere; }
body.jm-dash .jm-dud-entry-body.is-empty { color: var(--faint); }
body.jm-dash .jm-dud-entry-meta { display: flex; flex-wrap: wrap; gap: 4px 16px; margin: 10px 0 0; color: var(--faint); font-size: .82rem; }
body.jm-dash .jm-dud-reply { margin-top: 12px; padding: 10px 14px; max-width: 76ch; border-inline-start: 2px solid var(--border2); background: var(--card); border-radius: var(--r-sm); }
body.jm-dash .jm-dud-reply > .jm-dud-entry-body { margin-top: 2px; color: var(--muted); }
body.jm-dash .jm-dud-reply-label { margin: 0; color: var(--faint); font-size: .8rem; font-weight: 700; }
body.jm-dash .jm-dud-stars { display: inline-flex; align-items: baseline; gap: 6px; color: var(--accent-ink); font-size: 1rem; white-space: nowrap; }
body.jm-dash .jm-dud-stars-num { color: var(--muted); font-size: .85rem; font-weight: 700; font-variant-numeric: tabular-nums; }
body.jm-dash .jm-dud-shimmer-line { display: block; width: min(52ch, 90%); margin-top: 12px; }

/* ---- curriculum page (course.html) ---- */
body.jm-dash .jm-dud-crumbs { margin: 0 0 14px; }
body.jm-dash .jm-dud-back { display: inline-flex; align-items: center; gap: 6px; min-height: 44px; font-size: .9rem; font-weight: 700; }
body.jm-dash .jm-dud-back svg { flex: none; width: 16px; height: 16px; }
html[dir="rtl"] body.jm-dash .jm-dud-back svg { transform: scaleX(-1); }
body.jm-dash .jm-dud-coursepage { display: grid; gap: 22px; grid-template-columns: minmax(0, 1fr); }
body.jm-dash .jm-dud-hero { display: grid; grid-template-columns: minmax(0, 1fr); gap: 16px 24px; align-items: start; }
body.jm-dash .jm-dud-hero-main { display: grid; gap: 8px; min-width: 0; justify-items: start; }
body.jm-dash .jm-dud-hero-links { margin-top: 6px; padding-top: 6px; border-top: 1px solid var(--border); justify-self: stretch; }
body.jm-dash .jm-dud-coursenote { margin: -8px 0 0; }
@media (min-width: 640px) {
    body.jm-dash .jm-dud-hero { grid-template-columns: 200px minmax(0, 1fr); }
    body.jm-dash .jm-dud-hero .jm-dud-thumb { width: 200px; }
}
body.jm-dash .jm-dud-curhead { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 12px 32px; padding: 20px 24px; border-bottom: 1px solid var(--border); }
body.jm-dash .jm-dud-totals { display: flex; flex-wrap: wrap; gap: 8px 32px; margin: 0; }
body.jm-dash .jm-dud-totals dt { margin: 0; color: var(--muted); font-size: .8rem; font-weight: 700; }
body.jm-dash .jm-dud-totals dd { margin: 2px 0 0; color: var(--text); font-size: 1.25rem; font-weight: 700; line-height: 1.2; font-variant-numeric: tabular-nums; }
body.jm-dash .jm-dud-curnote { margin: 0; padding: 14px 24px 18px; }
body.jm-dash .jm-dud-secs { min-height: 60px; }
body.jm-dash .jm-dud-sec-skeleton { display: flex; justify-content: space-between; gap: 16px; padding: 16px 24px; border-bottom: 1px solid var(--border); }
body.jm-dash .jm-dud-sec-skeleton > :first-child { width: min(40ch, 60%); }
/* Sections are numbered because they are a sequence; each opens and closes on its own. */
body.jm-dash .jm-dud-sec { border-bottom: 1px solid var(--border); }
body.jm-dash .jm-dud-sec:last-child { border-bottom: 0; }
body.jm-dash .jm-dud-sec-head {
    display: grid; grid-template-columns: auto minmax(0, 1fr); align-items: baseline; gap: 2px 12px;
    padding: 14px 24px; cursor: pointer; list-style: none; font-size: .95rem;
}
body.jm-dash .jm-dud-sec-head::-webkit-details-marker { display: none; }
body.jm-dash .jm-dud-sec-head::before {
    content: ""; grid-row: 1 / span 2; align-self: center; width: 8px; height: 8px;
    border-inline-end: 2px solid var(--faint); border-bottom: 2px solid var(--faint);
    transform: rotate(-45deg); transition: transform .15s;
}
html[dir="rtl"] body.jm-dash .jm-dud-sec-head::before { transform: rotate(45deg); }
body.jm-dash .jm-dud-sec[open] > .jm-dud-sec-head::before { transform: rotate(45deg) translate(-2px, -2px); }
html[dir="rtl"] body.jm-dash .jm-dud-sec[open] > .jm-dud-sec-head::before { transform: rotate(-45deg) translate(2px, -2px); }
body.jm-dash .jm-dud-sec-head:hover { background: var(--card); }
body.jm-dash .jm-dud-sec-head:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
body.jm-dash .jm-dud-sec-no { grid-column: 2; color: var(--accent-ink); font-size: .8rem; font-weight: 700; }
body.jm-dash .jm-dud-sec-title { grid-column: 2; color: var(--text); font-weight: 700; line-height: 1.45; overflow-wrap: anywhere; }
body.jm-dash .jm-dud-sec-meta { grid-column: 2; display: flex; flex-wrap: wrap; gap: 2px 16px; color: var(--faint); font-size: .82rem; }
body.jm-dash .jm-dud-items { list-style: none; margin: 0; padding: 0 24px 10px; }
body.jm-dash .jm-dud-item {
    display: grid; grid-template-columns: 3ch minmax(0, 1fr) auto; align-items: baseline; gap: 4px 12px;
    padding: 10px 0; border-top: 1px solid var(--border); font-size: .92rem;
}
body.jm-dash .jm-dud-item-no { color: var(--faint); font-size: .82rem; font-variant-numeric: tabular-nums; text-align: end; }
body.jm-dash .jm-dud-item-title { color: var(--text); line-height: 1.5; overflow-wrap: anywhere; }
body.jm-dash .jm-dud-item-meta { grid-column: 2 / -1; display: flex; flex-wrap: wrap; gap: 6px; }
body.jm-dash .jm-dud-dur { grid-column: 3; grid-row: 1; color: var(--muted); font-variant-numeric: tabular-nums; text-align: end; }
@media (min-width: 768px) {
    body.jm-dash .jm-dud-sec-head { grid-template-columns: auto auto minmax(0, 1fr) auto; }
    body.jm-dash .jm-dud-sec-head::before { grid-row: auto; }
    body.jm-dash .jm-dud-sec-no { grid-column: auto; font-size: .88rem; white-space: nowrap; }
    body.jm-dash .jm-dud-sec-title { grid-column: auto; }
    body.jm-dash .jm-dud-sec-meta { grid-column: 4; justify-content: flex-end; white-space: nowrap; }
    body.jm-dash .jm-dud-items { padding-inline-start: 44px; }
    body.jm-dash .jm-dud-item { grid-template-columns: 3ch minmax(0, 1fr) auto 7ch; }
    body.jm-dash .jm-dud-item-meta { grid-column: 3; justify-content: flex-end; }
    body.jm-dash .jm-dud-dur { grid-column: 4; }
}
@media (max-width: 639px) {
    body.jm-dash .jm-dud-entry { padding: 16px; }
    body.jm-dash .jm-dud-state--pad { margin: 16px; }
    body.jm-dash .jm-dud-toolbar,
    body.jm-dash .jm-dud-curhead { padding-inline: 16px; }
    body.jm-dash .jm-dud-listbar { padding-inline: 16px; }
    body.jm-dash .jm-dud-sec-head { padding-inline: 16px; }
    body.jm-dash .jm-dud-items { padding-inline: 16px; }
}
/* Arabic: taller leading and no tracking on every block of running text in these pages. */
html[lang="ar"] body.jm-dash .jm-dud-course-title,
html[lang="ar"] body.jm-dash .jm-dud-sec-title,
html[lang="ar"] body.jm-dash .jm-dud-item-title,
html[lang="ar"] body.jm-dash .jm-dud-entry-title { line-height: 1.7; letter-spacing: 0; }
html[lang="ar"] body.jm-dash .jm-dud-course-headline,
html[lang="ar"] body.jm-dash .jm-dud-entry-body,
html[lang="ar"] body.jm-dash .jm-dud-state-text { line-height: 1.8; letter-spacing: 0; }
@media (prefers-reduced-motion: reduce) {
    body.jm-dash .jm-dud-sec-head::before { transition: none; }
}

/* ============================================================
   Create course: fill from a Udemy course
   (dashboard/courses/create.html, course-udemy-import.js)
   A card above the form, the picker dialog (on the .jm-dvm-dialog
   base) and the summary of what was copied. Udemy titles sit in
   <bdi dir="auto"> while their block keeps the page's alignment.
   ============================================================ */
body.jm-dash .jm-dimp { margin-bottom: 32px; }
/* Parts toggled by script carry the hidden attribute; several of them set their own display. */
body.jm-dash .jm-dimp [hidden] { display: none; }
body.jm-dash .jm-dimp-head { display: flex; flex-wrap: wrap; align-items: flex-start; justify-content: space-between; gap: 12px 24px; }
body.jm-dash .jm-dimp-head > div { flex: 1 1 320px; min-width: 0; }
body.jm-dash .jm-dimp-lead { margin: 6px 0 0; max-width: 68ch; color: var(--muted); font-size: .9rem; }
body.jm-dash .jm-dimp-setup { margin: 14px 0 0; display: flex; flex-wrap: wrap; gap: 4px 12px; color: var(--muted); font-size: .92rem; }
body.jm-dash .jm-dimp-setup .jm-link { font-weight: 700; }

/* ---- picker ---- */
body.jm-dash .jm-dimp-dialog { width: min(640px, calc(100vw - 24px)); max-height: min(720px, calc(100dvh - 24px)); padding: 0; overflow: hidden; }
body.jm-dash .jm-dimp-dialog[open] { display: flex; flex-direction: column; }
body.jm-dash .jm-dimp-dialog-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 18px 20px 6px; }
body.jm-dash .jm-dimp-x {
    flex: none; display: grid; place-items: center; width: 44px; height: 44px; margin-inline-end: -10px;
    border: 0; border-radius: 10px; background: none; color: var(--muted); cursor: pointer;
}
body.jm-dash .jm-dimp-x svg { width: 20px; height: 20px; }
body.jm-dash .jm-dimp-x:hover { background: var(--card); color: var(--text); }
body.jm-dash .jm-dimp-x:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
body.jm-dash .jm-dimp-search { display: grid; gap: 6px; padding: 8px 20px 0; }
body.jm-dash .jm-dimp-search .jm-field-error { margin: 0; }
body.jm-dash .jm-dimp-count { margin: 0; padding: 10px 20px; min-height: 1.4em; }
body.jm-dash .jm-dimp-list { list-style: none; margin: 0; padding: 0 8px; overflow-y: auto; flex: 1 1 auto; min-height: 96px; border-block: 1px solid var(--border); }
/* The whole row is the button: cover, title, students. */
body.jm-dash .jm-dimp-row {
    display: flex; align-items: center; gap: 14px; width: 100%; min-height: 72px; padding: 10px 12px;
    border: 0; border-radius: 10px; background: none; color: var(--text); font: inherit; text-align: start; cursor: pointer;
}
body.jm-dash button.jm-dimp-row:hover { background: var(--card); }
body.jm-dash button.jm-dimp-row:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
body.jm-dash button.jm-dimp-row:disabled { cursor: progress; opacity: .55; }
body.jm-dash button.jm-dimp-row[aria-busy="true"] { opacity: 1; background: var(--card); }
body.jm-dash .jm-dimp-thumb { flex: none; width: 96px; aspect-ratio: 16 / 9; border-radius: 8px; overflow: hidden; background: var(--card2); border: 1px solid var(--border); }
body.jm-dash .jm-dimp-thumb img { display: block; width: 100%; height: 100%; object-fit: cover; }
body.jm-dash .jm-dimp-row-text { display: grid; gap: 2px; min-width: 0; flex: 1 1 auto; }
body.jm-dash .jm-dimp-row-title { font-weight: 700; line-height: 1.45; overflow-wrap: anywhere; }
body.jm-dash .jm-dimp-row-meta { color: var(--muted); font-size: .84rem; font-variant-numeric: tabular-nums; }
body.jm-dash .jm-dimp-row-busy { flex: none; color: var(--accent-ink); font-size: .84rem; font-weight: 700; }
body.jm-dash .jm-dimp-state { margin: 14px 20px 0; padding: 14px 16px; border: 1px dashed var(--border2); border-radius: var(--r-sm); background: var(--card); }
body.jm-dash .jm-dimp-state-text { margin: 0; color: var(--text); font-size: .93rem; }
body.jm-dash .jm-dimp-state-actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 10px; }
body.jm-dash .jm-dimp-state-actions:not(:has(> :not([hidden]))) { display: none; }
body.jm-dash .jm-dimp-dialog .jm-dvm-dialog-actions { margin: 0; padding: 14px 20px 18px; align-items: center; justify-content: space-between; }
body.jm-dash .jm-dimp-all { font-size: .88rem; font-weight: 700; }

/* ---- what was copied ---- */
body.jm-dash .jm-dimp-summary { display: grid; gap: 14px; margin-top: 18px; padding-top: 16px; border-top: 1px solid var(--border); }
body.jm-dash .jm-dimp-summary-head { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 8px 16px; }
body.jm-dash .jm-dimp-summary-title { margin: 0; color: var(--text); font-weight: 700; overflow-wrap: anywhere; }
body.jm-dash .jm-dimp-summary-group { min-width: 0; }
body.jm-dash .jm-dimp-summary-label { margin: 0 0 4px; color: var(--muted); font-size: .82rem; font-weight: 700; }
body.jm-dash .jm-dimp-notes { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: 4px 8px; font-size: .9rem; color: var(--text); }
body.jm-dash .jm-dimp-notes li { padding: 2px 10px; border: 1px solid var(--border); border-radius: 999px; background: var(--card); }
/* Things to do read as sentences, one per line, not as chips. */
body.jm-dash .jm-dimp-summary-group:last-child .jm-dimp-notes { display: grid; gap: 4px; }
body.jm-dash .jm-dimp-summary-group:last-child .jm-dimp-notes li { padding: 0; border: 0; border-radius: 0; background: none; }
body.jm-dash .jm-dimp-lists { list-style: none; margin: 0 0 4px; padding: 0; display: grid; gap: 2px; font-size: .9rem; }
body.jm-dash .jm-dimp-lists li { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 14px; }
body.jm-dash .jm-dimp-remove { min-height: 32px; padding: 0 2px; border: 0; background: none; color: var(--cyan); font: inherit; font-size: .86rem; font-weight: 700; cursor: pointer; }
body.jm-dash .jm-dimp-remove:hover { color: var(--danger); }
body.jm-dash .jm-dimp-remove:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 4px; }
html[lang="ar"] body.jm-dash .jm-dimp-row-title,
html[lang="ar"] body.jm-dash .jm-dimp-lead,
html[lang="ar"] body.jm-dash .jm-dimp-state-text { line-height: 1.75; letter-spacing: 0; }
@media (max-width: 639px) {
    body.jm-dash .jm-dimp-thumb { width: 72px; }
    body.jm-dash .jm-dimp-remove { min-height: 44px; }
}

/* ============================================================
   Create course: field validation (course-form.js)
   The inputs take the shared .is-invalid border and glow; these
   are the two parts that are not inputs.
   ============================================================ */
/* A file input is invisible inside its drop zone, so the zone shows the error. */
body.jm-dash .jm-ddrop.is-invalid,
body.jm-dash .jm-ddrop.drop-zone.is-invalid { border-color: var(--danger); box-shadow: 0 0 0 4px var(--danger-soft); }
/* A post on its way: the button stays put and says so. */
body.jm-dash form[data-create-validate] button[type="submit"][aria-busy="true"] { cursor: progress; opacity: .7; }

/* ============================================================
   Course page: copy reviews from Udemy
   (dashboard/courses/view.html #udemy-reviews, course-ratings-udemy.js)
   The dialog stands on the .jm-dvm-dialog / .jm-dimp-dialog base
   (head, close button, state box); this block adds the filters and
   the review rows. Review text sits in <bdi dir="auto">.
   ============================================================ */
/* Parts toggled by script carry the hidden attribute; several of them set their own display. */
body.jm-dash .jm-drv [hidden] { display: none; }
body.jm-dash .jm-drv-bar { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 16px; margin: 0 0 12px; }
body.jm-dash .jm-drv-link { font-size: .84rem; font-weight: 700; }
body.jm-dash .jm-drv-setup { margin: 0; display: flex; flex-wrap: wrap; gap: 4px 12px; color: var(--muted); font-size: .86rem; }
body.jm-dash .jm-drv-setup .jm-link { font-weight: 700; }
body.jm-dash .jm-drv-dialog { width: min(720px, calc(100vw - 24px)); }
body.jm-dash .jm-drv-filters { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px 14px; padding: 8px 20px 0; }
body.jm-dash .jm-drv-field { display: grid; gap: 6px; min-width: 0; align-content: start; }
body.jm-dash .jm-drv-field--wide { grid-column: 1 / -1; }
body.jm-dash .jm-drv-field .jm-field-error { margin: 0; }
body.jm-dash .jm-drv-note { margin: 0; padding: 10px 20px 0; }
body.jm-dash .jm-drv-toolbar { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 16px; padding: 12px 20px; }
body.jm-dash .jm-drv-selected { color: var(--text); font-size: .88rem; font-weight: 700; font-variant-numeric: tabular-nums; }
body.jm-dash .jm-drv-toolbar > :last-child { margin-inline-start: auto; }
body.jm-dash .jm-drv-list { list-style: none; margin: 0; padding: 0 20px; overflow-y: auto; flex: 1 1 auto; min-height: 120px; border-block: 1px solid var(--border); }
body.jm-dash .jm-drv-row { display: flex; align-items: flex-start; gap: 12px; padding: 14px 0; border-bottom: 1px solid var(--border); }
body.jm-dash .jm-drv-row:last-child { border-bottom: 0; }
body.jm-dash .jm-drv-row.is-copied { opacity: .6; }
body.jm-dash .jm-drv-box { flex: none; width: 18px; height: 18px; margin: 3px 0 0; accent-color: var(--accent); }
body.jm-dash .jm-drv-avatar { flex: none; width: 36px; height: 36px; border-radius: 50%; object-fit: cover; background: var(--border); }
body.jm-dash .jm-drv-body { display: grid; gap: 4px; min-width: 0; flex: 1 1 auto; justify-items: start; }
body.jm-dash .jm-drv-head { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 12px; }
body.jm-dash .jm-drv-name { color: var(--text); font-size: .92rem; font-weight: 700; cursor: pointer; overflow-wrap: anywhere; }
body.jm-dash .jm-drv-stars { display: inline-flex; align-items: baseline; gap: 4px; color: var(--accent-ink); font-size: .9rem; font-weight: 700; font-variant-numeric: tabular-nums; white-space: nowrap; }
body.jm-dash .jm-drv-stored { margin-inline-start: 4px; color: var(--muted); font-size: .8rem; font-weight: 400; }
body.jm-dash .jm-drv-date { color: var(--faint); font-size: .8rem; }
body.jm-dash .jm-drv-text { margin: 0; max-width: 70ch; color: var(--text); font-size: .9rem; line-height: 1.55; white-space: pre-line; overflow-wrap: anywhere; }
body.jm-dash .jm-drv-text.is-empty { color: var(--faint); }
/* Three lines until "Show more"; the ellipsis comes from the clamp. */
body.jm-dash .jm-drv-text.is-clamped { display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3; line-clamp: 3; overflow: hidden; }
body.jm-dash .jm-drv-more { min-height: 32px; padding: 0; border: 0; background: none; color: var(--cyan); font: inherit; font-size: .84rem; font-weight: 700; cursor: pointer; }
body.jm-dash .jm-drv-more:hover { color: var(--accent-ink); }
body.jm-dash .jm-drv-more:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 4px; }
body.jm-dash .jm-drv-shimmer { display: block; width: min(48ch, 90%); margin-top: 8px; }
body.jm-dash .jm-drv-older { margin: 0; padding: 10px 20px 0; }
body.jm-dash .jm-drv-error { margin: 0; padding: 10px 20px 0; }
body.jm-dash .jm-drv-error:empty { padding: 0; }
body.jm-dash .jm-drv-dialog .jm-dvm-dialog-actions { justify-content: flex-end; }
html[lang="ar"] body.jm-dash .jm-drv-text { line-height: 1.8; letter-spacing: 0; }
@media (min-width: 640px) {
    body.jm-dash .jm-drv-filters { grid-template-columns: minmax(0, 2fr) minmax(0, 1fr) minmax(0, 1fr); }
    body.jm-dash .jm-drv-filters > .jm-drv-field--wide:first-child { grid-column: auto; }
}
@media (max-width: 639px) {
    body.jm-dash .jm-drv-more { min-height: 44px; }
    body.jm-dash .jm-drv-box { width: 22px; height: 22px; }
}

/* Subscription plan delete dialog (fragments/subscription-delete-dialog.html).
   Two consequence panels carry the decision: the quiet one keeps subscribers,
   the danger-tinted one removes them. The subscriber list above stays plain. */
body.jm-dash .jm-dsd-panel { max-width: 620px; }
body.jm-dash .jm-dsd-summary { margin: 0 0 12px; color: var(--text); font-size: .95rem; font-weight: 700; }
body.jm-dash .jm-dsd-summary:empty { display: none; }
body.jm-dash .jm-dsd-list-wrap.hidden,
body.jm-dash .jm-dsd-choice.hidden,
body.jm-dash .jm-dsd-ack.hidden,
body.jm-dash .jm-dsd-link.hidden { display: none; }
body.jm-dash .jm-dsd-list {
    margin: 0; padding: 0; list-style: none;
    max-height: 232px; overflow-y: auto;
    border: 1px solid var(--border); border-radius: var(--r-sm); background: var(--card);
}
body.jm-dash .jm-dsd-row {
    display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 6px 16px;
    padding: 10px 14px; border-bottom: 1px solid var(--border);
}
body.jm-dash .jm-dsd-row:last-child { border-bottom: 0; }
body.jm-dash .jm-dsd-who { display: grid; min-width: 0; }
body.jm-dash .jm-dsd-name { color: var(--text); font-size: .9rem; font-weight: 700; overflow-wrap: anywhere; }
body.jm-dash .jm-dsd-email { color: var(--muted); font-size: .8rem; overflow-wrap: anywhere; }
body.jm-dash .jm-dsd-meta { display: flex; align-items: center; gap: 10px; flex: none; }
body.jm-dash .jm-dsd-until { color: var(--faint); font-size: .8rem; font-variant-numeric: tabular-nums; white-space: nowrap; }
body.jm-dash .jm-dsd-shimmer {
    display: block; width: min(26ch, 55%); height: 14px; border-radius: 7px;
    background: linear-gradient(90deg, var(--card) 25%, var(--card2) 37%, var(--card) 63%);
    background-size: 400% 100%; animation: jm-dcb-shimmer 1.4s ease infinite;
}
body.jm-dash .jm-dsd-shimmer--short { width: 72px; }
body.jm-dash .jm-dsd-list-foot { display: flex; flex-wrap: wrap; justify-content: space-between; gap: 4px 16px; margin-top: 8px; }
body.jm-dash .jm-dsd-link {
    min-height: 32px; padding: 0; border: 0; background: none; display: inline-flex; align-items: center;
    color: var(--cyan); font: inherit; font-size: .84rem; font-weight: 700; cursor: pointer; text-decoration: none;
}
body.jm-dash .jm-dsd-link:hover { color: var(--accent-ink); }
body.jm-dash .jm-dsd-link:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 4px; }
body.jm-dash .jm-dsd-link[aria-busy="true"] { opacity: .6; cursor: progress; }
body.jm-dash .jm-dsd-note { margin: 12px 0 0; color: var(--muted); font-size: .84rem; line-height: 1.55; }
body.jm-dash .jm-dsd-error { margin: 12px 0 0; color: var(--danger); font-size: .88rem; }
body.jm-dash .jm-dsd-note.hidden, body.jm-dash .jm-dsd-error.hidden, body.jm-dash .jm-dsd-field-error.hidden { display: none; }
body.jm-dash .jm-dsd-choices { display: grid; gap: 12px; margin-top: 20px; }
body.jm-dash .jm-dsd-choice {
    display: flex; flex-direction: column; align-items: flex-start; gap: 14px;
    margin: 0; padding: 16px 18px;
    border: 1px solid var(--border); border-radius: var(--r-sm); background: var(--card);
}
body.jm-dash .jm-dsd-choice--danger { border-color: var(--danger-border); background: var(--danger-soft); }
body.jm-dash .jm-dsd-choice-text { display: grid; gap: 6px; min-width: 0; }
body.jm-dash .jm-dsd-choice h3 { margin: 0; color: var(--text); font-size: .98rem; font-weight: 700; }
body.jm-dash .jm-dsd-choice p { margin: 0; max-width: 62ch; color: var(--muted); font-size: .86rem; line-height: 1.55; }
body.jm-dash .jm-dsd-choice p.hidden { display: none; }
body.jm-dash .jm-dsd-choice .jm-btn { flex: none; }
body.jm-dash .jm-dsd-choice .jm-btn[aria-busy="true"] { cursor: progress; }
body.jm-dash .jm-dsd-ack { display: grid; gap: 6px; margin-top: 6px; }
body.jm-dash .jm-dsd-ack .jm-check { align-items: flex-start; color: var(--text); font-size: .88rem; line-height: 1.5; }
body.jm-dash .jm-dsd-ack input[type="checkbox"] { flex: none; width: 18px; height: 18px; margin-top: 2px; accent-color: var(--danger); border-radius: 4px; }
body.jm-dash .jm-dsd-ack input.jm-dsd-invalid { outline: 2px solid var(--danger); outline-offset: 2px; box-shadow: 0 0 0 5px var(--danger-soft); }
body.jm-dash .jm-dsd-choice p.jm-dsd-field-error { color: var(--danger); font-size: .82rem; font-weight: 700; }
html[lang="ar"] body.jm-dash .jm-dsd-choice p,
html[lang="ar"] body.jm-dash .jm-dsd-note { line-height: 1.8; letter-spacing: 0; }
@media (min-width: 640px) {
    body.jm-dash .jm-dsd-choice { flex-direction: row; align-items: center; justify-content: space-between; gap: 20px; }
}
@media (max-width: 639px) {
    body.jm-dash .jm-dsd-link { min-height: 44px; }
    body.jm-dash .jm-dsd-choice .jm-btn { width: 100%; justify-content: center; }
    body.jm-dash .jm-dsd-ack input[type="checkbox"] { width: 22px; height: 22px; }
}
@media (prefers-reduced-motion: reduce) {
    body.jm-dash .jm-dsd-shimmer { animation: none; }
}

/* Settings → System warning notifications (panel-system-alerts). One row per kind of
   server error: its switch and meaning on the start side, who is emailed on the end side. */
body.jm-dash .jm-dsa-kinds { margin: 0; padding: 0; list-style: none; border: 1px solid var(--border); border-radius: var(--r-sm); }
body.jm-dash .jm-dsa-kind { display: grid; gap: 12px; padding: 16px 18px; border-bottom: 1px solid var(--border); }
body.jm-dash .jm-dsa-kind:last-child { border-bottom: 0; }
body.jm-dash .jm-dsa-kind-main { display: flex; align-items: flex-start; gap: 12px; min-width: 0; }
body.jm-dash .jm-dsa-kind-main .jm-label { display: block; }
body.jm-dash .jm-dsa-kind-main .jm-help { margin: 2px 0 0; max-width: 56ch; }
body.jm-dash .jm-dsa-off { opacity: .55; }
body.jm-dash .jm-input.jm-dsa-invalid { border-color: var(--danger); box-shadow: 0 0 0 4px var(--danger-soft); }
@media (min-width: 768px) {
    body.jm-dash .jm-dsa-kind { grid-template-columns: minmax(0, 1fr) minmax(0, 320px); align-items: start; gap: 24px; }
}
@media (prefers-reduced-motion: no-preference) {
    body.jm-dash .jm-dsa-kind-mail, body.jm-dash [data-sa-needs-master] { transition: opacity .15s ease; }
}

/* Lesson questions (dashboard/course-questions/index.html). One card per question: who asked and
   its status on top, then the question (with the course / lesson / video-time trail) on the start
   side and the answer — saved, or the form to write it — on the end side. */
body.jm-dash .jm-dcq-scope { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 8px 20px; margin-bottom: 18px; padding: 12px 16px; background: var(--bg2); border: 1px solid var(--border); border-radius: var(--r-sm); }
body.jm-dash .jm-dcq-scope-title { margin: 0; color: var(--muted); font-size: .9rem; }
body.jm-dash .jm-dcq-scope-title strong { color: var(--text); font-weight: 700; }
body.jm-dash .jm-dcq-scope-links { display: flex; flex-wrap: wrap; gap: 6px 18px; }
body.jm-dash .jm-dcq-list { display: grid; gap: 16px; margin: 0; padding: 0; list-style: none; }
body.jm-dash .jm-dcq-card { padding: 20px; }
/* The page toggles chips, the form and the saved answer with [hidden]; their display rules would win otherwise. */
body.jm-dash [data-cq-root] [hidden] { display: none; }
body.jm-dash .jm-dcq-grid { display: grid; gap: 18px; min-width: 0; }
body.jm-dash .jm-dcq-head { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 16px; min-width: 0; }
body.jm-dash .jm-dcq-who { display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px 10px; min-width: 0; margin-inline-end: auto; }
body.jm-dash .jm-dcq-name { margin: 0; color: var(--text); font-size: 1rem; font-weight: 700; overflow-wrap: anywhere; }
body.jm-dash .jm-dcq-email { color: var(--muted); font-size: .84rem; overflow-wrap: anywhere; }
body.jm-dash .jm-dcq-when { margin: 0; color: var(--faint); font-size: .8rem; }
body.jm-dash .jm-dcq-question { display: grid; gap: 14px; align-content: start; min-width: 0; }
body.jm-dash .jm-dcq-where { display: grid; gap: 10px; padding: 12px 14px; background: var(--card); border: 1px solid var(--border); border-radius: var(--r-sm); }
body.jm-dash .jm-dcq-trail { display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px 0; margin: 0; padding: 0; list-style: none; color: var(--muted); font-size: .88rem; line-height: 1.5; }
body.jm-dash .jm-dcq-trail li { min-width: 0; overflow-wrap: anywhere; }
body.jm-dash .jm-dcq-trail li + li::before { content: "/"; margin-inline: 8px; color: var(--faint); }
body.jm-dash .jm-dcq-trail a { font-weight: 700; }
body.jm-dash .jm-dcq-trail a:hover { text-decoration: underline; }
body.jm-dash .jm-dcq-trail .jm-dcq-lesson { color: var(--text); font-weight: 700; }
body.jm-dash .jm-dcq-where-end { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 14px; }
body.jm-dash .jm-dcq-gone { color: var(--faint); font-size: .82rem; }
body.jm-dash .jm-dcq-body { margin: 0; max-width: 72ch; color: var(--text); font-size: .95rem; line-height: 1.65; white-space: pre-line; overflow-wrap: anywhere; }
body.jm-dash .jm-dcq-shots { display: flex; flex-wrap: wrap; gap: 10px; margin: 0; padding: 0; list-style: none; }
body.jm-dash .jm-dcq-shot { display: block; overflow: hidden; background: var(--card); border: 1px solid var(--border); border-radius: var(--r-sm); }
body.jm-dash .jm-dcq-shot img { display: block; width: 120px; height: 90px; object-fit: cover; }
body.jm-dash .jm-dcq-shot:hover { border-color: var(--accent); }
body.jm-dash .jm-dcq-shot:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
body.jm-dash .jm-dcq-answer { min-width: 0; padding-top: 18px; border-top: 1px solid var(--border); }
body.jm-dash .jm-dcq-view { display: grid; gap: 10px; }
body.jm-dash .jm-dcq-view:focus { outline: none; }
body.jm-dash .jm-dcq-answer-title { margin: 0; color: var(--muted); font-size: .82rem; font-weight: 700; }
body.jm-dash .jm-dcq-answer-text { margin: 0; max-width: 72ch; color: var(--text); font-size: .95rem; line-height: 1.65; white-space: pre-line; overflow-wrap: anywhere; }
body.jm-dash .jm-dcq-answer-foot { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 8px 16px; }
body.jm-dash .jm-dcq-answer-meta { display: flex; flex-wrap: wrap; gap: 2px 12px; margin: 0; color: var(--faint); font-size: .8rem; }
body.jm-dash .jm-dcq-answer-foot .jm-btn[aria-busy="true"] { cursor: progress; }
body.jm-dash .jm-dcq-form { display: grid; gap: 8px; }
body.jm-dash .jm-dcq-form .jm-label { margin: 0; }
body.jm-dash .jm-dcq-form .jm-textarea { width: 100%; min-height: 112px; }
body.jm-dash .jm-dcq-form-meta { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; }
body.jm-dash .jm-dcq-count { flex: none; color: var(--faint); font-size: .78rem; font-variant-numeric: tabular-nums; }
body.jm-dash .jm-dcq-form-foot { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 4px; }
html[lang="ar"] body.jm-dash .jm-dcq-body,
html[lang="ar"] body.jm-dash .jm-dcq-answer-text,
html[lang="ar"] body.jm-dash .jm-dcq-trail { line-height: 1.8; letter-spacing: 0; }
@media (min-width: 1024px) {
    body.jm-dash .jm-dcq-card { padding: 22px 24px; }
    body.jm-dash .jm-dcq-grid { grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr); column-gap: 28px; }
    body.jm-dash .jm-dcq-head { grid-column: 1 / -1; }
    body.jm-dash .jm-dcq-answer { padding-top: 0; padding-inline-start: 28px; border-top: 0; border-inline-start: 1px solid var(--border); }
}
@media (max-width: 639px) {
    body.jm-dash .jm-dcq-form-foot .jm-btn { flex: 1 1 auto; justify-content: center; min-height: 44px; }
    body.jm-dash .jm-dcq-scope-links .jm-quicklink { min-height: 44px; }
}

/* Lesson questions: the student's name links to their dashboard page. */
body.jm-dash .jm-dcq-userlink { display: inline-flex; align-items: center; gap: 6px; color: inherit; text-decoration: none; }
body.jm-dash .jm-dcq-userlink svg { width: 15px; height: 15px; flex: none; color: var(--cyan); }
body.jm-dash .jm-dcq-userlink:hover { color: var(--cyan); text-decoration: underline; }
body.jm-dash .jm-dcq-userlink:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 4px; }

/* ---------- Course FAQ tab (dashboard/courses/faq.html, course-faq.js) ---------- */
body.jm-dash .jm-dfaq-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 12px; }
body.jm-dash .jm-dfaq-item {
    display: flex; flex-wrap: wrap; align-items: flex-start; gap: 12px 16px;
    padding: 16px 18px; border: 1px solid var(--border); border-radius: var(--r-sm);
    background: var(--card); transition: opacity .2s, border-color .2s;
}
body.jm-dash .jm-dfaq-item.is-pending { opacity: .65; border-style: dashed; }
body.jm-dash .jm-dfaq-view { flex: 1 1 260px; min-width: 0; }
body.jm-dash .jm-dfaq-q { margin: 0 0 6px; font-weight: 700; color: var(--text); overflow-wrap: anywhere; }
body.jm-dash .jm-dfaq-a { margin: 0; color: var(--muted); white-space: pre-line; overflow-wrap: anywhere; line-height: 1.6; }
body.jm-dash .jm-dfaq-status { display: inline-block; margin-top: 8px; font-size: .8rem; font-weight: 600; color: var(--accent-ink); }
body.jm-dash .jm-dfaq-actions { display: flex; flex-wrap: wrap; gap: 6px; margin-inline-start: auto; }
body.jm-dash .jm-dfaq-actions .jm-btn svg { width: 16px; height: 16px; }
body.jm-dash .jm-dfaq-actions .jm-btn:disabled { opacity: .45; cursor: not-allowed; transform: none; }
body.jm-dash .jm-dfaq-edit { flex: 1 1 100%; }
/* Blog article FAQ (dashboard/blog/form.html, blog-faq.js): rows edited in place, saved with the article. */
body.jm-dash .jm-dfaq-fields { flex: 1 1 320px; min-width: 0; }
@media (prefers-reduced-motion: reduce) {
    body.jm-dash .jm-dfaq-item { transition: none; }
}
