/* ── Admin: All enrollments (/admin/enrollments) ─────────────────────
   Cross-cohort enrollments table. Builds on the shared admin table,
   filter-bar and pill helpers in admin.css (reg-* family); this file
   only skins what is unique to the page. */

/* This page's UI copy is Hebrew - re-establish RTL inside the LTR-pinned
   .admin-main (same scoped-island pattern as contracts/leads). LTR-sensitive
   values (emails, phones, dates, amounts) carry dir="ltr" in the template. */
.enr-page {
    direction: rtl;
    text-align: right;
}

/* ── The .enr-page homonym: neutralise the public checkout's leak ─────
   enrollment-page.css (the public /e funnel) owns a root class with the same
   name, so its 100vh gradient page shell leaks onto /admin/enrollments (the
   collision is documented in public/css/CLAUDE.md). The cascade order between
   the two files FLIPS between dev and production, so this override outranks
   by SPECIFICITY instead: only the admin screen renders inside .admin-main,
   the public funnel never does. Values restore the admin shell's own neutral
   surface. */
.admin-main .enr-page {
    min-block-size: 0;
    padding: 0;
    background: none;
    color: inherit;
}

/* Mirror the search box adornments (admin.css positions them physically). */
.enr-page .admin-search .fa-search {
    left: auto;
    right: 10px;
}

.enr-page .search-clear {
    right: auto;
    left: 6px;
}

.enr-page .reg-filter-bar .form-select,
.enr-page .reg-filter-bar .form-input {
    text-align: right;
}

/* ── The course-start notice button ──────────────────────────────────
   The one control in this page header that leaves the panel and reaches a
   person: the two beside it reload the table and download it. So it is the one
   that is tinted, and it is pushed a little clear of them, because a press
   meant for ייצוא CSV must not be able to land on a WhatsApp send. It is
   ABSENT, not greyed, for a reader without `leads:full` - that gate is in the
   view, never here.

   The WhatsApp greens are declared literally rather than borrowed from
   `--wa-green*` in admin-wa-bulk.css: those are custom properties on
   `.wab-scope`, a class on the bulk SHEET, so inheriting them would make this
   button's colour depend on a modal being mounted. Same hexes, and they are
   WhatsApp's brand colours rather than the site's - the brand gradient is
   forbidden at button weight anyway.

   No `.enr-page` prefix is needed for the public-checkout homonym documented
   above: enrollment-page.css owns no `.enr-wa-*` rule, so nothing here can be
   won or lost by the dev/production cascade flip. */

.enr-wa-btn {
    margin-inline-start: 0.35rem;
    /* Three Hebrew words. The header toolbar wraps as a whole below 1025px, and
       a button that wraps INSIDE itself instead loses the 44px touch floor's
       shape and reads as two controls. */
    white-space: nowrap;
    border-color: rgba(37, 211, 102, 0.55);
    background: rgba(37, 211, 102, 0.1);
    color: #117335;
}

.enr-wa-btn:hover {
    border-color: #25d366;
    background: rgba(37, 211, 102, 0.18);
    color: #0d5c2a;
}

.enr-wa-btn-icon {
    color: #25d366;
}

/* The glyph darkens WITH the label on hover: at rest the green mark is what
   names the channel, and on a wash this much stronger it stops reading. */
.enr-wa-btn:hover .enr-wa-btn-icon {
    color: #117335;
}

/* The queue's progress card, between the page header and the money band.
   `.wab-card` (admin-wa-bulk.css) declares a top margin only - on the two CRM
   screens it is the last thing above a table and needs no bottom - so the gap
   to the KPI band underneath it is this page's to declare. */
.enr-page .wab-card {
    margin-block-end: 1rem;
}

/* ── מחזור filter: the two states that are not a picker ──
   Cohort NAMES come from an endpoint gated on `course-cohorts:read`, which this
   page itself does not require. Where the picker cannot be populated it is not
   offered, and where a `?cohort=` from a shared link still narrows the table it
   is named and removable. Both states sit in the filter bar where the picker
   would have been, so the bar keeps its rhythm; neither may look like an empty
   dropdown. Sizing follows `.reg-filter-field .form-select` in admin.css. */

.enr-filter-locked {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    /* Same box as the picker it stands in for, so the labels along the filter
       bar stay on one baseline: 2 x 1px border + 2 x 0.45rem padding + the
       select's 18px content box. A shorter chip drops its own label 2px. */
    min-block-size: 2.15rem;
    padding: 0.45rem 0.7rem;
    background: #f6f8fb;
    border: 1px solid #e2e8f2;
    border-radius: 6px;
    font-size: 0.88rem;
    color: var(--adm-ink-2);
}

.enr-filter-locked-name {
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
}

.enr-filter-locked-clear {
    flex: none;
    margin-inline-start: auto;
    padding: 0 0.15rem;
    background: none;
    border: 0;
    color: var(--adm-ink-3);
    font-size: 0.82rem;
    line-height: 1;
    cursor: pointer;
}

.enr-filter-locked-clear:hover {
    color: #b3352c;
}

/* Sits under the picker, inside the same column flex - the picker stays usable
   while it shows, because a stale option list is still better than none. */
.enr-filter-note {
    display: flex;
    align-items: center;
    gap: 0.35rem;
    padding: 0;
    background: none;
    border: 0;
    color: #b3352c;
    font-family: inherit;
    font-size: 0.74rem;
    text-align: start;
    cursor: pointer;
}

.enr-filter-note:hover {
    text-decoration: underline;
}

/* ── KPI band: one glass instrument, hairline-separated tiles ── */

.enr-kpis {
    display: flex;
    align-items: stretch;
    flex-wrap: wrap;
    gap: 0.75rem;
    padding: 0.7rem 1rem;
    margin-bottom: 0.85rem;
    background: var(--adm-glass);
    -webkit-backdrop-filter: var(--adm-glass-blur);
    backdrop-filter: var(--adm-glass-blur);
    border: 1px solid var(--adm-glass-border);
    border-radius: 14px;
    box-shadow: var(--adm-glass-shadow);
}

/* Contents pinned to the TOP, not centred. The tiles stretch to a common
   height and the band now mixes THREE-line money tiles (figure / ex-VAT /
   label) with TWO-line count tiles; centring each tile's own column floats the
   count tiles' figures half a line below the money tiles' and the band stops
   reading as one instrument. Top-aligned, every figure sits on the same line -
   and the labels are pulled back down to the bottom edge by their own auto
   margin, so the second row lines up too. */
.enr-kpi {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: flex-start;
    gap: 0.15rem;
    min-width: 110px;
    padding: 0.35rem 0.9rem;
    border: 1px solid transparent;
    border-radius: 12px;
}

.enr-kpi:not(:first-child) {
    border-inline-start-color: var(--adm-line);
    border-start-start-radius: 0;
    border-end-start-radius: 0;
}

/* Solid ink, weight 600 - the brand gradient stays off work-surface numerals. */
.enr-kpi-value {
    font-size: 1.18rem;
    font-weight: 600;
    color: #191A23;
    white-space: nowrap;
}

.enr-kpi--balance .enr-kpi-value {
    color: #C4551A;
}

/* Money that is already LATE - a subset of the balance beside it, and the
   only tile on the band that is about a deadline rather than a total. Louder
   than the balance's rust because it is the one figure here somebody is
   expected to act on today, and it appears only when it is non-zero, so the
   red is never ambient.

   A solid colour, never the brand gradient: the repo's rule puts that ramp on
   hairlines and light weights only, and these numerals are 600. */
.enr-kpi--pastdue .enr-kpi-value {
    color: #B3261E;
}

/* Rows with no agreed amount: a caveat on the balance beside it, not a
   headline number of its own. */
.enr-kpi--unpriced .enr-kpi-value {
    color: #8E8F9E;
}

/* Every tile that explains itself in a tooltip gets the help cursor, so a new
   explained tile cannot be added without the affordance following it. */
.enr-kpi[title] {
    cursor: help;
}

