/* ── Admin: Enrollment pages (/admin/enrollment-pages) ───────────────
   Builds on the shared admin table/modal/form styles in admin.css. Every
   class here is prefixed `ep-`.

   This page's UI copy is Hebrew, so the page root re-establishes RTL inside
   the LTR-pinned .admin-main - the same self-contained island pattern
   .ct-page uses in admin-contracts.css. LTR-sensitive values (URLs, phones,
   emails, dates, amounts) keep their dir="ltr" attributes in the template.
   The page root is deliberately NOT a horizontal scroller: the one wide
   element on it (the drill-down table) scrolls in its own .ep-drill-scroll
   box, URLs wrap (overflow-wrap), and the course pills wrap, so the
   document never pans sideways on a phone. */

.ep-page {
    direction: rtl;
    text-align: right;
}

/* admin.css positions the hint physically (margin-left) for the LTR pages. */
.ep-page .form-label-hint {
    margin-left: 0;
    margin-right: 0.35rem;
}

/* HOW MANY SEATS THE QUOTA BESIDE IT IS ALREADY MEASURED AGAINST.
   A line of its own rather than more words inside the hint: the hint explains
   the field and never changes, this is a live figure, and buried at the end of
   a 200-character sentence it would be exactly as invisible as it was before
   this existed. Darker than `.form-label-hint`'s grey for the same reason -
   near the tertiary text token, so it reads as data rather than as more
   explanation, while staying quieter than the label above it.
   `margin-inline: 0` undoes the inline offset the rule above gives a hint that
   really does sit beside the label text. */
.ep-page .ep-quota-used {
    display: block;
    margin-inline: 0;
    margin-block-start: 0.3rem;
    color: #494950;
}

/* ── Filter bar ─────────────────────────────────────────────────── */

.ep-filter-bar {
    display: flex;
    align-items: flex-end;
    gap: 0.75rem;
    margin-bottom: 1.25rem;
}

.ep-filter-field {
    min-width: 190px;
}

.ep-filter-field .form-select {
    direction: rtl;
    text-align: right;
}

/* ── Card list ──────────────────────────────────────────────────── */

.ep-list {
    display: flex;
    flex-direction: column;
    gap: 1rem;
}

.ep-card {
    background: #fff;
    border: 1px solid #e8e8e8;
    border-radius: 12px;
    padding: 1.25rem 1.35rem;
    box-shadow: 0 1px 3px rgba(0, 60, 130, 0.04);
    transition: box-shadow 0.2s, border-color 0.2s;
}

.ep-card:hover {
    box-shadow: 0 4px 16px rgba(0, 60, 130, 0.07);
}

/* The default page is the one the bare subdomain serves - it earns a rail. */
.ep-card--default {
    border-color: #cfe3ff;
    box-shadow: inset 4px 0 0 0 #0071e3, 0 1px 3px rgba(0, 60, 130, 0.04);
}

.ep-card--archived {
    background: #fafafa;
    opacity: 0.75;
}

/* Rehearsal page. Crimson is unused elsewhere on this screen (status chips are
   green/amber/grey, the default badge is blue), so the rail alone separates a
   test page from a selling one in a list scan. Listed after --default so that
   if a page somehow carries both, the louder warning wins the rail. */
.ep-card--test {
    border-color: #f3c6d3;
    box-shadow: inset 4px 0 0 0 #c2185b, 0 1px 3px rgba(0, 60, 130, 0.04);
}

/* Solid fill, not a tint: every other chip on the card is tinted, so a filled
   badge is the one thing the eye lands on first. */
.ep-test-badge {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    margin-bottom: 0.4rem;
    padding: 3px 11px;
    border-radius: 999px;
    background: #c2185b;
    color: #fff;
    font-size: 0.74rem;
    font-weight: 600;
    letter-spacing: 0.01em;
    white-space: nowrap;
}

.ep-test-badge i {
    font-size: 0.68rem;
}

.ep-card-head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
}

.ep-card-titles {
    min-width: 0;
    flex: 1 1 340px;
}

.ep-card-title {
    font-size: 1.1rem;
    font-weight: 600;
    color: var(--text-color, #191a23);
    margin: 0 0 0.5rem 0;
    letter-spacing: -0.01em;
}

.ep-chips {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.4rem;
}

/* ── Status + flags ─────────────────────────────────────────────── */

.ep-status {
    display: inline-block;
    padding: 2px 10px;
    border-radius: 999px;
    font-size: 0.72rem;
    font-weight: 600;
    white-space: nowrap;
}

.ep-status--active {
    background: rgba(31, 157, 85, 0.12);
    color: #1f7a44;
}

.ep-status--paused {
    background: rgba(255, 163, 4, 0.16);
    color: #9a6b00;
}

.ep-status--archived {
    background: rgba(90, 91, 106, 0.12);
    color: #5a5b6a;
}

.ep-default-badge {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    padding: 2px 10px;
    border-radius: 999px;
    font-size: 0.72rem;
    font-weight: 600;
    white-space: nowrap;
    background: #e8f0fe;
    color: #0071e3;
    border: 1px solid #cfe3ff;
}

.ep-default-badge i {
    font-size: 0.65rem;
}

.ep-flag {
    display: inline-block;
    padding: 2px 10px;
    border-radius: 999px;
    font-size: 0.72rem;
    font-weight: 600;
    white-space: nowrap;
    background: #f3f4f6;
    color: #6b7280;
}

.ep-flag--warn {
    background: rgba(196, 85, 26, 0.1);
    color: #b23c17;
}

/* ── Counters ───────────────────────────────────────────────────── */

.ep-card-counts {
    display: flex;
    gap: 1.5rem;
    flex: 0 0 auto;
}

.ep-count {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 0.1rem;
}

.ep-count-value {
    font-size: 1.35rem;
    font-weight: 600;
    line-height: 1.1;
    color: var(--text-color, #191a23);
    direction: ltr;
}

.ep-count-cap {
    font-size: 0.95rem;
    font-weight: 400;
    color: #8e8f9e;
}

.ep-count-label {
    font-size: 0.72rem;
    color: #8e8f9e;
}

/* ── Closed-state note ──────────────────────────────────────────── */

.ep-closed-note {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    margin-top: 0.85rem;
    padding: 0.5rem 0.75rem;
    border-radius: 8px;
    background: rgba(196, 85, 26, 0.07);
    color: #b23c17;
    font-size: 0.8rem;
}

/* ── Public URL row ─────────────────────────────────────────────── */

.ep-url-row {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin-top: 0.9rem;
}

.ep-url {
    flex: 1 1 auto;
    min-width: 0;
    direction: ltr;
    text-align: left;
    font-family: var(--font-mono, monospace);
    font-size: 0.8rem;
    background: #fafbfd;
}

.ep-url-row .btn {
    white-space: nowrap;
}

/* ── Meta grid ──────────────────────────────────────────────────── */

.ep-meta-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
    gap: 0.75rem 1.25rem;
    margin-top: 1rem;
    padding-top: 1rem;
    border-top: 1px solid #f0f0f0;
}

.ep-meta {
    display: flex;
    flex-direction: column;
    gap: 0.2rem;
    min-width: 0;
}

.ep-meta-label {
    font-size: 0.7rem;
    font-weight: 600;
    letter-spacing: 0.04em;
    color: #8e8f9e;
}

.ep-meta-value {
    font-size: 0.85rem;
    color: #444;
}

.ep-meta-empty {
    font-size: 0.82rem;
    color: #8e8f9e;
}

.ep-cohort-chips {
    display: flex;
    flex-wrap: wrap;
    gap: 0.3rem;
    min-width: 0;
}

/* The cohort list holds N long chips while every other meta cell holds one
   short value, so it takes a row of its own and lets the chips run across it.
   `1 / -1` rather than `span 2`: with auto-fit, a span can conjure an extra
   column at narrow widths, whereas 1/-1 is the full row at any column count. */
.ep-meta--cohorts {
    grid-column: 1 / -1;
}

/* Deliberately NOT white-space:nowrap. A cohort label runs long
   ("Developer & Architect מחזור 1 - 04/09/2026"), and nowrap inside a
   minmax(190px,1fr) grid cell pushed the chip straight over the neighbouring
   date. Wrapping keeps the whole label readable - truncating with an ellipsis
   would hide the serial or the start date, which is the entire point of the
   chip. max-width pins it to its cell no matter how long the label gets. */
.ep-cohort-chip {
    padding: 1px 8px;
    border-radius: 999px;
    font-size: 0.75rem;
    background: #f3f5f9;
    color: #5b6470;
    max-width: 100%;
    overflow-wrap: anywhere;
}

/* ── Course pills ───────────────────────────────────────────────── */

.ep-course-row {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    margin-top: 1rem;
}

/* A COLUMN since the pill grew a second row: the money line, and under it the
   optional line naming the discount that decided the price. `inline-flex` was
   only ever nominal - a flex item is blockified, so this pill has always
   computed to `flex` inside `.ep-course-row`. The baseline alignment and the
   inner wrapping moved down to `.ep-course-main`. `.ep-course-row` keeps its
   default `stretch`, so a pill that grows the note levels its neighbours
   instead of leaving a ragged row of chips. */
.ep-course-pill {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 0.2rem;
    padding: 0.35rem 0.75rem;
    border-radius: 8px;
    font-size: 0.82rem;
    background: #eef2f7;
    color: #5b6470;
}

/* The money line. Wraps only when it has run out of room, which the ex-VAT
   figure the charged price carries made possible on a narrow bundle pill. This
   page's RTL island answers an overflow by scrolling the whole card sideways,
   so a line that cannot wrap moves the card instead of itself. */
.ep-course-main {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: 0.45rem;
    max-width: 100%;
}

.ep-course-pill--developer {
    background: #e8f0fe;
    color: #0071e3;
}

.ep-course-pill--architect {
    background: #f3e8fe;
    color: #8b34c9;
}

.ep-course-pill--bundle {
    background: #fff4e0;
    color: #b06c00;
}

.ep-course-name {
    font-weight: 600;
}

.ep-course-price {
    font-weight: 600;
    direction: ltr;
}

.ep-course-list {
    font-size: 0.75rem;
    opacity: 0.65;
    text-decoration: line-through;
    direction: ltr;
}

.ep-course-pct {
    font-size: 0.72rem;
    opacity: 0.8;
}

/* The discount line, under the money. It states WHY the price above it is what
   it is, so it is readable rather than decorative.

   `--warn` is the ENDLESS discount and is the only state here that wants a
   human: it cannot clear itself by waiting, so it is lifted out of the pill's
   own hue onto the same amber `.ep-flag--warn` carries rather than being
   stepped back like everything else. `--muted` is the opposite end, a discount
   that has already ended, where the figure above is simply the standing price.

   `overflow-wrap: anywhere` because the longest sentence here is wider than a
   pill on a 320px phone, and the alternative is the card scrolling sideways. */
.ep-course-offer {
    font-size: 0.72rem;
    opacity: 0.85;
    max-width: 100%;
    overflow-wrap: anywhere;
}

.ep-course-offer--warn {
    opacity: 1;
    font-weight: 600;
    color: #b23c17;
}

.ep-course-offer--muted {
    opacity: 0.6;
}

/* ── Card actions ───────────────────────────────────────────────── */

.ep-card-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem;
    margin-top: 1rem;
    padding-top: 0.9rem;
    border-top: 1px solid #f0f0f0;
}