/* The other half of the top-alignment above: the label takes whatever vertical
   slack its tile has, so a two-line tile's label drops to the same baseline as
   a three-line tile's instead of floating in the middle of the box. A tile with
   no slack (the money ones, which set the band's height) resolves this to zero
   and is unaffected. */
.enr-kpi-label {
    margin-block-start: auto;
    font-size: 0.72rem;
    color: #8E8F9E;
    white-space: nowrap;
}

/* The ex-VAT legend, as the band's own footer row rather than a line floating
   underneath it: the tiles and the table's three money columns both print the
   short "(10,331 ₪)" form, and this is the single place on the page that says
   what those parentheses are. `flex-basis: 100%` is what makes it a row of its
   own instead of a sixth tile - it carries no .enr-kpi class, so the hairline
   separator between tiles never reaches it. Alignment is left to the RTL
   island, so it starts under the first tile. */
.enr-kpi-legend {
    flex: 1 0 100%;
    margin: 0.1rem 0 0;
    padding-inline: 0.15rem;
}

/* ── Quick-filter pill rows ── */

.enr-pillbars {
    display: flex;
    flex-direction: column;
    gap: 0.2rem;
    margin-bottom: 0.6rem;
}

/* ── Failed load: stale data, and a load that never landed ──
   A failed refresh leaves the PREVIOUS filter's rows and money on screen. They
   stay readable (they were true a minute ago) but must not look current, so
   EVERY block rendered from that payload is visibly held back - the money band,
   the faceted pill counts, the table and the pagination footer - and the banner
   names why. Half a page dimmed is worse than none: the un-dimmed numbers then
   read as the current ones. The banner and its retry button stay at full
   contrast; they are the way out. */

.enr-stale {
    opacity: 0.5;
    filter: saturate(0.6);
    transition: opacity 0.15s;
}

.enr-stale-note {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.5rem;
    margin-bottom: 0.7rem;
    padding: 0.55rem 0.85rem;
    background: #fff8e1;
    border: 1px solid #f0dca8;
    border-radius: 12px;
    font-size: 0.84rem;
    color: #7a5c12;
}

.enr-stale-note .fa-triangle-exclamation {
    color: #C4551A;
}

.enr-stale-note .btn {
    margin-inline-start: auto;
}

.enr-load-error {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.7rem;
}

.enr-load-error-text {
    margin: 0;
    color: #b3352c;
}

/* ── Sort control (phone / tablet only) ──
   Hidden here, shown by the 1024px block below where <thead> - and with it
   every sortable header - is dropped. */

.enr-sortbar {
    display: none;
    align-items: center;
    gap: 0.5rem;
    margin-bottom: 0.6rem;
}

.enr-sortbar-label {
    font-size: 0.78rem;
    color: #8E8F9E;
}

.enr-sort-select {
    flex: 1 1 auto;
    min-width: 0;
    min-height: 44px;
    text-align: right;
}

/* ── Selection toggle in the sortbar (phone / tablet only) ──
   Below 1024px <thead> is dropped, so the select-all header checkbox does not
   exist on a phone at all. The affordance there is a MODE, hosted in the sortbar
   because that is already this page's only phone/tablet control strip, already
   guarded on there being rows, and already directly above the cards. Hidden here
   and shown by the 1024 block, exactly like .enr-sortbar itself. */
.enr-tool {
    display: none;
    align-items: center;
    justify-content: center;
    min-width: 44px;
    min-height: 44px;
    border: 1px solid var(--adm-line);
    border-radius: 10px;
    background: #fff;
    color: var(--text-color);
}

.enr-tool--on {
    background: #eff6ff;
    border-color: #93c5fd;
    color: #0071e3;
}

/* ── Bulk-action bar ──
   `.reg-bulk-bar` in admin.css carries the dark slab, the white-on-dark button
   skin and the red danger variant; this class carries only the geometry, exactly
   as `.leads-bulk-bar` does beside it. Desktop: sticky to the top of the
   scroller, so a mark made at row 180 can be acted on without scrolling back up
   to find the bar. The phone half - fixed to the bottom edge - is in the 1024
   block, and the `inset-block-start: auto` there is load-bearing against this
   `top`. */
.enr-bulk-bar {
    position: sticky;
    top: 0;
    z-index: 20;
}

/* The whole-filter promotion reads as a SENTENCE, not as a sibling of the action
   buttons: it changes WHO the actions are about, the others change WHAT happens
   to them. Transparent and underlined instead of another filled pill on the
   slab. */
.enr-bulk-scope {
    background: transparent;
    border-color: rgba(255, 255, 255, 0.35);
    text-decoration: underline;
    text-underline-offset: 3px;
}

/* Phone-only overflow door. Shown by the 767 block, where the four
   `.enr-bulk--folds` controls fold behind it so the fixed bar stays one thumb
   swipe wide. */
.enr-bulk-more {
    display: none;
}

/* ── Bulk result panel ──
   A per-row report ("4 עודכנו, 1 לא נמצאה") that a 3.2s toast cannot carry, and
   that a bulk action over rows the reader cannot all see has to leave behind. */
.enr-bulk-report {
    margin: 0 0 0.85rem;
    padding: 0.8rem 1rem;
    background: #fff;
    border: 1px solid #e6ebf2;
    border-radius: 12px;
}

.enr-bulk-report__line {
    margin: 0.15rem 0;
    font-size: 0.86rem;
}

.enr-bulk-report__names {
    margin: 0 0 0.4rem;
    color: #8E8F9E;
    font-size: 0.8rem;
}

/* ── Table ── */

/* Horizontal scroll lives here, never on the page body. Contained so a
   swipe that reaches the table's edge does not start dragging the page. */
.enr-table-wrap {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior-x: contain;
}

.enr-table {
    /* 1316px + the 44px selection column declared below. The two numbers are a
       pair: widen the column without this and the last money column loses the
       room instead.

       Since the column picker shipped the NUMBER comes from the registry -
       `useAdminColumns().widthPx` sums the width share of every column actually
       on screen and publishes it as `--enr-cols-width` on the <table>. Hiding
       six columns now shrinks the floor instead of stretching six survivors
       across 1360px of reserved emptiness.

       It has to be a custom property and never an inline `min-width`: an inline
       declaration would outrank the `min-width: 0` in the 1024 block below
       regardless of the media query, and every phone card would inherit a
       1360px floor. The fallback is the old hand-sum, so a build with no
       registry width still lands exactly where it does today.

       THE FALLBACK WAS 1264px UNTIL `carPlate` SHIPPED VISIBLE (2026-09-03).
       It and the width shares in `src/lib/adminColumns/enrollments.ts` are one
       number written twice: move one without the other and the table reserves a
       width nothing else agrees with. */
    min-width: var(--enr-cols-width, 1360px);
}

.enr-table th,
.enr-table td {
    white-space: nowrap;
}

.enr-row--clickable {
    cursor: pointer;
}

.enr-row--clickable:hover td {
    background: #f5f9ff;
}

/* Cancelled rows stay visible for the record but read as history. */
.enr-row--cancelled td {
    opacity: 0.55;
}

/* ── Bulk-selection checkbox column ───────────────────────────────────
   FIRST cell of the row, header and body alike. Leading and not trailing
   because both places the mark has to live sit at the inline start: the frozen
   identity column on desktop (below) and the card's `name` area under 1024px.

   The column is rendered only for an account that may manage enrollments, so it
   is present for one reader and absent for the next - which is why no rule on
   this page may address a cell by POSITION any more (see the card block far
   below, where three `td:nth-child()` rules became classes for exactly this
   reason). 44px is the touch floor this admin uses everywhere, and it is
   repeated as the sticky offset in the desktop block: change one, change both.

   The `padding-inline` here LOSES, and deliberately so - see the desktop block
   below, which re-declares it at a specificity that wins. Kept at this weight
   because the card-mode `.enr-row--picking .enr-cell-check` rule needs to beat
   it with `padding: 0`, and it is only two classes. */
.enr-th-check,
.enr-cell-check {
    width: 44px;
    min-width: 44px;
    text-align: center;
    padding-inline: 0.4rem;
}

.enr-cell-check input[type="checkbox"] {
    cursor: pointer;
}

/* The selected-row tint, both halves, because neither shared half reaches this
   table: admin.css keys them on `.reg-row--selected` (and the card-mode one on
   `.reg-table` as well), and these rows carry `.enr-row--selected` on a
   `class="admin-table enr-table"`. So the desktop cell tint is here and the
   card-mode mark is inside the 1024 block, mirroring the shared pair value for
   value. `!important` is what keeps the tint on a row that is also hovered. */
.enr-table tbody tr.enr-row--selected td {
    background: #eff6ff !important;
}

/* ── Desktop-only sticky identity column ─────────────────────────────
   REVIEW: verify in a live RTL viewport (this worktree cannot render one).
   The wide table (min-width 1360px) pans horizontally on a narrower desktop, so
   the first columns - the selection box and the buyer's name - are frozen at the
   inline-start edge and the money columns a figure belongs to are never read
   against the wrong row. Scoped to >=1025px because below that the table is a
   card stack, not a table.

   Freezes the IDENTITY column, NOT a money column: the three money columns are
   interior and position:sticky can only pin a cell to a scroll edge, so pinning
   one would detach it and overlap its neighbours. The frozen cell needs an
   opaque background or the panned cells bleed through it, and the row hover is
   re-asserted on it so it tints with the rest of its row. Nothing between the
   cell and .enr-table-wrap sets overflow, so the wrapper is the scroll container
   the sticky sticks to.

   ADDRESSED BY CLASS, never by position. This block used to say
   `th:first-child`, which the selection header silently stole the moment the
   checkbox column was added: the NAME header stopped being frozen while
   `td.enr-cell-name` stayed frozen, so a header scrolled sideways away from its
   own column and nothing failed anywhere else. Both halves carry a class now. */
@media (min-width: 1025px) {
    .enr-table th.enr-th-check,
    .enr-table td.enr-cell-check {
        position: sticky;
        inset-inline-start: 0;
        z-index: 1;
        background: #fff;
        /* THIS IS WHAT MAKES THE 44px BELOW TRUE, and it is here rather than
           beside the `width` because only the frozen pair depends on it and
           because the card-mode rule must keep outranking that one.
           `admin.css` sets `.admin-table td { padding: 0.65rem 1rem }` at
           (0,1,1), which beats a bare `.enr-cell-check` (0,1,0), so this column
           was being laid out with 16px of inline padding it never asked for. A
           cell cannot be narrower than its own min-content, and 13px of
           checkbox plus 32px of padding is 45.5px, so `table-layout: auto`
           silently overrode the declared 44px: the frozen NAME column, pinned
           at exactly 44px, ended up 1.5px underneath the boxes once the table
           was panned sideways. Measured in a real RTL viewport, not guessed. */
        padding-inline: 0.4rem;
    }

    /* 44px is the checkbox column's own declared width above, and the padding
       override in the rule above is what keeps that declaration honest - the
       two numbers must move together or the name lands on top of the boxes. */
    .enr-table th.enr-th-name,
    .enr-table td.enr-cell-name {
        position: sticky;
        inset-inline-start: 44px;
        z-index: 1;
        background: #fff;
    }

    /* A read-only account has no checkbox column at all, so on that account the
       name IS the first cell and starts at the edge. */
    .enr-table thead tr:not(:has(> .enr-th-check)) th.enr-th-name,
    .enr-table tbody tr:not(:has(> .enr-cell-check)) td.enr-cell-name {
        inset-inline-start: 0;
    }

    .enr-table th.enr-th-check,
    .enr-table th.enr-th-name {
        z-index: 2;
        background: #fafafa;
    }

    /* #f8f9ff is what the shared .admin-table hover actually paints on these
       rows (it outweighs the enr-specific #f5f9ff rule), so the frozen cell
       matches the rest of the hovered row instead of staying white. */
    .enr-table tr:hover td.enr-cell-check,
    .enr-table tr:hover td.enr-cell-name {
        background: #f8f9ff;
    }

    /* A selected row's frozen cells. The `!important` selected tint declared
       above already reaches them; this repeats the colour so the pair reads as
       one decision beside the hover rule it sits under. */
    .enr-table tbody tr.enr-row--selected td.enr-cell-check,
    .enr-table tbody tr.enr-row--selected td.enr-cell-name {
        background: #eff6ff;
    }
}

/* The keyboard-reachable way into the sale's own page. It has to LOOK like the
   plain bold name it wraps - the row's own hover already says the row is live,
   and a blue underlined name in every row would turn the first column into a
   wall of links. The focus ring is the browser default, deliberately left
   alone: it is the only thing that shows a keyboard user where they are. */
.enr-name-link {
    color: inherit;
    text-decoration: none;
}

.enr-name-link:hover,
.enr-name-link:focus-visible {
    text-decoration: underline;
}

.enr-cell-contact,
.enr-cell-cohort,
.enr-cell-when {
    line-height: 1.35;
}

.enr-cell-contact span,
.enr-cell-cohort span,
.enr-cell-when span {
    display: block;
}

/* The column's own width. Without it the header carries a class that styles
   nothing and the column is sized entirely by its widest chip, which on a
   partner named at length pushes the money columns off the visible area. The
   cell's own max-width is what does the clipping; this reserves the room. */
.enr-th-origin {
    width: 210px;
    min-width: 150px;
}

/* ── The "מקור" cell: how the buyer was WON ────────────────────────────────
   Two stacked lines - the resolved bucket, then the partner code that earned it.

   THE CELL ITSELF MUST STAY A TABLE-CELL. `display: flex` on this `<td>` looks
   like the natural way to stack two chips and it silently destroys the row:
   `.enr-cell-actions` right next to it is ALREADY `display: flex` (see below),
   and CSS wraps a RUN of adjacent non-table-cell children of a `<tr>` in ONE
   anonymous table cell - so the two cells merge into a single column and stack
   vertically, the actions landing underneath the chips. Measured in Chromium at
   1440px: every ordinary `<td>` reported the row's full 139px height while
   these two reported 59px and 79px, one directly below the other. It also makes
   `vertical-align: middle` inert and leaves the row's bottom border broken
   across those columns.

   So the stacking is done by the CHILDREN instead. `display: flex` on a child
   is a BLOCK-level flex box, which is what puts each chip on its own line, and
   `width: fit-content` is what stops that block stretching to the full column
   width - the one thing a chip must never do, since its background is what
   makes it read as a chip. This is also why the cell cannot join the
   `span { display: block }` list above: that is a descendant selector, and this
   cell's first line is a pill with a span INSIDE it carrying the ellipsis. */
.enr-cell-origin {
    line-height: 1.35;
    max-width: 210px;
}

.enr-cell-origin > * {
    display: flex;
    width: fit-content;
    max-width: 100%;
}

.enr-cell-origin > .enr-aff-chip,
.enr-cell-origin > .enr-origin-later {
    margin-top: 0.15rem;
}

/* The resolved traffic bucket (Meta / Telegram / the partner's group). Neutral
   by default; the confirmed-paid variant borrows the affiliate chip's blue so a
   billed click reads distinct at a glance. Copied from `.lead-origin-chip`
   rather than reused: admin-leads.css is globally linked, so borrowing its
   class would work today and silently redraw this column the day the leads chip
   is restyled. */
.enr-origin-chip {
    margin-left: 0;
    max-width: 100%;
    min-width: 0;
    background: #f8fafc;
    color: #334155;
    border-color: #e2e8f0;
    font-weight: 600;
    white-space: nowrap;
    overflow: hidden;
    line-height: 1.25;
}

/* The ellipsis lives on the CHILD, not on the pill. `.reg-source-badge` is
   `inline-flex`, where `text-overflow` is inert - on the leads table it sat on
   the pill for months and clipped long partner names mid-glyph with no mark at
   all. The full label is on the chip's title. */