.ep-btn-danger {
    color: #b23c17;
    border-color: #f0d5cb;
}

.ep-btn-danger:hover:not(:disabled) {
    border-color: #b23c17;
}

/* ── Enrollments drill-down ─────────────────────────────────────── */

.ep-drill {
    margin-top: 0.9rem;
    padding-top: 0.9rem;
    border-top: 1px dashed #e5e5e5;
}

/* Explains the ₪1 rows before the reader can misread them as a shortfall. */
.ep-drill-test-note {
    display: flex;
    align-items: flex-start;
    gap: 0.4rem;
    margin: 0 0 0.7rem;
    padding: 0.5rem 0.7rem;
    border-radius: 8px;
    background: #fdf2f6;
    color: #a3134a;
    font-size: 0.78rem;
    line-height: 1.55;
}

.ep-drill-test-note i {
    margin-top: 0.15rem;
    flex: 0 0 auto;
    font-size: 0.72rem;
    opacity: 0.8;
}

.ep-drill-scroll {
    overflow-x: auto;
    overscroll-behavior-x: contain;
    -webkit-overflow-scrolling: touch;
}

.ep-drill-table {
    font-size: 0.82rem;
    min-width: 880px;
}

.ep-drill-table th,
.ep-drill-table td {
    text-align: right;
}

.ep-drill-sub {
    font-size: 0.75rem;
    color: #8e8f9e;
}

.ep-drill-error {
    padding: 0.6rem 0.8rem;
    border-radius: 8px;
    background: rgba(220, 53, 69, 0.08);
    color: #b02a37;
    font-size: 0.82rem;
}