.enr-origin-chip > span {
    overflow: hidden;
    text-overflow: ellipsis;
}

.enr-origin-chip--paid {
    background: #eef4ff;
    color: #2456c4;
    border-color: #d5e3fb;
}

/* A snapshot REBUILT from the CRM after the fact rather than captured when the
   money moved - so it may describe a later touch than the one that won the
   sale. The dashed border is the whole disclosure at this width; the sentence
   saying so is in the cell's tooltip, and the person page states it in full.

   A DASHED BORDER and not the obvious dotted underline: the chip carries
   `overflow: hidden` (it has to - that is what arms the ellipsis on its inner
   span), and `overflow` clips ink to the PADDING box, which is where a text
   decoration is painted. A border is drawn on the border box, outside that
   clip, so it cannot be cropped at any font size or line height. It also
   follows the pill's own radius, which an underline does not.

   It must never be styled as an error: a reconstructed attribution is the best
   answer we have for most historical sales, not a broken one - hence a neutral
   grey and a border that was already there, only solid. */
.enr-origin-chip--rebuilt {
    border-style: dashed;
}

/* Only where the paid variant has not already spoken for the colour. The two
   modifiers are independent - a confirmed paid click CAN carry a rebuilt
   snapshot - and a flat `border-color` here would sit after
   `.enr-origin-chip--paid` in this sheet and grey out its blue rim while
   leaving the blue fill behind it. The dashed STYLE above is unconditional,
   because that is the part carrying the disclosure. */
.enr-origin-chip--rebuilt:not(.enr-origin-chip--paid) {
    border-color: #c7cedb;
}

/* The partner code that earned the sale, with its human name beside it, so
   identifying the partner does not require the tooltip. Present even when the
   bucket above says "Meta": a paid click and a partner link can both be on the
   URL that converted, and only this line says which partner. */
.enr-aff-chip {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    max-width: 100%;
    background: #eef4ff;
    color: #2456c4;
    border: 1px solid #d5e3fb;
    border-radius: 5px;
    padding: 0 0.35rem;
    font-size: 0.66rem;
    font-weight: 700;
    letter-spacing: 0.05em;
}

.enr-aff-name {
    font-weight: 600;
    letter-spacing: 0;
    max-width: 110px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* ── The third line: what came AFTER the origin ──────────────────────────────
   Deliberately the QUIETEST thing in the cell. The headline above it answers
   the column's question ("where did this person come from"), and this line is
   context - a later touch that did not win the sale. Painted as a chip it would
   read as a second, competing verdict, which is the exact confusion this column
   was rebuilt to end: the leads table said one partner and this table said Meta
   about the same buyer, because both were printing a LAST touch as an origin.

   No background, no border, no pill. Muted, one size down from the cell, one
   clipped line - the full text is on the line's own title.

   `.enr-cell-origin > *` above already makes this a block-level flex box, which
   is what puts it on its own line; only the inner arrangement is set here. */
.enr-origin-later {
    align-items: baseline;
    gap: 0.25rem;
    min-width: 0;
    font-size: 0.7rem;
    color: #8E8F9E;
    line-height: 1.3;
}

/* The "אחר כך:" prefix never shrinks - it is what makes the line legible as
   context rather than as a second answer, so the label beside it is what gives
   way when the column runs out of room. */
.enr-origin-later-pre {
    flex: 0 0 auto;
}

.enr-origin-later-label {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* "A link WE sent", and it gets its own class rather than borrowing
   `.enr-aff-chip` on purpose. The partner chip is blue because blue means a
   partner earned the touch; this tag means the opposite - the touch is a
   re-engagement message of ours, and an outbound code may never be an origin
   (owner decision 2026-08-23). Painting it in the partner's colour would credit
   us to a partner in the one place a reader looks to tell them apart. Neutral
   slate, no weight, so it reads as a footnote on an already quiet line. */
.enr-origin-ours {
    flex: 0 0 auto;
    background: #f1f5f9;
    color: #64748b;
    border: 1px solid #e2e8f0;
    border-radius: 4px;
    padding: 0 0.3rem;
    font-size: 0.62rem;
    font-weight: 600;
    letter-spacing: 0.02em;
    white-space: nowrap;
}

/* ── Columns the picker can switch on ────────────────────────────────────
   Every rule below belongs to a column that ships hidden, so none of it paints
   anything in the default layout. They are kept together rather than filed
   beside their neighbours so the whole opt-in set can be read - and, if the
   feature is ever pulled, deleted - in one place.

   Each `width` here is the same number the column's def carries in
   src/lib/adminColumns/enrollments.ts. The two are a PAIR, the way the 44px
   checkbox width above is a pair with its sticky offset: the registry number is
   what the table's min-width floor is summed from, this one is what the column
   reserves once it is on screen. Change one, change both. */

.enr-th-listprice,
.enr-cell-listprice {
    width: 110px;
}

.enr-th-discount,
.enr-cell-discount {
    width: 84px;
}

.enr-th-payments,
.enr-cell-payments {
    width: 96px;
}

.enr-th-signed,
.enr-cell-signed {
    width: 100px;
}

.enr-th-created,
.enr-cell-created {
    width: 100px;
}

/* A page title runs long, and the cell is `white-space: nowrap` like every
   other cell on this table - so without the clip one self-serve page name
   pushes the money columns off the visible area. The full text is on the
   cell's own title. */
.enr-th-page,
.enr-cell-page {
    width: 170px;
    max-width: 170px;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Same reason, one size up: a company name is longer than a page title. */
.enr-th-invoice,
.enr-cell-invoice {
    width: 180px;
    max-width: 180px;
}

/* The cell stacks up to three short lines (the personal marker, the name, the
   ח.פ). It cannot join the `span { display: block }` list further up - that is
   a descendant selector over three named cells, and adding a fourth there
   would reach cells this one has nothing to do with. Each line clips on its
   own; the whole cell's explanation is on its title. */
.enr-cell-invoice > span {
    display: block;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* "issued to the student personally" - a marker, not a name, so it reads as a
   quiet tag above whatever else the cell has. Neutral slate and never a colour
   that could read as a warning: it is an ordinary, chosen state. */
.enr-invoice-personal {
    color: #64748b;
    font-size: 0.7rem;
    font-weight: 600;
}

/* A Latin code in an RTL table. Tabular figures so a column of them lines up. */
.enr-th-certificate,
.enr-cell-certificate {
    width: 150px;
    font-variant-numeric: tabular-nums;
}

.enr-cell-contact {
    font-size: 0.82rem;
}

.enr-cell-sub {
    font-size: 0.74rem;
    color: #8E8F9E;
}

/* The as-typed name from the student row, printed beneath the person's own and
   only on the rows where the two disagree. It borrows `.enr-cell-sub` for the
   muted tone every second line on this table shares, and adds only what that
   class cannot supply here: `.enr-cell-sub` is laid out by the `display: block`
   rule further up, which lists the three cells that stack spans, and the name
   cell is deliberately not one of them - its other child is a bold link that
   must stay on a line of its own. */
.enr-name-typed {
    display: block;
    margin-top: 0.1rem;
    line-height: 1.35;
}

.enr-cell-muted {
    color: #b9c0cc;
}

.enr-col-num {
    text-align: left;
    font-variant-numeric: tabular-nums;
}

/* Two deliberate lines: `עריכה` plus the deep-link glyphs above, the labelled
   cancel/delete pair below. Wide enough that the pair never wraps onto a third
   line - the column drove row height to ~105px when it did, which is why the
   edit button was put on the FIRST line rather than beside the pair. */
.enr-col-actions--manage,
.enr-cell-actions--manage {
    /* content box: the pair needs ~233px, plus the cell's 32px padding.
       Only reserved for a user who actually gets the buttons - a read-only
       staff member would otherwise stare at 272px of empty column. */
    min-width: 272px;
}

.enr-cell-actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.25rem;
    white-space: nowrap;
}

/* Zero-height full-width flex item = a forced line break. */
.enr-actions-break {
    flex-basis: 100%;
    height: 0;
    margin: 0;
}

/* The two destructive row actions carry a label as well as a glyph - "cancel"
   and "delete permanently" keep different things, so an icon alone would be a
   coin flip. Compact so the pair still fits one line beside the deep links. */
.enr-action-btn {
    padding: 0.25rem 0.5rem;
    font-size: 0.74rem;
    line-height: 1.25;
}

.enr-action-btn i {
    margin-inline-end: 0.2rem;
}

.enr-btn-danger {
    color: #dc2626;
    border-color: rgba(220, 38, 38, 0.4);
}

.enr-btn-danger:hover:not(:disabled) {
    background: #fef2f2;
    border-color: #dc2626;
    color: #b91c1c;
}

/* Disabled is signalled by SHAPE, not by more transparency. These buttons sit
   inside .enr-table-wrap, which is already at 0.5 opacity whenever the stale
   wash is on - stacking another 0.5 would both bury the control and make "off"
   look like nothing more than a deeper wash. A flat grey face, a dashed edge
   and a blocked cursor survive the wash and read as inert on their own. */
.enr-action-btn:disabled {
    opacity: 1;
    cursor: not-allowed;
    background: #f2f4f8;
    border-color: #c9ced8;
    border-style: dashed;
    color: #8E8F9E;
    box-shadow: none;
}

/* RouterLinks share the icon-button look with real buttons. */
.enr-page a.btn-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    text-decoration: none;
}

/* ── Chips ── */

.enr-sku-chip,
.enr-contract-chip {
    display: inline-flex;
    align-items: center;
    padding: 0.16rem 0.55rem;
    border-radius: 999px;
    font-size: 0.72rem;
    font-weight: 600;
    white-space: nowrap;
}

.enr-sku-chip--developer {
    background: #eaf3ff;
    color: #0b62c4;
}

.enr-sku-chip--architect {
    background: #f1ecff;
    color: #6d3fd6;
}

.enr-sku-chip--bundle {
    background: #fff3e6;
    color: #b35a12;
}

.enr-sku-chip--none {
    background: #f2f4f8;
    color: #8E8F9E;
}

.enr-contract-chip--signed {
    background: #e8f7ee;
    color: #1a7f45;
}

.enr-contract-chip--pending {
    background: #fff8e1;
    color: #9a7215;
}

.enr-contract-chip--cancelled {
    background: #fdeceb;
    color: #b3352c;
}

/* ── Participation (Enrollment.zoomOnly) ──
   Only the EXCEPTION wears a chip. Nearly every student is in the room, so a
   coloured pill on every ordinary row would be a column of noise with the one
   fact worth spotting hidden inside it; the ordinary case is muted text in the
   same ink the rest of the row's context uses. Teal rather than any of the four
   colours above: sku, contract and payment state have each claimed a hue, and a
   fifth meaning wearing a fourth-meaning colour is worse than a new one. */
.enr-zoom-chip {
    display: inline-flex;
    align-items: center;
    padding: 0.16rem 0.55rem;
    border-radius: 999px;
    font-size: 0.72rem;
    font-weight: 600;
    white-space: nowrap;
    background: #e6f6f7;
    color: #0f6d75;
}

.enr-th-zoom,
.enr-cell-zoom {
    white-space: nowrap;
}

/* ── "מספר רכב": the venue's gate list, edited in the row ──────────────────
   The plate is a fact about the PERSON, not about the sale, and it is the one
   thing the venue (Mindspace) needs to raise a barrier for a student. It sits
   beside `השתתפות` because between them they answer how somebody reaches the
   room, and it is EDITABLE here so the list can be repaired from the same
   screen the "send the parking list" button lives on.

   THE CELL ITSELF MUST STAY A TABLE-CELL - the same trap the `מקור` cell
   documents at length further up this file. `display: flex` on this `<td>` to
   line up the input and its two glyphs would merge it with any adjacent
   non-table-cell into ONE anonymous cell, stacked vertically, with the row's
   border broken across both. So the flex box is the CHILD span
   (`.enr-plate-edit`), which is inline-level and joins no such run. */
.enr-th-plate,
.enr-cell-plate {
    white-space: nowrap;
}

/* The three-state editor's open form: field, save, cancel, on one line. */
.enr-plate-edit {
    display: inline-flex;
    align-items: center;
    gap: 0.25rem;
    min-inline-size: 0;
}

/* Narrow: a plate is eight to ten characters and `.form-input` is full width,
   which inside a 96px column would blow the whole table's pan floor open.

   `direction: ltr` HAS TO BE HERE, and the `dir="ltr"` on the element is not
   enough - measured in a real browser on the person card, not assumed.
   `.form-input` in admin.css declares `direction: rtl; text-align: right` for
   Hebrew form fields, and an AUTHOR declaration beats the `dir` attribute,
   which the browser applies as a UA-level presentational hint. Left alone,
   `413-81-403` renders with its segments reordered inside a field whose whole
   content is a licence plate a guard at a barrier has to read back.
   `.per-od-plate-input` and `.reg-inline-edit-input` carry the same two lines
   and say the same thing. `text-align: start` rather than `left`: the element's
   OWN direction is ltr here, so `start` IS left and the file's logical-property
   rule stays intact.

   THE COLUMN WIDENS WHILE THE EDITOR IS OPEN, and that is accepted rather than
   designed away. The field plus its two glyphs is wider than the header text
   the closed column sizes to, and the registry's 96px share for this column is a
   share of the table's pan floor - not a measurement of anything, and no rule
   here reads it. Reserving the open width permanently would cost every reader
   40px of sideways pan for a state that is on screen for a few seconds. The
   panel's other in-place editors behave identically (`.reg-inline-edit-input` is
   9.5rem in a 124px column); this one is already the narrowest of them. */
.enr-plate-input {
    inline-size: 6.6rem;
    max-inline-size: 100%;
    padding-block: 0.18rem;
    padding-inline: 0.35rem;
    direction: ltr;
    font-size: 0.78rem;
    text-align: start;
}

/* The editor's three glyphs, borrowed value for value from `.per-od-plate-btn`
   on the person card rather than shared with it: admin-person.css is globally
   linked, so reusing its class would work today and silently redraw this column
   the day that card is restyled.

   The pencil is ALWAYS VISIBLE rather than revealed on hover. Hover affordances
   do not exist on a phone, and this table becomes a card stack there - an
   editable field nobody can find is not editable. Muted ink is what keeps it
   quiet instead of hiding it. */
.enr-plate-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0.14rem 0.28rem;
    border: 0;
    border-radius: 5px;
    background: none;
    color: #9aa2af;
    font-size: 0.72rem;
    line-height: 1;
    cursor: pointer;
    transition: color 0.15s, background-color 0.15s;
}

.enr-plate-btn:hover:not(:disabled) {
    background: rgba(0, 113, 227, 0.08);
    color: var(--adm-accent);
}

.enr-plate-btn:focus-visible {
    outline: 2px solid var(--adm-accent);
    outline-offset: 1px;
}

/* Disabled means "a save is in flight", which is a state the operator caused
   and should be able to see. Dimmed rather than hidden, so the row does not
   reflow under the cursor at the exact moment somebody is aiming at it. */
.enr-plate-btn:disabled {
    opacity: 0.45;
    cursor: default;
}

.enr-plate-btn--save {
    color: #197a4a;
}

.enr-plate-btn--save:hover:not(:disabled) {
    background: rgba(25, 122, 74, 0.1);
    color: #0f5c37;
}

.enr-plate-btn--edit {
    margin-inline-start: 0.3rem;
}

.enr-paystate--paid {
    color: #1a7f45;
    font-weight: 600;
}

.enr-paystate--partial {
    color: #9a7215;
    font-weight: 600;
}

.enr-paystate--unpaid {
    color: #b3352c;
}

/* ── A cancelled sale is not a debt ──
   The wire still carries a balance and a payment state for a cancelled row (no
   cancel path clears the agreed amount), so the ROW decides not to bill for it.
   The paid figure keeps its number but loses the red - on a sale nobody may
   collect on, "unpaid" red is a debt claim in colour. The יתרה cell carries
   where the money ended up instead of a figure: words, at label size, in the
   same muted ink as the rest of the row's context, and left-aligned with the
   numbers above it so the column keeps one edge. */
.enr-paystate--cancelled {
    color: var(--adm-ink-2);
}

/* `.enr-table td` in the selector on purpose: `.admin-table td` in admin.css
   sets `color: #444` at one class plus one element, so a lone class here loses
   the colour while keeping the size - measured in the browser, where the first
   version of this rule rendered #444 instead of the muted ink. */
.enr-table td.enr-cell-balance--cancelled {
    font-size: 0.74rem;
    color: var(--adm-ink-3);
}

/* ── Pagination ── */

.enr-pagination {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    margin-top: 0.9rem;
    flex-wrap: wrap;
}

.enr-pagination-mid {
    display: flex;
    align-items: center;
    gap: 1rem;
    flex-wrap: wrap;
}

.enr-pagination-info {
    font-size: 0.84rem;
    color: #5A5B6A;
}

.enr-page-size {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    font-size: 0.78rem;
    color: #8E8F9E;
}

.enr-page-size-select {
    padding: 0.2rem 0.45rem;
    border: 1px solid #dfe4ec;
    border-radius: 8px;
    background: #fff;
    font-size: 0.8rem;
    color: #47505c;
}

/* ── The edit / move-cohort modal ─────────────────────────────────────
   The page's first and only `.modal-overlay`. The chrome, the form controls
   and the buttons are all the shared kit in admin.css - only the four things
   that kit has no name for live here.

   The dialog sits INSIDE `.enr-page`, so it inherits `direction: rtl` from the
   island root and needs no direction of its own. What it does need is the one
   mirror every other Hebrew island already carries: `.form-label-hint` is
   positioned physically in admin.css (`margin-left`), which under RTL puts the
   gap on the wrong side of the label it qualifies. Scoped here rather than
   added to the shared group in admin.css, which five other screens read - the
   same call `.edt-page` and `.ep-page` made. */

.enr-page .form-label-hint {
    margin-left: 0;
    margin-right: 0.35rem;
}

/* Who and what the dialog is about, in the words the ROW used. */
.enr-modal-subject {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.3rem;
    margin: 0 0 1rem;
    font-size: 0.9rem;
    color: var(--adm-ink-2);
}

.enr-modal-subject-sep {
    color: #c8cdd6;
}

/* The move block's own hints read as paragraphs rather than as the short
   suffix `.form-label-hint` is sized for, so they get their own line height
   and drop the inline gap. Both carry `.enr-page` so they outrank the RTL
   mirror at the top of this block, which is the rule putting that gap there. */
.enr-page .enr-move-hint {
    display: block;
    margin: 0.4rem 0 0;
    line-height: 1.5;
}

.enr-page .enr-move-blocked {
    display: block;
    margin: 0;
    line-height: 1.5;
}

/* A cohort the public funnel is no longer selling. Staff enrolment is ungated
   by that everywhere in this product, so the option stays selectable and is
   only muted - the words `סגור להרשמה` in its label are what actually carry
   the fact, because `<option>` colour is honoured unevenly across browsers. */
.enr-move-option--closed {
    color: var(--adm-ink-3);
}

.enr-move-reason {
    min-height: 60px;
}

/* The two numbers, side by side and read-only: what this sale agreed, and what
   the target cohort is selling for today. They are allowed to differ - the
   move writes one column and no money - and the sub-line under the second one
   is what says so. */
.enr-move-compare {
    display: flex;
    flex-wrap: wrap;
    gap: 0.9rem;
    margin: 0 0 1rem;
    padding: 0.7rem 0.9rem;
    background: #f6f8fb;
    border: 1px solid #e3e9f1;
    border-radius: 12px;
}

.enr-move-compare-col {
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
    flex: 1 1 44%;
    min-width: 0;
}

.enr-move-compare-head {
    font-size: 0.74rem;
    color: var(--adm-ink-3);
}

.enr-move-compare-value {
    font-size: 1.02rem;
    font-weight: 600;
    color: var(--text-color);
}

.enr-move-compare-sub {
    font-size: 0.72rem;
    line-height: 1.45;
    color: var(--adm-ink-3);
}

/* Where a field that is NOT in this dialog lives. Quiet, and last in the body
   so it reads as a footnote rather than as an instruction. */
.enr-modal-foot-note {
    margin: 1rem 0 0;
    font-size: 0.74rem;
    color: var(--adm-ink-3);
}

/* The server's own refusal sentence. It stays on the dialog rather than in a
   3.2-second toast because each refusal names a different repair. */
.enr-modal-error {
    margin: 0.9rem 0 0;
    padding: 0.55rem 0.75rem;
    background: #fdecea;
    border: 1px solid #f5c6c2;
    border-radius: 10px;
    font-size: 0.82rem;
    line-height: 1.5;
    color: #8c2c25;
}

/* ── Tablet / phone: rows become cards ── */

@media (max-width: 1024px) {
    /* The card layout below throws away <thead>, so this is the only way to
       reorder the list at this width. */
    .enr-sortbar {
        display: flex;
    }

    /* ...and the only way to reach a checkbox, for the same reason: the
       select-all header cell is gone with the header. */
    .enr-tool {
        display: inline-flex;
    }

    .enr-table {
        display: block;
        min-width: 0;
        overflow: visible;
        background: transparent;
        border: none;
        box-shadow: none;
    }

    .enr-table thead {
        display: none;
    }

    .enr-table tbody {
        display: block;
        width: 100%;
    }

    .enr-table tbody tr {
        display: grid;
        grid-template-columns: 1fr auto;
        grid-template-areas:
            'name status'
            'contact cohort'
            'chips chips'
            'origin origin'
            'plate plate'
            'money money'
            'when actions';
        row-gap: 0.45rem;
        column-gap: 0.6rem;
        width: 100%;
        margin-bottom: 0.85rem;
        padding: 0.85rem 1rem 0.65rem;
        background: #fff;
        border: 1px solid #e6ebf2;
        border-radius: 14px;
        box-shadow: 0 1px 3px rgba(0, 60, 130, 0.05);
    }

    .enr-row--cancelled {
        background: #fafbfc;
    }

    .enr-table td {
        border: none;
        padding: 0;
        font-size: 0.86rem;
        white-space: normal;
    }

    .enr-cell-name {
        grid-area: name;
        font-size: 1rem;
    }

    /* ── The card's own checkbox ──
       It SHARES the `name` area, the way the three money cells share `money`.
       A fifth grid area would mean hand-editing all four `grid-template-areas`
       blocks below (base, --cancelled, --zoom, and both at once), and the file
       already explains why crossing a third modifier turns four templates into
       eight. Hidden until the sortbar's toggle puts the list in pick mode: a
       permanent column of boxes on every card is a tap target competing with
       the card itself, which is a link. */
    .enr-cell-check {
        display: none;
    }

    .enr-row--picking .enr-cell-check {
        display: flex;
        grid-area: name;
        justify-self: start;
        align-self: start;
        align-items: center;
        justify-content: center;
        min-width: 44px;
        min-height: 44px;
        padding: 0;
        /* Not decoration: the name cell shares this same grid area, declares no
           alignment so it stretches across the whole of it, and comes later in
           the DOM - so it paints and hit-tests ON TOP of the box, and the opaque
           row-hover tint erases the tick on any hovered unselected card (on
           touch, the card just tapped). A non-auto z-index lifts the box above
           its later sibling and keeps it tappable. No layout shift: the cell
           still starts at the edge and the name still indents 44px. */
        position: relative;
        z-index: 1;
    }

    .enr-row--picking .enr-cell-check input[type="checkbox"] {
        width: 22px;
        height: 22px;
    }

    /* The name yields the width the box now occupies inside the shared area. */
    .enr-row--picking .enr-cell-name {
        padding-inline-start: 44px;
    }

    /* Card mode: the card IS the row, so the mark moves off the cells and onto
       the card's own border and ring - the same handoff `.reg-table` makes in
       admin.css, whose rule is keyed on a class this table does not carry. */
    .enr-table tbody tr.enr-row--selected {
        border-color: #93c5fd;
        background: #f5f9ff;
        box-shadow: 0 0 0 1px #93c5fd;
    }

    .enr-table tbody tr.enr-row--selected td {
        background: transparent !important;
    }

    .enr-cell-status {
        grid-area: status;
        justify-self: end;
    }

    .enr-cell-contact {
        grid-area: contact;
    }

    .enr-cell-cohort {
        grid-area: cohort;
        text-align: left;
    }

    /* Track + contract chips share one line. */
    .enr-cell-sku {
        grid-area: chips;
    }

    .enr-cell-contract {
        grid-area: chips;
        justify-self: end;
    }

    /* The three money cells become one labelled mini-band - a two-column GRID
       each, not a flex line, and the difference is what lets the ex-VAT
       parenthetical survive down here. The cell's label (::before) and its
       figure sit on row 1; the parenthetical takes row 2 of the FIGURE's
       column. In a flex line the block form is merely a third item beside the
       figure, and forcing it onto a second line there costs a
       `flex-basis: 100%` that also widens the cell by the parenthetical's full
       width - which is the one thing this layout cannot afford: the three cells
       share ONE grid area, spread start / center / end, and OVERLAP the moment
       one outgrows its third (see the note further down). Stacked, a cell is
       only as wide as its widest ROW, and "(10,331 ₪)" is narrower than
       "שולם 12,190.5 ₪" - so the figure costs a line of card HEIGHT, which the
       auto-sized row absorbs, and not a pixel of width. */
    .enr-cell-expected,
    .enr-cell-paid,
    .enr-cell-balance {
        grid-area: money;
        display: inline-grid;
        grid-template-columns: auto auto;
        align-items: baseline;
        column-gap: 0.35rem;
        direction: rtl;
        font-size: 0.84rem;
    }

    .enr-cell-expected::before,
    .enr-cell-paid::before,
    .enr-cell-balance::before {
        font-size: 0.72rem;
        color: #8E8F9E;
    }

    /* Column 2 is the FIGURE's column, and naming it is the whole trick: left to
       auto-placement the parenthetical would land in column 1, under the label,
       and read as a second caption. Its row is implicit - the grid only ever
       has one item to put there. */
    .enr-cell-expected .exvat,
    .enr-cell-paid .exvat,
    .enr-cell-balance .exvat {
        grid-column: 2;
    }

    .enr-cell-expected::before {
        content: 'לתשלום';
    }

    .enr-cell-paid::before {
        content: 'שולם';
    }

    .enr-cell-balance::before {
        content: 'יתרה';
    }

    /* On a cancelled row the cell holds where the money ended up, not a figure
       to collect - so the label in front of it has to say that too, or the card
       reads "יתרה הוחזר במלואו". */
    .enr-row--cancelled .enr-cell-balance::before {
        content: 'מצב הכסף';
    }

    .enr-cell-expected {
        justify-self: start;
    }

    .enr-cell-paid {
        justify-self: center;
    }

    .enr-cell-balance {
        justify-self: end;
    }

    /* The three money cells share ONE grid area, spread start / center / end, so
       they do not reflow - they sit side by side and would OVERLAP if one
       outgrew its third. On a cancelled row that cell holds a phrase
       ("הוחזר יותר ממה שנגבה") rather than a figure, which does not fit beside
       two amounts at ANY card width - a tablet card is wider than a phone's, but
       the phrase grew by more than the card did. So it gets a line of its own
       from the moment rows become cards, not only on a phone. The selector has
       to outrank `.enr-table tbody tr`, hence the element names. */
    .enr-table tbody tr.enr-row--cancelled {
        grid-template-areas:
            'name status'
            'contact cohort'
            'chips chips'
            'origin origin'
            'plate plate'
            'money money'
            'moneystate moneystate'
            'when actions';
    }

    .enr-row--cancelled .enr-cell-balance {
        grid-area: moneystate;
        justify-self: start;
    }

    /* ── Participation on a card ──
       The in-room student's cell is DROPPED here rather than printed. On
       desktop the column is sortable and must say something in every row, but a
       card has no column header to sort by and no empty cell to explain, so
       "בכיתה" on nine cards out of ten is a line of noise around the one that
       matters.
       Which is why the card grid gains its `attend` row only under the row
       modifier, exactly the way the cancelled row gains `moneystate` above: an
       area named in the base template would cost every card a row-gap for a
       track that is empty on almost all of them. Element names in the selector
       to outrank `.enr-table tbody tr`, same as the rule above. */
    .enr-cell-zoom--plain {
        display: none;
    }

    /* ── The picker's opt-in columns never reach a card ───────────────────
       Below this breakpoint the row is a named-area grid with FOUR
       hand-maintained `grid-template-areas` variants and no data-label
       captions anywhere - the card is composed, not gutter-labelled. A <td>
       with no area auto-flows into an implicit row at the bottom as bare,
       unlabelled text, which is what a reader would get months after this
       shipped, the first time somebody ticked a box.

       The card layout is frozen, so the answer is uniform and dull: a column
       that is not part of the default layout is a table column at >=1025px and
       nothing at all below it. The picker says so in its own copy.

       If one of these ever earns a place on the card, it needs a grid area in
       all four templates (the `origin` precedent) or a fifth row modifier (the
       `attend` / `moneystate` precedent), plus its own ::before caption - NOT a
       data-label, which is inert on this table because `.enr-table` does not
       wear `.reg-table`. */
    .enr-cell-listprice,
    .enr-cell-discount,
    .enr-cell-payments,
    .enr-cell-signed,
    .enr-cell-created,
    .enr-cell-page,
    .enr-cell-invoice,
    .enr-cell-certificate {
        display: none;
    }

    .enr-table tbody tr.enr-row--zoom {
        grid-template-areas:
            'name status'
            'contact cohort'
            'chips chips'
            'origin origin'
            'attend attend'
            'plate plate'
            'money money'
            'when actions';
    }

    .enr-table tbody tr.enr-row--zoom.enr-row--cancelled {
        grid-template-areas:
            'name status'
            'contact cohort'
            'chips chips'
            'origin origin'
            'attend attend'
            'plate plate'
            'money money'
            'moneystate moneystate'
            'when actions';
    }

    .enr-cell-zoom {
        grid-area: attend;
        justify-self: start;
    }

    /* ── The car plate on a card ──
       The ONE column that is part of the default layout AND reaches a card, so
       it is named in all FOUR `grid-template-areas` variants above - the
       `origin` precedent, not the `attend` / `moneystate` one. A fifth row
       modifier would have crossed with the two that already exist and turned
       four hand-maintained templates into eight.

       It is directly under `attend` in both zoom variants on purpose: those two
       cells are one sentence about how this person reaches the room.

       PRINTED ON EVERY CARD, including the rows with nothing in them, which is
       the deliberate opposite of what `.enr-cell-zoom--plain` and
       `.enr-cell-origin--empty` do in this same media block. Those two drop a
       cell that has nothing to say; this column exists precisely to make the
       empty ones findable, because a student with no plate is silently absent
       from the mail the venue works from. "לא הוזן" IS the fact worth showing.

       No `display: flex` on the cell and none needed: below 1024px
       `.enr-table tbody tr` is `display: grid`, so every cell is already a grid
       item and the anonymous-table-cell run the desktop rule warns about cannot
       form. The caption is a ::before rather than a data-label, which is inert
       on this table - `.enr-table` does not wear `.reg-table`. */
    .enr-cell-plate {
        grid-area: plate;
        justify-self: start;
        font-size: 0.84rem;
    }

    .enr-cell-plate::before {
        content: 'רכב';
        margin-inline-end: 0.4rem;
        font-size: 0.72rem;
        color: #8E8F9E;
    }

    /* ── The origin on a card ──
       Placed under the track/contract chips: "what this sale is", then "where
       it came from", then the money.

       A card has no column header, so the cell has to name itself - same
       ::before device the money cells use. And a card with nothing to say drops
       the cell ENTIRELY rather than printing "לא ידוע", exactly as
       `.enr-cell-zoom--plain` does above and for the same stated reason: a
       phrase repeated on nine cards out of ten is noise around the one that
       matters.

       The `origin` track is named in all four templates rather than gained
       under a row modifier the way `attend` and `moneystate` are. That costs an
       empty card one collapsed track plus one row-gap, and it is the deliberate
       trade: adding a fifth modifier would have crossed with the two existing
       ones and turned four hand-maintained templates into eight. */
    .enr-cell-origin {
        grid-area: origin;
        justify-self: start;
        /* Flex is safe HERE and only here: `.enr-table tbody tr` is
           `display: grid` below 1024px, so every cell is already a grid item
           and there is no anonymous-table-cell run for this to join. */
        display: flex;
        flex-direction: row;
        flex-wrap: wrap;
        align-items: center;
        column-gap: 0.35rem;
        max-width: 100%;
    }

    /* Back to ordinary flex items in the row; the desktop rule's
       block-level stacking would put each chip on its own line. */
    .enr-cell-origin > .enr-aff-chip,
    .enr-cell-origin > .enr-origin-later {
        margin-top: 0;
    }

    /* The later touch keeps a line of its OWN on a card even though the chips
       beside it wrap freely. It is a sentence ("אחר כך: WhatsApp קישור שלנו"),
       not a chip, and wrapped in mid-sentence between two pills it reads as two
       more pills. `flex-basis: 100%` on a wrapping flex row is the line break. */
    .enr-cell-origin > .enr-origin-later {
        flex: 1 1 100%;
    }

    .enr-cell-origin::before {
        content: 'מקור';
        font-size: 0.72rem;
        color: #8E8F9E;
    }

    .enr-cell-origin--empty {
        display: none;
    }

    /* Date and the close-channel label share one line as flex items with a real
       gap between them. The old `margin-inline-end` on the spans put the space
       on the wrong side (issue 102): the date span carries dir="ltr", so its
       inline-end resolved to its own physical right - the card's outer edge in
       this RTL context - and no gap ever landed between the date and the label.
       A flex gap is direction-proof and lets the label wrap cleanly under the
       date when the card is narrow. */
    .enr-cell-when {
        grid-area: when;
        display: flex;
        flex-wrap: wrap;
        align-items: baseline;
        gap: 0.15rem 0.5rem;
        color: #8E8F9E;
        font-size: 0.78rem;
    }

    /* The desktop column reservation would overflow a 390px card. */
    .enr-col-actions--manage,
    .enr-cell-actions--manage {
        min-width: 0;
    }

    .enr-cell-actions {
        grid-area: actions;
        justify-self: end;
        display: flex;
        flex-wrap: wrap;
        justify-content: flex-end;
        gap: 0.3rem;
    }

    .enr-kpi {
        min-width: 88px;
        padding-inline: 0.5rem;
    }

    /* ── 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. */
    .enr-page .btn,
    .enr-page .btn-icon,
    .enr-page .enr-action-btn {
        min-height: 44px;
        min-width: 44px;
    }

    .enr-page .reg-date-pill {
        min-height: 44px;
    }

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

    /* Same iOS zoom rule, WITHOUT the 44px floor: the move dialog's reason box
       already stands taller than that, and a `min-height` here would beat both
       its own rule and the shared one on specificity and shrink it. */
    .enr-page .form-textarea {
        font-size: 16px;
    }

    .enr-filter-locked-clear,
    .enr-filter-note {
        min-height: 44px;
        min-width: 44px;
        display: inline-flex;
        align-items: center;
    }

    .enr-page .search-clear {
        display: inline-flex;
        align-items: center;
        justify-content: center;
        min-width: 44px;
        min-height: 44px;
    }

    .enr-page .admin-search input {
        padding-left: 48px;
    }

    /* ── The bulk bar docks to the bottom edge ──
       A selection made 40 cards down is acted on where the thumb already is, and
       the bar never scrolls away mid-decision. The controls scroll sideways
       rather than stacking into a four-row slab that eats half the screen.

       `inset-block-start: auto` is load-bearing, not tidy-up: the desktop rule is
       `position: sticky; top: 0`, and that `top` does NOT stop applying when the
       position changes - a fixed box with both block ends pinned is stretched to
       the whole viewport. That is how the leads bar once shipped as a
       full-screen dark slab with its buttons floating mid-air.

       z-index 1015 is the shared docked-bar rung (`.adm-tabbar`,
       `.leads-bulk-bar`): above the content, and BELOW `.modal-overlay` at 1018,
       which is not arbitrary either - a confirm dialog's footer behind a 1015 bar
       had its buttons swallowed once already. The tab bar itself is hidden while
       this bar is up (admin.css), so two fixed bars never stack on a 390px
       screen. */
    .enr-bulk-bar {
        position: fixed;
        inset-inline: 0;
        inset-block-start: auto;
        inset-block-end: 0;
        z-index: 1015;
        height: auto;
        margin: 0;
        border-radius: 0;
        flex-wrap: nowrap;
        overflow-x: auto;
        overscroll-behavior-x: contain;
        padding: 0.6rem 0.85rem calc(0.6rem + env(safe-area-inset-bottom, 0px));
        box-shadow: 0 -8px 28px rgba(0, 60, 130, 0.22);
    }

    .enr-bulk-bar .btn,
    .enr-bulk-bar .form-select,
    .enr-bulk-bar .reg-bulk-count {
        flex: 0 0 auto;
    }

    .enr-bulk-bar .btn {
        min-height: 44px;
    }

    /* The spacer's auto margin would push everything apart inside a horizontal
       scroller instead of pinning one button to the far side. */
    .enr-bulk-bar .reg-bulk-spacer {
        margin-inline: 0;
    }

    /* Clear the fixed bar so the last card is never under it. Scoped to
       `.admin-main` on purpose: the plain `.enr-page--bulk` this would naturally
       be loses to `.admin-main .enr-page { padding: 0 }` at the top of this file
       (the neutraliser for the public checkout's same-named page shell), which
       outranks it by specificity. The leads page has no such neutraliser, which
       is why its twin rule needs no prefix. */
    .admin-main .enr-page--bulk {
        padding-block-end: 5.5rem;
    }
}

@media (max-width: 767px) {
    /* The cancelled row's own `moneystate` line is declared in the 1024 block
       above, which this one nests inside - it applies here unchanged. */

    /* Phone only: the bar is a horizontal scroller, and seven controls in it is
       three more than a thumb will ever find. The four least-used fold behind
       the door, leaving count + participation + channel + move + certificates +
       WhatsApp + door. A tablet card is wide enough to keep all of them. */
    .enr-bulk-more {
        display: inline-flex;
    }

    .enr-bulk--folds {
        display: none;
    }

    .enr-kpis {
        gap: 0.4rem;
        padding: 0.55rem 0.6rem;
        justify-content: space-between;
    }

    .enr-kpi {
        min-width: 0;
        flex: 1 1 40%;
    }

    .enr-kpi:not(:first-child) {
        border-inline-start-color: transparent;
    }

    .enr-kpi-value {
        font-size: 1.02rem;
    }

    .enr-filter-bar {
        flex-wrap: wrap;
    }

    /* iOS Safari ZOOMS THE WHOLE PAGE when a field it focuses has a font-size
       under 16px, and there is no gesture back out of that zoom except a pinch -
       so a staff member typing a plate into a card ends up scrolled sideways
       inside a table they can no longer see. admin.css exempts every other admin
       field in its own 767 block for exactly this; this input is declared in
       this file, so its exemption has to be declared here too. The `inline-size`
       above is unchanged: the field is sized in rem and stays where it is. */
    .enr-plate-input {
        font-size: 16px;
    }
}