.ep-lead-link {
    color: var(--primary-color, #0071e3);
    font-weight: 600;
    text-decoration: none;
}

.ep-lead-link:hover {
    text-decoration: underline;
}

.ep-paid-short {
    color: #b23c17;
}

/* A cancelled enrollment still counts in the audit trail but is not a live
   sale - mute the whole row so it cannot be misread as one. */
.ep-drill-row--cancelled td {
    opacity: 0.55;
}

.ep-drill-row--cancelled .ep-mini {
    opacity: 1;
}

/* Compact status chips inside the drill-down table. */
.ep-mini {
    display: inline-block;
    padding: 1px 8px;
    border-radius: 999px;
    font-size: 0.72rem;
    font-weight: 600;
    white-space: nowrap;
    background: #f3f4f6;
    color: #6b7280;
}

.ep-mini--signed,
.ep-mini--tp-verified {
    background: rgba(31, 157, 85, 0.12);
    color: #1f7a44;
}

.ep-mini--pending,
.ep-mini--tp-created,
.ep-mini--tp-redirected,
.ep-mini--tp-callback_received {
    background: rgba(255, 163, 4, 0.16);
    color: #9a6b00;
}

.ep-mini--cancelled,
.ep-mini--tp-failed,
.ep-mini--tp-mismatch,
.ep-mini--tp-unmatched {
    background: rgba(196, 85, 26, 0.1);
    color: #b23c17;
}

/* ── Create / edit modal ────────────────────────────────────────── */

/* Widened from 680px when the modal became tabbed (owner, 2026-08-23): a course
   card now carries three money fields on one row plus a percent, a deadline and
   a quota on the next, and 680px squeezed all six. The clamp is unchanged and
   simply bites later - below 892px rather than below 712px. `.ep-share-modal`
   is a separate class at 480px and is deliberately untouched. */
.ep-modal {
    width: 860px;
    max-width: min(860px, calc(100vw - 32px));
}

/* ── The duplicate banner ───────────────────────────────────────────
   Shown only while the modal is a copy form. It sits above the tab strip rather
   than inside `כללי`, because it describes the whole dialog and because a
   reader who lands on an intake tab still needs to know these fields were
   inherited rather than typed. Same shape as `.ep-drill-test-note` - flex, icon
   pinned to the first line - in an informational blue rather than that one's
   warning pink: making a copy is a normal act, not a hazard. */
.ep-dup-note {
    display: flex;
    align-items: flex-start;
    gap: 0.5rem;
    margin: 0 0 1.1rem;
    padding: 0.6rem 0.8rem;
    border-radius: 10px;
    background: #eff5ff;
    color: #1c4a8f;
    font-size: 0.8rem;
    line-height: 1.6;
}

.ep-dup-note i {
    margin-top: 0.25rem;
    flex: 0 0 auto;
    font-size: 0.78rem;
    opacity: 0.75;
}

/* The source page's name and the word מושהה - the two things a reader must not
   skim past. No gradient on this text, so 600 is free to be used here. */
.ep-dup-note strong {
    font-weight: 600;
}

/* ── The modal's tab strip ──────────────────────────────────────────
   The panel's house pill kit (`.course-filter-tabs` in admin.css), co-classed
   so only the things that are specific to a modal live here. */

/* `.course-filter-tabs` is `inline-flex` with no wrap and no responsive rules
   of its own, and both earlier adopters had to add exactly this pair for
   exactly this reason: without it the Hebrew labels force a horizontal
   scrollbar on the whole page at phone widths. The case here is worse than
   theirs - the strip sits INSIDE the modal, so its track is the clamp above,
   and it carries `כללי` plus one tab per intake with no ceiling on the count.
   It wraps to a second row and never scrolls sideways: a scrolled-away intake
   tab is a destination nobody can see. */
.ep-tabs {
    flex-wrap: wrap;
    max-width: 100%;
    margin-bottom: 1.1rem;
}

.ep-tab-panel {
    display: block;
}

.ep-section-title {
    display: flex;
    align-items: baseline;
    gap: 0.4rem;
    flex-wrap: wrap;
    margin: 1.5rem 0 0.75rem;
    padding-bottom: 0.5rem;
    border-bottom: 1px solid #eee;
    font-size: 0.9rem;
    font-weight: 600;
    color: #333;
}

.ep-section-title:first-child {
    margin-top: 0;
}

/* The INTAKE multi-select in `כללי`. It offers intake numbers and never a
   single cohort: ticking one opens its own tab, and the cohorts inside it are
   ticked on their own cards. It replaced the flat cohort picker, whose classes
   went with it, so a spec addressing `.ep-cohort-option` is reading a control
   that no longer exists. */
.ep-intake-picker {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
    gap: 0.4rem;
    max-height: 190px;
    overflow-y: auto;
    overscroll-behavior: contain;
    padding: 0.6rem;
    border: 1px solid #eee;
    border-radius: 8px;
    background: #fafbfd;
}

.ep-intake-option {
    display: flex;
    align-items: center;
    gap: 0.45rem;
    font-size: 0.85rem;
    color: #444;
    cursor: pointer;
    padding: 0.2rem 0.1rem;
}

.ep-intake-option input {
    flex: 0 0 auto;
    accent-color: var(--primary-color, #0071e3);
}

/* The cohort's own enrolment is closed. Since 2026-08-21 that is a BLOCK, not a
   hint: the public page refuses this cohort outright unless the page carries
   the `allowClosedCohorts` override. Hence the alert palette rather than the
   grey it used to wear - but a small chip, because the row it sits in is still
   the thing being read. */
.ep-cohort-closed {
    flex: 0 0 auto;
    padding: 0 7px;
    border-radius: 999px;
    font-size: 0.68rem;
    font-weight: 600;
    background: var(--alert-light, rgba(190, 18, 60, 0.07));
    color: var(--alert-color, #BE123C);
    border: 1px solid var(--alert-border, rgba(190, 18, 60, 0.22));
    white-space: nowrap;
}

/* Override ON: this page MAY sell the closed cohort, so the chip states a fact
   about the cohorts screen instead of warning about a refusal that will not
   happen. Back to the muted hint it always was. */
.ep-cohort-closed--allowed {
    background: #f3f4f6;
    color: #8e8f9e;
    border-color: transparent;
}

/* Per-course price block */

/* Since the modal became tabbed this block holds ONE switch and, when the
   course sells nothing, its warning. The prices moved to `.ep-course-card`
   inside the intake panels, so the padding came down with the content. */
.ep-course-block {
    padding: 0.6rem 1rem;
    margin-bottom: 0.5rem;
    border: 1px solid #eee;
    border-radius: 10px;
    background: #fff;
    transition: opacity 0.2s, background 0.2s;
}

.ep-course-block--off {
    background: #fafafa;
    opacity: 0.6;
}

/* No bottom margin: the head is the whole block now, and the warning below it
   carries its own top margin when there is one. */
.ep-course-block-head {
    display: flex;
    align-items: center;
    gap: 0.65rem;
}

/* The logo components size themselves off the parent font-size - this is the
   only knob that scales them, never the SVG. */
.ep-course-block-name {
    font-size: 1.15rem;
    line-height: 1;
    display: inline-flex;
    align-items: center;
}

/* ── The intake tab's head ──────────────────────────────────────────
   Settings that govern the whole intake, above the per-course cards. */

.ep-intake-head {
    margin-bottom: 0.9rem;
    padding: 0.8rem 1rem;
    border: 1px solid #eee;
    border-radius: 10px;
    background: #fafbfd;
}

/* Two different numbers on this screen are both spelled מחזור - the tab is the
   combined intake, the caption on each card is that course's own run number -
   so the hint leads the panel rather than sitting under it. */
.ep-intake-hint {
    margin: 0 0 0.8rem;
    font-size: 0.78rem;
    line-height: 1.55;
    color: #8e8f9e;
}

.ep-intake-controls {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    align-items: end;
    gap: 0.9rem 1rem;
}

/* The switch takes the full width above the two number fields: it is the one
   control here that answers yes or no rather than how many. */
.ep-intake-switch {
    grid-column: 1 / -1;
    display: flex;
    align-items: center;
    gap: 0.65rem;
    cursor: pointer;
}

.ep-intake-switch-label {
    font-size: 0.85rem;
    color: #555;
}

.ep-intake-controls .form-group {
    margin-bottom: 0;
}

/* The bulk discount writes into every card of the intake at once and then
   steps aside, so it reads as a shortcut rather than as a stored value. */
.ep-bulk-discount .ep-pct-field {
    max-width: 116px;
}

@media (max-width: 767px) {
    .ep-intake-controls {
        grid-template-columns: 1fr;
    }
}

/* ── One course card inside an intake tab ───────────────────────────
   The card left `.ep-course-block` when the modal became tabbed: the three
   course switches stayed in `כללי` and the prices moved into the intake
   panels. FOUR rules were descendant-scoped to that old ancestor and are
   re-scoped here in the same edit, or every row inside a card silently loses
   its spacing and its grid. */

.ep-course-card {
    margin-top: 0.75rem;
    padding: 0.8rem 0.9rem;
    border: 1px solid #f0f0f0;
    border-radius: 10px;
    background: #fbfbfd;
    transition: opacity 0.2s, background 0.2s;
}

/* The page-level course switch is off, so this card sells nothing. Greyed and
   disabled, never hidden and never dropped from the save (D10): what was typed
   here comes back the moment the course is switched on again. */
.ep-course-card--off {
    background: #fafafa;
    opacity: 0.6;
}

.ep-course-card .form-row {
    margin-bottom: 0.35rem;
}

.ep-course-card .form-group {
    margin-bottom: 0;
}

/* Display list price | cohort price | discounted price. Three money fields of
   equal weight, which is what the widened modal bought.

   The phone override lives BESIDE this rule and not in the shared
   `.ep-modal .form-row` block at the end of the file: at (0,3,0) this selector
   out-specifies that one at (0,2,0), so leaving the collapse to it silently
   keeps three columns on a phone and squeezes each number input to about 76px,
   on the screen where prices are typed. Every new grid row inside a card needs
   the same pair. */
.ep-course-card .form-row.ep-price-row {
    grid-template-columns: 1fr 1fr 1fr;
}

/* Percent | discount deadline | seat cap. The percent holds "100" at most, so
   it gets a fixed track; the seat cap carries by far the longest hint, so it
   gets the widest. `align-items: end` bottom-aligns the three inputs - without
   it the row stretches and the quota input sits several lines below its
   neighbours, because its label wraps and theirs do not. */
.ep-course-card .form-row.ep-cohort-extras {
    grid-template-columns: 116px minmax(0, 1fr) minmax(0, 1.4fr);
    align-items: end;
    margin-top: 0.6rem;
}

@media (max-width: 767px) {
    .ep-course-card .form-row.ep-price-row,
    .ep-course-card .form-row.ep-cohort-extras {
        grid-template-columns: 1fr;
    }
}

/* Two controls that mean different things, so they sit on one line and are
   read together: the tick decides whether the page sells this cohort at all,
   the switch pauses selling while keeping every price below it. */
.ep-card-switches {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.5rem 1.25rem;
    margin-bottom: 0.7rem;
}

.ep-card-tick {
    display: flex;
    align-items: center;
    gap: 0.45rem;
    font-size: 0.85rem;
    font-weight: 500;
    color: #444;
    cursor: pointer;
}

.ep-card-tick input {
    flex: 0 0 auto;
    accent-color: var(--primary-color, #0071e3);
}

.ep-card-switch {
    display: flex;
    align-items: center;
    gap: 0.55rem;
    cursor: pointer;
}

.ep-card-switch-label {
    font-size: 0.85rem;
    color: #555;
}

/* Neutral grey and not the amber of `.ep-course-warn`: nothing is
   misconfigured here. The card is simply following a switch in `כללי`. */
.ep-card-off-note {
    display: flex;
    align-items: flex-start;
    gap: 0.4rem;
    margin: 0.6rem 0 0;
    padding: 0.5rem 0.7rem;
    border-radius: 8px;
    background: #f3f4f6;
    color: #494950;
    font-size: 0.78rem;
    line-height: 1.55;
}

.ep-card-off-note i {
    margin-top: 0.15rem;
    flex: 0 0 auto;
}

/* `.ep-pct-field` and `.ep-quota-field` carry no box rules of their own on
   purpose: they are `.form-input` like every other number on the card and must
   keep its alignment, which the island inherits. They exist as stable hooks -
   the percent replaced a preset dropdown and a card now holds five number
   inputs, so nothing may address one of them by DOM position. */

/* `.ep-cohort-price` is a CO-CLASS on `.ep-course-card` and carries no box
   rules: the card above owns the box. It survives purely as the selector a
   dozen assertions address a per-cohort card by, so dropping it turns every one
   of them into an empty search that proves nothing rather than failing.

   The cohort's name is a CAPTION LINE over the card and deliberately not a
   grid column: `.ep-price-row` spends the row on three money fields, and a
   caption column takes the width out of the numbers being read and typed. */
.ep-cohort-price-label {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.4rem;
    margin-bottom: 0.5rem;
    font-size: 0.82rem;
    font-weight: 600;
    color: #494950;
}

/* The same shape as `.ep-datetime`, under a name of its own. That class is how
   tests/AdminEnrollmentPages.spec.ts addresses the two PAGE deadlines - it
   counts the date and time inputs it finds - and a cohort's offer deadline is
   not one of them. */
.ep-cohort-dt {
    display: flex;
    gap: 0.5rem;
}

.ep-cohort-dt .ep-dt-date {
    flex: 1 1 auto;
    min-width: 0;
}

.ep-cohort-dt .ep-dt-time {
    flex: 0 0 96px;
}

@media (max-width: 767px) {
    .ep-cohort-dt {
        flex-wrap: wrap;
    }

    .ep-cohort-dt .ep-dt-date,
    .ep-cohort-dt .ep-dt-time {
        flex: 1 1 100%;
    }
}

/* Deadline entry: a date input beside a time input, replacing the single
   datetime-local that used to discard a date typed without a time. The time is
   fixed-width - it holds "23:59" and nothing longer - so the date field takes
   the slack and both stay readable at the modal's two-column width. */
.ep-datetime {
    display: flex;
    gap: 0.5rem;
}

.ep-datetime .ep-dt-date {
    flex: 1 1 auto;
    min-width: 0;
}

.ep-datetime .ep-dt-time {
    flex: 0 0 108px;
}

@media (max-width: 767px) {
    .ep-datetime {
        flex-wrap: wrap;
    }

    .ep-datetime .ep-dt-date {
        flex: 1 1 100%;
    }

    .ep-datetime .ep-dt-time {
        flex: 1 1 100%;
    }
}

/* Read-only derived hints (discount percent, deposit explainer). */
.ep-derived {
    font-size: 0.78rem;
    color: #8e8f9e;
    line-height: 1.5;
}

/* An enabled course with no matching cohort is dropped from the public page -
   amber, not red: it is a misconfiguration to notice, not a blocked save. */
.ep-course-warn {
    display: flex;
    align-items: flex-start;
    gap: 0.4rem;
    margin: 0.6rem 0 0;
    padding: 0.5rem 0.7rem;
    border-radius: 8px;
    background: rgba(255, 159, 10, 0.12);
    color: #8a5300;
    font-size: 0.78rem;
    line-height: 1.55;
    font-weight: 500;
}

.ep-course-warn i {
    margin-top: 0.15rem;
    flex: 0 0 auto;
}

.ep-deposit-row {
    display: flex;
    align-items: center;
    gap: 0.65rem;
    margin-bottom: 0.4rem;
}

.ep-deposit-label {
    font-size: 0.85rem;
    color: #555;
    flex: 1 1 auto;
}

.ep-deposit-input {
    flex: 0 0 140px;
    width: 140px;
}

/* The amount and its ex-VAT hint travel as one flex item so the hint sits under
   the NUMBER rather than at the start of the row. It shrink-wraps to the input's
   own 140px, so the row's geometry is exactly what it was before the wrapper. */
.ep-deposit-amount {
    flex: 0 0 auto;
    min-width: 0;
}

/* Test-mode panel in the modal. Its own bordered block rather than another
   row in the settings list: this is the switch that stops a page selling for
   real, so it must not be flippable absently or skimmable when reading a page
   back. Stays visibly inert until it is on, then goes loud. */
.ep-test-panel {
    margin-top: 1.25rem;
    padding: 0.9rem 1rem;
    border: 1px solid #eee;
    border-radius: 10px;
    background: #fafbfd;
    transition: background 0.2s, border-color 0.2s;
}

.ep-test-panel--on {
    border-color: #f3c6d3;
    background: #fdf2f6;
}

.ep-test-head {
    display: flex;
    align-items: center;
    gap: 0.65rem;
    cursor: pointer;
}

.ep-test-title {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    font-size: 0.9rem;
    font-weight: 600;
    color: var(--text-color, #191a23);
}

.ep-test-panel--on .ep-test-title {
    color: #a3134a;
}

.ep-test-title i {
    font-size: 0.8rem;
    opacity: 0.75;
}

.ep-test-help {
    margin: 0.55rem 0 0;
    font-size: 0.78rem;
    line-height: 1.6;
    color: #8e8f9e;
}

.ep-test-panel--on .ep-test-help {
    color: #6b6c7a;
}

/* Blocks the save, so it reads as an error rather than a note. */
.ep-test-conflict {
    display: flex;
    align-items: flex-start;
    gap: 0.4rem;
    margin: 0.6rem 0 0;
    padding: 0.5rem 0.7rem;
    border-radius: 8px;
    background: rgba(220, 53, 69, 0.09);
    color: #b02a37;
    font-size: 0.78rem;
    line-height: 1.55;
    font-weight: 500;
}

.ep-test-conflict i {
    margin-top: 0.15rem;
    flex: 0 0 auto;
}

/* ── "this intake is free" ──────────────────────────────────────── */
/* Same shape as .ep-test-conflict, deliberately NOT its red. Nothing has gone
   wrong here: a 0 in the price box is a legal, chosen setting, and painting it
   as an error teaches staff to read red as decoration. Amber says "you meant
   this, and it matters" - which is exactly what the save dialog then asks. */
.ep-free-note {
    display: flex;
    align-items: flex-start;
    gap: 0.4rem;
    margin: 0.4rem 0 0;
    padding: 0.45rem 0.65rem;
    border-radius: 8px;
    background: rgba(214, 158, 46, 0.12);
    color: #8a5d0b;
    font-size: 0.75rem;
    line-height: 1.5;
    font-weight: 500;
}

.ep-free-note i {
    margin-top: 0.15rem;
    flex: 0 0 auto;
}

/* ── The ex-VAT parenthetical ───────────────────────────────────── */
/* Base styling is shared (.exvat / .exvat-legend, admin-money.css). Only what
   this screen's own surfaces need is tuned here. */

/* The legend rides the filter bar, whose `align-items: flex-end` would
   otherwise pin it to the very bottom of the select beside it. */
.ep-filter-bar .exvat-legend {
    margin: 0 0 0.45rem;
}

/* Inside a course pill the ex-VAT figure keeps the pill's own hue and steps back
   with opacity instead. The shared grey is tuned for ink on white, and a neutral
   grey sitting inside a tinted blue/violet/amber pill reads as a rendering fault
   rather than as small print. Size, weight and the gap are left to the shared
   `.exvat` / `.exvat--inline` - the markup nests the component INSIDE
   `.ep-course-price` rather than beside it, so it stays inline text within one
   flex item and keeps the single space ExVat.vue emits, instead of being
   blockified into a second flex item and taking a second helping of the pill's
   `gap`. */
.ep-course-pill .exvat {
    color: inherit;
    opacity: 0.62;
}

/* ── Share panel ────────────────────────────────────────────────── */

.ep-share-modal {
    width: 480px;
    max-width: min(480px, calc(100vw - 32px));
}

.ep-share-body {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.9rem;
    text-align: center;
}

.ep-share-title {
    font-size: 1rem;
    font-weight: 600;
    color: var(--text-color, #191a23);
}

.ep-qr {
    width: 100%;
    max-width: 320px;
    height: auto;
    border: 1px solid #eee;
    border-radius: 12px;
    background: #fff;
}

.ep-share-url {
    width: 100%;
    padding: 0.6rem 0.75rem;
    border-radius: 8px;
    background: #f6f8fc;
    font-family: var(--font-mono, monospace);
    font-size: 0.95rem;
    color: var(--text-color, #191a23);
    word-break: break-all;
    text-align: center;
}

.ep-share-actions {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 0.5rem;
}

/* ── Responsive ─────────────────────────────────────────────────── */

@media (max-width: 1024px) {
    .ep-card-counts {
        gap: 1.1rem;
    }
}

@media (max-width: 767px) {
    .ep-card {
        padding: 1rem;
    }

    .ep-card-head {
        gap: 0.75rem;
    }

    .ep-card-counts {
        width: 100%;
        justify-content: flex-start;
        gap: 1.5rem;
    }

    .ep-url-row {
        flex-wrap: wrap;
    }

    .ep-url {
        flex: 1 1 100%;
    }

    .ep-meta-grid {
        grid-template-columns: 1fr;
    }

    .ep-modal .form-row {
        grid-template-columns: 1fr;
    }

    .ep-intake-picker {
        grid-template-columns: 1fr;
    }

    .ep-deposit-row {
        flex-wrap: wrap;
    }

    .ep-deposit-input {
        flex: 1 1 100%;
        width: 100%;
    }

    /* The wrapper is the flex item now, so it is the one that has to take the
       whole row - the input's own rule above then fills it. */
    .ep-deposit-amount {
        flex: 1 1 100%;
    }
}

/* ── Touch floors (admin mobile revamp) ───────────────────────────────
   44px targets and 16px input text below 1025px; an iOS input under 16px
   zooms the whole page on focus. Desktop keeps the compact sizes. */
@media (max-width: 1024px) {
    .ep-page .btn,
    .ep-page .btn-icon {
        min-height: 44px;
        min-width: 44px;
    }

    .ep-page .form-input,
    .ep-page .form-select,
    .ep-page .form-textarea {
        font-size: 16px;
        min-height: 44px;
    }

    /* An intake row in the multi-select is one tap target. */
    .ep-intake-option {
        min-height: 44px;
    }

    /* And so is a card's membership tick. */
    .ep-card-tick {
        min-height: 44px;
    }

    /* The floors above target `.btn`, `.btn-icon` and the three form controls,
       none of which a `.course-filter-tab` is - its desktop height is 29px. The
       kit itself carries no floor, by design: every host sheet floats its own,
       and this is ours. */
    .ep-tabs .course-filter-tab {
        min-height: 44px;
    }
}
