/* MeetPlatform dark theme — tuned for high-contrast meet-day displays (scoreboard, warm-up, overlay). */
:root {
    --mp-bg: #0d1117;
    --mp-surface: #161b22;
    --mp-surface-2: #1f2630;
    --mp-border: #2d333b;
    --mp-text: #e6edf3;
    --mp-muted: #9aa7b4;
    --mp-accent: #f0a500;       /* barbell gold */
    --mp-good: #2ea043;         /* good lift / white light */
    --mp-nolift: #d92d20;       /* no lift / red light */
    --mp-info: #1f6feb;

    /* ---- Dark control tokens (Setup redesign, fable-spec §6.2 / WP0 §2 rule 6) ----
       Semantic roles for form controls, layered on top of the surface tokens above with safe fallbacks so a
       future theme can override --mp-accent-2 without touching this file. Applied under .mp-setup-scope only
       (see platform.css "Setup tab professional redesign" below) so other pages/forms are not regressed. */
    --mp-control-bg: #171e28;
    --mp-control-bg-hover: #1a222d;
    --mp-control-border: #354253;
    --mp-control-border-focus: var(--mp-accent-2, #f0b94d);
    --mp-control-placeholder: #5e6978;
    --mp-nested-surface: #141b24;

    /* ---- display-board-typography §4.1: venue-display text-size tokens ----
       Per-surface font scale, written to <html> by wwwroot/display-scale.js from device-local storage (see that
       file for why <html> and not the board root). Declared here so a board still renders at 100% if storage is
       unavailable, if the script is blocked, or on any page that never sets one. */
    --mp-rb-font-scale: 1;      /* operational run board  (strengthmeet:display-scale:v1:run-board)  */
    --mp-sb-font-scale: 1;      /* public scoreboard      (strengthmeet:display-scale:v1:scoreboard) */
}

/* ---- display-board-typography §4.1: shared venue-display type system ----------------------------------------
   TWO independent inputs, deliberately kept apart (§4.2 forbids transform/zoom on a whole board):

     --mp-display-px          RESOLUTION. A "reference pixel" LENGTH: exactly 1 CSS px on a 1920×1080 screen and
                              2 CSS px at 3840×2160, so the same setting is the same PHYSICAL size on the same
                              65-inch panel whichever source resolution the venue feeds it (§7.2). Derived from the
                              viewport itself — never from window.screen, devicePixelRatio, the user agent or a
                              hardcoded "4K mode". max(1px, …) floors it so a 1280×720 operator laptop keeps
                              full-size type instead of shrinking to 67% (§11.2 lists 720p as a regression check,
                              not as a surface that should get smaller text).

     --mp-display-font-scale  OPERATOR CHOICE. 0.8–1.5, mapped from the surface's own --mp-*-font-scale below.

   Their product is --mp-display-unit, and every type token on every board is `calc(<1080p design px> *
   var(--mp-display-unit))`. Number × length × number is valid calc arithmetic and yields a length. Only TYPE (and
   the minimum spacing needed to stop collisions) reacts to the font scale; panel geometry stays resolution-driven,
   which is what keeps popovers, safe areas and hit targets correct at every size. */
.mp-runboard,
.mp-sb {
    --mp-display-px: max(1px, calc(100vh / 1080));
    --mp-display-unit: calc(var(--mp-display-px) * var(--mp-display-font-scale));
}

.mp-runboard { --mp-display-font-scale: var(--mp-rb-font-scale, 1); }
.mp-sb { --mp-display-font-scale: var(--mp-sb-font-scale, 1); }

/* ---- display-board-typography §5.6: the shared plate-label ink treatment ----
   Emitted by MeetPlatform.Contracts.Running.PlateAppearance.InkCssClass(configured colour) on EVERY plate on every
   surface — the run board's current bar, its Next/Then chips, and the chromeless platform display's large and mini
   plates — so the two platform-facing views can never disagree about a colour. The opposite-colour shadow is the
   safety net for intermediate custom colours that sit near the light/dark boundary, where neither ink is clearly
   better; it costs nothing on the unambiguous ones. Colour is never the sole signal: every plate prints its weight. */
.mp-plate-ink-light { color: #ffffff; text-shadow: 0 1px 2px rgba(0, 0, 0, 0.85), 0 0 3px rgba(0, 0, 0, 0.75); }
.mp-plate-ink-dark { color: #0a0d10; text-shadow: 0 1px 0 rgba(255, 255, 255, 0.45); }

/* ---- display-board-typography §3.1/§8: the Text size control, shared by both boards ----
   Shares the anchored-popover geometry with the Indicators control (see the .mp-ind-wrap/.mp-scale-wrap rule further
   down, where both are listed together) so it sits beside Present looking like the rest of the toolbar — but under
   its OWN class names, because .mp-ind-* means "the Indicators control" and UI tests locate it by that. Buttons stay
   at least 44×44 CSS px in the normal operator toolbar (§8) and are unaffected by the font scale — the control sizes
   the BOARD, not itself. */
.mp-scale-popover { width: min(24rem, 92vw); }
.mp-scale-stepper { display: flex; align-items: center; gap: 0.5rem; margin-top: 0.7rem; }
.mp-scale-stepper button { min-width: 44px; min-height: 44px; font-size: 1.15rem; font-weight: 900; }
.mp-scale-value { flex: 1 1 auto; text-align: center; font-size: 1.05rem; font-weight: 900; color: var(--mp-accent); font-variant-numeric: tabular-nums; }
.mp-scale-range { width: 100%; margin-top: 0.55rem; accent-color: var(--mp-accent); }
.mp-scale-presets { display: flex; flex-wrap: wrap; gap: 0.35rem; margin-top: 0.6rem; }
.mp-scale-presets button { flex: 1 1 7rem; min-height: 40px; font-size: 0.8rem; }
.mp-scale-actions { display: flex; justify-content: flex-end; margin-top: 0.6rem; }
/* §8: the polite announcement target — one committed change, one announcement, never one per slider step. */
.mp-scale-status { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }

body {
    background-color: var(--mp-bg);
    color: var(--mp-text);
    /* The app palette is dark — tell the browser so native controls (date-picker calendar icon + popup,
       scrollbars, etc.) render light-on-dark instead of an invisible black icon. */
    color-scheme: dark;
}

a { color: var(--mp-accent); }
a:hover { color: #ffc233; }

.mp-shell { min-height: 100vh; }

.mp-navbar {
    background: var(--mp-surface);
    border-bottom: 1px solid var(--mp-border);
    padding: 0.75rem 1.25rem;
    display: flex;
    align-items: center;
    gap: 1.25rem;
}
.mp-brand { font-weight: 800; letter-spacing: -0.02em; font-size: 1.15rem; color: var(--mp-text); text-decoration: none; }
.mp-brand span { color: var(--mp-accent); }
/* Strength Meet brand lock-up (BrandLockup.razor). Desktop mark height sits in the 32-34px navbar target
   (spec §7); the wordmark text hides itself under 720px so the Full variant compacts to mark-only on phones
   without a second DOM node, and the mark itself steps down into the 28px compact range at the same
   breakpoint. Only height is fixed — width:auto/object-fit:contain preserve the mark's native 2.0203:1 ratio
   so the wider/flatter art (wwwroot/brand/strength-meet-logo.svg) never stretches or crops. */
.mp-brand-lockup { display: inline-flex; align-items: center; gap: 0.5rem; }
.mp-brand-mark { height: 34px; width: auto; display: block; object-fit: contain; flex: 0 0 auto; }
.mp-brand-word { white-space: nowrap; }
@media (max-width: 720px) {
    .mp-brand-full .mp-brand-word { display: none; }
    .mp-brand-lockup .mp-brand-mark { height: 28px; }
}
/* min-width:0 lets this flex item actually shrink to its widest single link (and wrap the rest) instead of the
   default flex min-width:auto forcing the whole row's natural width onto its flex-basis, which was pushing a
   couple of px past the viewport at very narrow widths (meets-ui fable-spec §10.3 phone no-overflow contract). */
.mp-nav-links { display: flex; gap: 1rem; flex-wrap: wrap; min-width: 0; }
/* overflow-wrap:anywhere gives each link an in-word break opportunity, so a link whose text is wider than the
   viewport allows (the profile link renders the user's arbitrary display name) wraps inside its own row instead
   of holding its full min-content width and pushing the document past a 320px viewport — the same phone
   no-overflow contract as the container's min-width:0 note above. */
.mp-nav-links a { color: var(--mp-muted); text-decoration: none; font-weight: 600; overflow-wrap: anywhere; }
.mp-nav-links a:hover, .mp-nav-links a.active { color: var(--mp-text); }

/* Full width by default; the top-right toggle adds html.mp-narrow to constrain it. Horizontal padding scales
   with viewport (meets-ui fable-spec §6.1) so wide/4K layouts don't carry a fixed narrow gutter, while narrow
   viewports keep a sane minimum. */
.mp-container { max-width: none; margin: 0 auto; padding: 1.75rem clamp(1rem, 1.4vw, 2rem) 4rem; }
html.mp-narrow .mp-container { max-width: 1100px; }

.mp-width-toggle {
    background: var(--mp-surface-2); color: var(--mp-text); border: 1px solid var(--mp-border);
    border-radius: 6px; padding: 0.3rem 0.6rem; cursor: pointer; font-weight: 600; font-size: 0.85rem; white-space: nowrap;
}
.mp-width-toggle:hover { border-color: var(--mp-accent); }
.mp-width-toggle .when-narrow { display: none; }
html.mp-narrow .mp-width-toggle .when-wide { display: none; }
html.mp-narrow .mp-width-toggle .when-narrow { display: inline; }
/* Below small-phone widths the toggle is INERT — full-width and the 1100px-max "narrow" container render
   identically when the viewport is far under 1100px — yet its nowrap label still forced the navbar ~27px past a
   320px viewport (document-level horizontal overflow on every page). Hide the control where it does nothing. */
@media (max-width: 480px) { .mp-width-toggle { display: none; } }

/* Secondary (in-meet) navigation bar. */
.mp-meet-nav {
    display: flex; flex-wrap: wrap; gap: 1.1rem; align-items: center;
    background: var(--mp-surface); border: 1px solid var(--mp-border); border-radius: 10px;
    padding: 0.6rem 1rem; margin-bottom: 1.25rem;
}
.mp-meet-nav a { padding: 0.15rem 0; }
.mp-meet-nav a.active { color: var(--mp-accent); border-bottom: 2px solid var(--mp-accent); }

/* ---- Registration grid (ag-grid-style inline editing) ---- */
/* A full-height scroll viewport: headers stay pinned (vertical scroll), and it scrolls horizontally when wider.
   The height below is only a no-JS fallback — registration-grid.js pins the exact height (viewport minus the
   chrome above it) at runtime so the page itself never scrolls and the grid's own scrollbars stay visible. */
.mp-reg-wrap { height: calc(100vh - 13rem); min-height: 18rem; overflow: auto; border: 1px solid var(--mp-border); border-radius: 10px; background: var(--mp-surface); }
.mp-reg { border-collapse: separate; border-spacing: 0; width: max-content; min-width: 100%; font-size: 0.85rem; }
.mp-reg thead th {
    position: sticky; top: 0; z-index: 3; background: var(--mp-surface);
    border-bottom: 2px solid var(--mp-border); padding: 0.5rem 0.65rem; text-align: left;
    white-space: nowrap; font-weight: 700; color: var(--mp-muted);
}
.mp-reg tbody td { border-bottom: 1px solid var(--mp-border); padding: 0; white-space: nowrap; vertical-align: middle; }
.mp-reg tbody tr:hover td { background: color-mix(in srgb, var(--mp-accent) 7%, transparent); }
/* Editors read like plain cells until focused — a single click puts the cell into edit mode. */
.mp-reg .form-control {
    border: 1px solid transparent; background: transparent; border-radius: 0; box-shadow: none;
    width: 100%; min-width: 5rem; padding: 0.4rem 0.65rem; font: inherit; color: var(--mp-text); height: 2.2rem;
}
.mp-reg td > .form-control:hover { background: color-mix(in srgb, var(--mp-accent) 10%, transparent); }
.mp-reg td > .form-control:focus {
    border-color: var(--mp-accent); background: var(--mp-bg); outline: none;
    box-shadow: inset 0 0 0 1px var(--mp-accent); position: relative; z-index: 1;
}
/* The multiselect cells blend into the grid: borderless until opened, matching the inline editors. */
.mp-reg .mp-multiselect > summary.msd-control { border-color: transparent; background: transparent; min-height: 2.2rem; border-radius: 0; }
.mp-reg td:hover > .mp-multiselect > summary.msd-control { background: color-mix(in srgb, var(--mp-accent) 10%, transparent); }
.mp-reg .mp-multiselect[open] > summary.msd-control { background: var(--mp-bg); border-color: var(--mp-accent); }

/* Sortable + filterable column headers — single line: label (sort) on the left, filter funnel on the right. */
.mp-reg .mp-rhead { display: flex; align-items: center; gap: 0.4rem; justify-content: space-between; }
.mp-reg .mp-rsort-label { cursor: pointer; user-select: none; display: inline-flex; align-items: center; gap: 0.25rem; white-space: nowrap; }
.mp-reg .mp-rsort-label:hover { color: var(--mp-text); }
.mp-reg .mp-rsort-ind { font-size: 0.65rem; color: var(--mp-accent); }
.mp-reg .mp-rsort-ord { font-size: 0.6rem; color: var(--mp-muted); margin-left: -0.15rem; }
/* Filter funnel: a popover anchored to the header; the icon glows accent when a filter is active. */
.mp-reg .mp-rfilter-wrap { position: relative; flex: none; }
.mp-reg .mp-rfilter-wrap > summary {
    list-style: none; cursor: pointer; color: var(--mp-muted); display: inline-flex; line-height: 1; padding: 2px; border-radius: 4px;
}
.mp-reg .mp-rfilter-wrap > summary::-webkit-details-marker { display: none; }
.mp-reg .mp-rfilter-wrap > summary:hover { color: var(--mp-text); background: color-mix(in srgb, var(--mp-accent) 12%, transparent); }
.mp-reg .mp-rfilter-wrap.mp-filter-on > summary { color: var(--mp-accent); }
.mp-reg th.mp-rsort:has(.mp-rfilter-wrap[open]) { z-index: 5; }
.mp-reg .mp-rfilter-pop {
    position: absolute; right: 0; top: 100%; z-index: 6; margin-top: 3px;
    background: var(--mp-surface); border: 1px solid var(--mp-border); border-radius: 6px; padding: 6px; box-shadow: 0 6px 18px rgba(0,0,0,0.35);
}
.mp-reg .mp-rfilter {
    width: 150px; box-sizing: border-box; padding: 0.3rem 0.4rem; font-size: 0.8rem; font-weight: 400;
    border: 1px solid var(--mp-border); border-radius: 4px; background: var(--mp-bg); color: var(--mp-text);
}
.mp-reg .mp-rfilter:focus { outline: none; border-color: var(--mp-accent); }

/* Cells without a full-bleed editor provide their own padding (the tds themselves have none). */
.mp-reg td.mp-reg-center { text-align: center; padding: 0.3rem 0.5rem; }
.mp-reg td.mp-reg-center input[type=checkbox] { margin: 0 auto; display: block; }
.mp-reg td.mp-reg-pad { padding: 0.25rem 0.4rem; }
/* "Not applicable" dash in a cell that otherwise holds an inline editor (weigh-ins openers/racks). */
.mp-reg .mp-reg-na { display: block; padding: 0.45rem 0.65rem; color: var(--mp-muted); }

/* ---- Sticky-LEFT lifter/name column (lifter-linking WP-U3) ----
   Mirrors .mp-dg-sticky-left on the shared data-grid stack further down this file — .mp-reg never had one. The body cell
   needs an OPAQUE background so horizontally-scrolled cells don't bleed through it; z-index is kept BELOW the
   filter-open (5) and popover (6) values on this same grid so a filter dropdown always wins the stacking order,
   even the sticky column's own. */
.mp-reg .mp-reg-sticky-left { position: sticky; left: 0; z-index: 2; background: var(--mp-surface); }
.mp-reg tbody tr:hover td.mp-reg-sticky-left { background: color-mix(in srgb, var(--mp-accent) 12%, var(--mp-surface)); }
.mp-reg thead th.mp-reg-sticky-left { z-index: 4; }

/* ---- Bodyweight/weight-class mismatch (lifter-linking WP-U2) ----
   Colour is never the only signal — see the "Class mismatch" text badge in the status column (WeighIns.razor)
   and the aria-invalid/aria-describedby pair on the two fields themselves. The tint lives on the <td> (not the
   .form-control), so a focused editor's own opaque background + accent focus ring (:115 above) still show through
   unobscured — focus visibility is never traded away for the invalid styling. */
.mp-reg td.mp-cell-invalid { background: color-mix(in srgb, var(--mp-nolift) 14%, transparent); }
.mp-reg td.mp-cell-invalid > .form-control { color: var(--mp-nolift); }
/* Row-level attention marker on the sticky lifter cell — stays visible even once phase-2 column-hiding can hide
   the class/bodyweight cells themselves. Decorative (the accessible signal is the field pair + status badge
   above), so it is left out of the accessibility tree. */
.mp-reg td.mp-row-attention { position: relative; padding-left: 1.6rem; }
.mp-reg td.mp-row-attention::before {
    content: "⚠"; position: absolute; left: 0.5rem; top: 50%; transform: translateY(-50%);
    color: var(--mp-nolift); font-weight: 800;
}

/* ---- Grid toolbar + application full-screen mode (lifter-linking WP-U3) ----
   A row above each meet-day grid (Registration/Weigh-ins) that will also host the column chooser in phase 2.
   Buttons are held at a 44px touch target unconditionally — a director on a tablet needs this row as much as one
   on a phone. */
.mp-grid-toolbar { display: flex; justify-content: flex-end; gap: 0.5rem; margin-bottom: 0.5rem; }
.mp-grid-toolbar .mp-btn { min-height: 44px; display: inline-flex; align-items: center; gap: 0.35rem; }

/* .mp-grid-fs is a plain structural wrapper around a grid's toolbar-head + .mp-reg-wrap — display:contents keeps
   it invisible to layout (and CSS) until full screen is entered, so it never disturbs the page's normal flow.
   Entering full screen (grid-fullscreen.js) adds the existing .mp-board-fullscreen idiom (:228 below) — same CSS
   that already covers the viewport and hides the navbar for Scoreboard/RunBoard (.mp-shell:has(.mp-board-fullscreen)
   .mp-navbar) — so a grid's full-screen mode gets that behaviour for free instead of a second implementation. */
.mp-grid-fs { display: contents; }
.mp-grid-fs.mp-board-fullscreen { display: flex; flex-direction: column; gap: 0; }
.mp-grid-fs.mp-board-fullscreen .mp-reg-wrap { flex: 1 1 auto; min-height: 0; }
/* results-scoreboard-workspace ADR-1 §4: generalized scroll-region growth rule alongside the Registration/Weigh-
   ins-specific one above — any grid that opts in via [data-grid-fs-scroll] (the OPL export editor's
   .mp-oplxe-scroller) gets the SAME "only the grid grows, everything else stays fixed" full-screen behaviour,
   overriding that element's own max-height cap so it can actually fill the remaining space. */
.mp-grid-fs.mp-board-fullscreen [data-grid-fs-scroll] { flex: 1 1 auto; min-height: 0; max-height: none; overflow: auto; }
.mp-grid-fs-head { display: none; }
.mp-grid-fs.mp-board-fullscreen .mp-grid-fs-head {
    display: flex; align-items: center; gap: 1rem; flex-wrap: wrap;
    margin: -1rem -1.25rem 0.75rem; padding: 0.65rem 1.25rem;
    background: #0b0f14; color: #fff; border-bottom: 1px solid var(--mp-border);
}
.mp-grid-fs-brand { font-weight: 800; letter-spacing: 0.02em; }
.mp-grid-fs-meet { color: color-mix(in srgb, #fff 75%, transparent); }
.mp-grid-fs-name { font-weight: 700; color: var(--mp-accent); }
.mp-grid-fs-head .mp-autosave-status { margin-left: auto; }
.mp-grid-fs-head .mp-btn { min-height: 44px; }

/* ---- Lifter-linking Phase 2 (WP-U5/U6/U7/U8): identity fields, match strip, account/email/opl/media columns ---- */

/* Add-form email match strip (rapid-add, WP-U5) — text as well as colour: every state renders a leading glyph and
   the label text is never colour-only. Populated by entry-identity.js from /entry-email-match. */
.mp-id-strip { margin-top: 0.3rem; font-size: 0.78rem; min-height: 1rem; }
.mp-id-strip[data-state] { display: flex; align-items: center; gap: 0.35rem; }
.mp-id-strip[data-state="verified"] { color: var(--mp-good); }
.mp-id-strip[data-state="unverified"] { color: var(--mp-accent); }
.mp-id-strip[data-state="already"] { color: var(--mp-info); }
.mp-id-strip[data-state="conflict"], .mp-id-strip[data-state="invalid"] { color: var(--mp-nolift); }
.mp-id-strip[data-state="none"] { color: var(--mp-muted); }
.mp-id-strip .mp-linkbtn { font-size: 0.78rem; }

/* OpenPowerlifting handle input with a fixed "openpowerlifting.org/u/" prefix (mock-up affordance) — a full URL
   still works if pasted (ProfileLinkNormalizer accepts either), the prefix is purely a hint. */
.mp-opl-input { display: flex; align-items: stretch; border: 1px solid var(--mp-border); border-radius: 6px; overflow: hidden; background: var(--mp-bg); }
.mp-opl-prefix { display: flex; align-items: center; padding: 0 0.5rem; font-size: 0.78rem; color: var(--mp-muted); background: var(--mp-surface-2); white-space: nowrap; }
.mp-opl-input .mp-opl-field.form-control { border: none; border-radius: 0; }

/* The "Will link to…" note left by the pre-add review panel (WP-U5/WP-U6 shared dialog, pre-add mode). */
.mp-id-link-note { margin: 0.4rem 0 0; font-size: 0.82rem; color: var(--mp-good); }

/* Account/OpenPowerlifting grid cells (WP-U6/WP-U7). */
.mp-opl-cell { display: flex; align-items: center; gap: 0.4rem; padding: 0.25rem 0.4rem; }
.mp-opl-link { color: var(--mp-text); text-decoration: underline; font-size: 0.82rem; }
.mp-opl-link:hover { color: var(--mp-accent); }
button.mp-opl-state { border: 1px solid var(--mp-border); cursor: pointer; }
button.mp-opl-state:hover, button.mp-opl-state:focus-visible { border-color: var(--mp-accent); outline: none; }
.mp-reg td[data-col="opl"] input.form-control { border-top: 1px solid var(--mp-border); }

/* Media cell (WP-U8): a small square preview + label, sized as a real 44px-plus touch target. */
.mp-id-media-btn {
    display: flex; flex-direction: column; align-items: center; gap: 0.2rem; width: 100%; min-height: 44px;
    background: transparent; border: none; cursor: pointer; color: var(--mp-text); padding: 0.3rem;
}
.mp-id-media-btn:hover, .mp-id-media-btn:focus-visible { color: var(--mp-accent); outline: none; }
.mp-id-media-thumb { width: 1.8rem; height: 1.8rem; border-radius: 50%; object-fit: cover; border: 1px solid var(--mp-border); }
.mp-id-media-placeholder { width: 1.8rem; height: 1.8rem; border-radius: 50%; border: 1px dashed var(--mp-border); display: flex; align-items: center; justify-content: center; color: var(--mp-muted); font-size: 0.7rem; }
.mp-id-media-btn span[aria-hidden] { font-size: 0.65rem; text-transform: uppercase; letter-spacing: 0.03em; color: var(--mp-muted); }

/* Shared right-side drawer for the three identity panels (link review / OpenPowerlifting preview / media manage) —
   same native-<dialog>-as-drawer shape as .mp-undo-drawer (free focus trap/Escape/focus-return from showModal()). */
.mp-id-drawer {
    position: fixed; inset: 0 0 0 auto; margin: 0; width: min(28rem, 100%); max-width: min(28rem, 100%);
    height: 100%; max-height: 100vh; overflow-y: auto;
    background: var(--mp-surface); color: var(--mp-text); border: 1px solid var(--mp-border);
    border-radius: 0; border-top: 0; border-right: 0; border-bottom: 0; padding: 1.1rem 1.2rem;
    box-shadow: -14px 0 40px rgba(0,0,0,0.45);
}
.mp-id-drawer::backdrop { background: rgba(0, 0, 0, 0.55); }
.mp-id-drawer-close { width: 2.2rem; height: 2.2rem; border-radius: 6px; background: var(--mp-surface-2); color: var(--mp-text); border: 1px solid var(--mp-border); cursor: pointer; font-size: 1rem; line-height: 1; }
.mp-id-drawer-close:hover { border-color: var(--mp-accent); color: var(--mp-accent); }
.mp-id-drawer-actions { display: flex; flex-direction: column; gap: 0.6rem; margin-top: 1rem; }
.mp-id-drawer-actions label { font-size: 0.85rem; display: flex; align-items: center; gap: 0.4rem; }
.mp-id-drawer-error { color: var(--mp-nolift); font-weight: 700; margin-top: 0.7rem; font-size: 0.85rem; }
.mp-id-drawer-candidate { border: 1px solid var(--mp-border); border-radius: 8px; padding: 0.7rem 0.85rem; margin: 0.6rem 0; background: var(--mp-surface-2); }
.mp-id-drawer-candidate dt { color: var(--mp-muted); font-size: 0.75rem; }
.mp-id-drawer-candidate dd { margin: 0 0 0.4rem; }
.mp-id-media-section { border: 1px solid var(--mp-border); border-radius: 8px; padding: 0.75rem; margin-bottom: 0.85rem; }
.mp-id-media-section h4 { margin: 0 0 0.4rem; }
.mp-id-media-preview { width: 100%; max-width: 12rem; border-radius: 6px; display: block; margin-bottom: 0.5rem; border: 1px solid var(--mp-border); }
.mp-id-media-actions { display: flex; gap: 0.5rem; flex-wrap: wrap; }
.mp-id-stats-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 0.5rem 0.8rem; margin: 0.6rem 0; }
.mp-id-stat { border: 1px solid var(--mp-border); border-radius: 8px; padding: 0.5rem 0.6rem; }
.mp-id-stat dt { color: var(--mp-muted); font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.03em; }
.mp-id-stat dd { margin: 0; font-size: 1.1rem; font-weight: 800; font-variant-numeric: tabular-nums; }
.mp-id-attribution { font-size: 0.75rem; color: var(--mp-muted); margin-top: 1rem; padding-top: 0.6rem; border-top: 1px solid var(--mp-border); }
@media (max-width: 480px) {
    .mp-id-drawer { width: 100%; max-width: 100%; }
}

/* Lightweight client-side email validation (entry-identity.js, on blur) — the input itself turns red AND an
   inline text message appears, so the state is never colour-only. Never blocks saving a well-formed value; the
   server remains the source of truth for what actually gets rejected. */
input.mp-field-invalid { border-color: var(--mp-nolift) !important; }
.mp-field-error-msg { display: block; color: var(--mp-nolift); font-size: 0.75rem; margin-top: 0.2rem; }
.mp-reg td .mp-field-error-msg { position: absolute; background: var(--mp-surface); padding: 0.1rem 0.3rem; border-radius: 4px; }

/* ---- Shared data-grid foundation (director-ui-spec §8.3 / WP2) ----
   Net-new, reusable primitives extracted from the proven Registration grid above: sticky header, bounded
   horizontal + vertical scroll, dense hoverable rows, and data-driven sortable/filterable headers. Driven by
   data-grid.js off column data-attributes (data-dg-numeric) and stable .mp-dg-* hooks rather than page-specific
   selectors, so any page (Entries, future grids) can consume it. Registration/WeighIns deliberately still use the
   .mp-reg-* rules above — see WP2 notes; migrating them is a separate safe step. Adds a sticky-LEFT column
   capability (Entries needs a pinned Lifter column) that the Registration original never had. */
.mp-data-grid-wrap { height: calc(100vh - 13rem); min-height: 18rem; overflow: auto; border: 1px solid var(--mp-border); border-radius: 10px; background: var(--mp-surface); }
.mp-data-grid { border-collapse: separate; border-spacing: 0; width: max-content; min-width: 100%; font-size: 0.85rem; }
.mp-data-grid thead th {
    position: sticky; top: 0; z-index: 3; background: var(--mp-surface);
    border-bottom: 2px solid var(--mp-border); padding: 0.5rem 0.65rem; text-align: left;
    white-space: nowrap; font-weight: 700; color: var(--mp-muted);
}
.mp-data-grid tbody td { border-bottom: 1px solid var(--mp-border); padding: 0.4rem 0.65rem; white-space: nowrap; vertical-align: middle; }
.mp-data-grid tbody tr:hover td { background: color-mix(in srgb, var(--mp-accent) 7%, transparent); }

/* Sticky-LEFT column (e.g. Entries lifter name). The body cell needs an OPAQUE background so horizontally
   scrolled cells don't bleed through it; the header corner (sticky top AND left) must sit above everything. */
.mp-data-grid .mp-dg-sticky-left { position: sticky; left: 0; z-index: 2; background: var(--mp-surface); }
.mp-data-grid tbody tr:hover td.mp-dg-sticky-left { background: color-mix(in srgb, var(--mp-accent) 12%, var(--mp-surface)); }
.mp-data-grid thead th.mp-dg-sticky-left { z-index: 6; }

/* Sortable + filterable header — label (sort, keyboard-activatable) on the left, filter funnel on the right. */
.mp-data-grid .mp-dg-head { display: flex; align-items: center; gap: 0.4rem; justify-content: space-between; }
.mp-data-grid .mp-dg-sort-label { cursor: pointer; user-select: none; display: inline-flex; align-items: center; gap: 0.25rem; white-space: nowrap; border-radius: 4px; }
.mp-data-grid .mp-dg-sort-label:hover { color: var(--mp-text); }
.mp-data-grid .mp-dg-sort-label:focus-visible { outline: 2px solid var(--mp-accent); outline-offset: 2px; }
.mp-data-grid .mp-dg-sort-ind { font-size: 0.65rem; color: var(--mp-accent); }
.mp-data-grid .mp-dg-sort-ord { font-size: 0.6rem; color: var(--mp-muted); margin-left: -0.15rem; }
.mp-data-grid .mp-dg-filter-wrap { position: relative; flex: none; }
.mp-data-grid .mp-dg-filter-wrap > summary {
    list-style: none; cursor: pointer; color: var(--mp-muted); display: inline-flex; line-height: 1; padding: 2px; border-radius: 4px;
}
.mp-data-grid .mp-dg-filter-wrap > summary::-webkit-details-marker { display: none; }
.mp-data-grid .mp-dg-filter-wrap > summary:hover { color: var(--mp-text); background: color-mix(in srgb, var(--mp-accent) 12%, transparent); }
.mp-data-grid .mp-dg-filter-wrap > summary:focus-visible { outline: 2px solid var(--mp-accent); outline-offset: 1px; }
.mp-data-grid .mp-dg-filter-wrap.mp-dg-filter-on > summary { color: var(--mp-accent); }
.mp-data-grid th:has(.mp-dg-filter-wrap[open]) { z-index: 7; }
.mp-data-grid .mp-dg-filter-pop {
    position: absolute; right: 0; top: 100%; z-index: 8; margin-top: 3px;
    background: var(--mp-surface); border: 1px solid var(--mp-border); border-radius: 6px; padding: 6px; box-shadow: 0 6px 18px rgba(0,0,0,0.35);
}
.mp-data-grid .mp-dg-filter {
    width: 150px; box-sizing: border-box; padding: 0.3rem 0.4rem; font-size: 0.8rem; font-weight: 400;
    border: 1px solid var(--mp-border); border-radius: 4px; background: var(--mp-bg); color: var(--mp-text);
}
.mp-data-grid .mp-dg-filter:focus { outline: none; border-color: var(--mp-accent); }
.mp-data-grid td.mp-dg-center { text-align: center; }
.mp-data-grid .mp-dg-empty { padding: 1rem; text-align: center; color: var(--mp-muted); }

/* Collapsible "Add competitor" panel. */
.mp-add-panel { border: 1px solid var(--mp-border); border-radius: 10px; background: var(--mp-surface); margin-bottom: 0.75rem; }
.mp-add-panel > summary { cursor: pointer; padding: 0.6rem 0.9rem; font-weight: 700; list-style: none; display: flex; align-items: center; gap: 0.5rem; }
.mp-add-panel > summary::-webkit-details-marker { display: none; }
.mp-add-panel > summary::before { content: "▸"; color: var(--mp-accent); transition: transform 0.15s; }
.mp-add-panel[open] > summary::before { transform: rotate(90deg); }
.mp-add-panel .mp-add-body { padding: 0 0.9rem 0.9rem; }
/* Themed inputs in the Add-competitor form, matching the Divisions/Events multiselect controls. */
.mp-add-panel .form-control {
    background: var(--mp-bg); color: var(--mp-text); border: 1px solid var(--mp-border); border-radius: 6px;
    padding: 0.4rem 0.5rem; font: inherit; box-shadow: none;
}
.mp-add-panel .form-control::placeholder { color: var(--mp-muted); }
.mp-add-panel .form-control:hover { border-color: color-mix(in srgb, var(--mp-accent) 45%, var(--mp-border)); }
.mp-add-panel .form-control:focus {
    outline: none; border-color: var(--mp-accent); background: var(--mp-bg); color: var(--mp-text);
    box-shadow: 0 0 0 2px color-mix(in srgb, var(--mp-accent) 25%, transparent);
}
.mp-add-panel label.mp-muted { display: block; margin-bottom: 0.15rem; }

/* ---- Meet-day boards ---- */
.mp-board-fullscreen { position: fixed; inset: 0; z-index: 1000; overflow: auto; padding: 1rem 1.25rem; background: var(--mp-bg); }
/* A fullscreen board only visually covers the app chrome; z-index occlusion alone leaves the navbar's links
   keyboard-Tab-reachable on a kiosk/audience screen. display:none removes them from the tab order and the
   accessibility tree. The shell observes the board structurally with :has() because MainLayout renders
   statically (SSR) and cannot see the interactive board island's Present state toggle at runtime. */
.mp-shell:has(.mp-board-fullscreen) .mp-navbar { display: none; }
/* Presentation mode: only the boards show; the Exit button stays out of the way until hovered. */
.mp-sb-present { padding: 0.5rem 0.75rem; }
.mp-sb-exit { position: fixed; top: 0.5rem; right: 0.5rem; z-index: 1100; opacity: 0.25; transition: opacity 0.15s; }
.mp-sb-exit:hover { opacity: 1; }
.mp-board-head { display: flex; justify-content: space-between; align-items: center; gap: 1rem; margin-bottom: 0.75rem; flex-wrap: wrap; }
.mp-board-title { font-weight: 800; font-size: 1.25rem; }
.mp-board-logo { height: 32px; vertical-align: middle; margin-right: 0.5rem; }
.mp-board-platform { margin-bottom: 1.5rem; }
.mp-board-platform:last-child { margin-bottom: 0; }
.mp-board-current { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.3rem 0.85rem; background: var(--mp-surface); border: 1px solid var(--mp-border); border-left: 4px solid var(--mp-accent); border-radius: 8px; padding: 0.6rem 1rem; margin-bottom: 0.75rem; }
.mp-board-table th, .mp-board-table td { padding: 0.35rem 0.55rem; font-variant-numeric: tabular-nums; }
.mp-board-table td { border-bottom: 1px solid var(--mp-border); }
.mp-row-current { background: color-mix(in srgb, var(--mp-accent) 18%, transparent); }
/* Flight separator band: each flight in a platform board gets a labelled header row; the flight lifting now is highlighted, the others are dimmed. */
.mp-board-table .mp-sb-flightrow td { background: var(--mp-surface-2, #1b222c); color: var(--mp-muted); font-weight: 800; text-transform: uppercase; letter-spacing: 0.04em; font-size: 0.78rem; border-top: 2px solid var(--mp-border); border-bottom: 1px solid var(--mp-border); }
.mp-board-table .mp-sb-flightrow.current td { color: var(--mp-accent); background: color-mix(in srgb, var(--mp-accent) 14%, var(--mp-surface)); }
.mp-board-table tr.mp-sb-otherflight td { opacity: 0.6; }
.mp-board-table td.mp-cell-sub { font-weight: 700; }
.mp-cell-good { color: var(--mp-good); font-weight: 800; }
.mp-cell-nolift { color: var(--mp-nolift); font-weight: 800; text-decoration: line-through; }
.mp-cell-bomb { color: var(--mp-nolift); font-weight: 800; }
.mp-cell-current { outline: 2px solid var(--mp-accent); outline-offset: -2px; }

/* ==== Scoreboard/Livestream WP5: condensed scoreboard + play links (spec §3.1/§5.1) ==== */
.mp-sb-toggle-group { display: inline-flex; border-radius: 8px; overflow: hidden; }
.mp-sb-toggle-group .mp-btn { border-radius: 0; }

/* Sticky first column (place + forecast + name) so the identity stays visible while the attempt columns scroll
   horizontally at narrow widths. Needs an OPAQUE background matching whatever the row underneath would show,
   otherwise horizontally-scrolled cells show through the sticky column. */
.mp-sb-sticky {
    position: sticky; left: 0; z-index: 2; text-align: left;
    background: var(--mp-surface); min-width: 9rem; max-width: 15rem;
}
tr.mp-row-current .mp-sb-sticky { background: color-mix(in srgb, var(--mp-accent) 18%, var(--mp-surface)); }
.mp-sb-place { font-weight: 800; }
/* Forecast transition ("9 → 8"): visually marked as a PROJECTION (arrow + accent colour), distinct from the plain
   current-place number beside it — spec §3.1 "never as the current place". */
.mp-sb-forecast { display: inline-flex; align-items: center; gap: 0.1rem; margin-left: 0.35rem; color: var(--mp-accent); font-weight: 800; font-size: 0.78rem; }
.mp-sb-name { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 14rem; }

/* Play control: a real link (never a bare onclick div), touch target held at >=44x44 CSS px even though the glyph
   itself is small (spec §3.1 "must remain at least 44 x 44 CSS px as a touch target, even if its visible glyph is
   smaller"). Present in both full and condensed modes (spec §5.1); absent whenever a completed cell has no Ready
   clip (Razor renders nothing — no dead/broken link, spec §12). */
.mp-lift-video {
    display: inline-flex; align-items: center; justify-content: center;
    width: 44px; height: 44px; margin-left: 0.15rem; vertical-align: middle;
    border-radius: 8px; color: var(--mp-text); text-decoration: none; font-size: 0.85rem;
    background: color-mix(in srgb, var(--mp-accent) 12%, transparent);
}
.mp-lift-video:hover, .mp-lift-video:focus-visible {
    background: color-mix(in srgb, var(--mp-accent) 28%, transparent);
    outline: 2px solid var(--mp-accent); outline-offset: 1px;
}
/* The condensed grid's glyph is smaller (compact numeric cells) but the tappable box itself never shrinks below 44px. */
.mp-sb-condensed-table .mp-lift-video { font-size: 0.68rem; }

/* Present mode: belt-and-braces (spec §5.1/§13 acceptance example 5). The Razor condition already never renders a
   play link while _present is true — this rule is the defensive second layer named in the WP brief, so a play
   control can never surface even if a future change forgets the Razor guard. */
.mp-sb-present .mp-lift-video { display: none !important; }

/* Fit at 390px with compact numeric cells (spec §3.1); a horizontal scrollbar on the TABLE'S OWN wrapper (never the
   outer page) covers narrower widths and the extra column a fourth-attempt meet adds. */
.mp-sb-condensed-wrap { overflow-x: auto; }
.mp-sb-condensed-table th, .mp-sb-condensed-table td { text-align: center; font-variant-numeric: tabular-nums; white-space: nowrap; }
@media (max-width: 480px) {
    .mp-sb-condensed-table th, .mp-sb-condensed-table td { padding: 0.3rem 0.4rem; font-size: 0.82rem; }
    .mp-sb-sticky { min-width: 7rem; max-width: 9rem; }
    .mp-sb-name { max-width: 8rem; }
}

/* ==== display-board-typography §7.2/§7.3: the scoreboard's resolution-aware type scale ======================
   EVERY rule below is scoped under .mp-sb on purpose, including the ones that look like they belong on the
   shared classes. .mp-board-table, .mp-row-current and the .mp-cell-* family are shared with the OPERATOR run
   board (RunMeet.razor renders the same .mp-table.mp-board-table), so the shared rules above are left exactly
   as they are and the scoreboard states its own sizes here. A change made for the 65-inch audience screen must
   never silently re-type the director's laptop.

   Each token is `calc(<1080p design px> * var(--mp-display-unit))`, where --mp-display-unit is
   (max(1px, 100vh/1080)) x the operator's 0.8-1.5 choice — see the shared block at the top of this file. So the
   number inside each calc() IS the intended size in CSS px on a 1920x1080 screen at 100%, and it doubles by
   itself at 3840x2160 purely because the viewport is twice as tall. Nothing here branches on window.screen,
   devicePixelRatio, the user agent or a "4K mode": the viewport is the only input, which is what makes a
   bookmarked ?fullscreen=true URL, Present mode and a browser-source capture all agree.

   The bases are picked so that base x 1.25 clears the §7.3 minimum at the "Audience 65in" preset, which is the
   size those minimums are stated at:
     current lifter name  28 -> 35.00 (min 34)     scoreboard body rows  23 -> 28.75 (min 28)
     current weight       29 -> 36.25 (min 36)     lifter identity       24 -> 30.00 (min 30)
     table headings       16 -> 20.00 (min 20)     flight separator      16 -> 20.00 (min 20)
     PB/record glyph      13 -> 16.25 (min 16)     (in Scoreboard.razor.css, where those badges live)

   §4.4/§7.4: there is deliberately NO clamp-down, no max-height and no font-size reduction anywhere in this
   block. When the operator asks for bigger type the board shows FEWER ROWS in the same space — the table
   wrappers scroll — rather than quietly serving type smaller than what was asked for. */

/* The current-lifter strip: the loudest thing on the board (§7.4). The strip itself gets a modest base so the
   round/flight chatter beside the name scales with everything else; .mp-badge keeps its own size, so the
   platform and "Competition not started" pills are unaffected. "Next" gets an explicit, much smaller token
   instead of the browser default, so the gap between "lifting now" and "on deck" is just as obvious at 4K/140%
   as it is at 1080p/100% (at the default it would stay 16px while the current line grew to 56px). */
.mp-sb .mp-board-current { font-size: calc(17 * var(--mp-display-unit)); min-width: 0; max-width: 100%; }
.mp-sb .mp-sb-current-name {
    font-size: calc(28 * var(--mp-display-unit)); font-weight: 900; line-height: 1.15;
    min-width: 0; max-width: 100%; overflow-wrap: anywhere;
}
.mp-sb .mp-sb-current-weight {
    font-size: calc(29 * var(--mp-display-unit)); font-weight: 900; line-height: 1.15;
    color: var(--mp-accent); font-variant-numeric: tabular-nums; white-space: nowrap;
}
.mp-sb .mp-sb-current-next { font-size: calc(18 * var(--mp-display-unit)); min-width: 0; max-width: 100%; }

/* Board rows and headings. font-variant-numeric is restated because these overrides sit at higher specificity
   than the shared .mp-board-table rule that carries it; without it a weight column would lose tabular figures
   and its digits would visibly jitter as attempts land. */
.mp-sb .mp-board-table th { font-size: calc(16 * var(--mp-display-unit)); }
.mp-sb .mp-board-table td { font-size: calc(23 * var(--mp-display-unit)); font-variant-numeric: tabular-nums; }
/* Flight separator band — a label, not data, so it stays at heading size rather than row size. */
.mp-sb .mp-board-table .mp-sb-flightrow td { font-size: calc(16 * var(--mp-display-unit)); }

/* Lifter identity, one step above the numbers it sits beside (§7.3): the condensed board's .mp-sb-name span and
   the full board's .mp-sb-namecell span are the same idiom. Both stay single-line + ellipsis — a name that
   wrapped to two lines would cost a whole extra row of board height per long-named lifter at 140%. The ellipsis
   box has to be an inner BLOCK because max-width on a <td> is not honoured under auto table layout. Its
   max-width scales with the type (it is collision spacing, not panel geometry): a fixed 14rem box with 30px
   text inside would truncate two thirds of the field at the audience preset. */
.mp-sb .mp-sb-name,
.mp-sb .mp-board-table td .mp-sb-namecell { font-size: calc(24 * var(--mp-display-unit)); font-weight: 700; }
.mp-sb .mp-sb-name { max-width: calc(224 * var(--mp-display-unit)); }
.mp-sb .mp-board-table td .mp-sb-namecell {
    display: block; min-width: 0; max-width: calc(240 * var(--mp-display-unit));
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.mp-sb .mp-sb-sticky { min-width: calc(144 * var(--mp-display-unit)); max-width: calc(240 * var(--mp-display-unit)); }

/* The forecast arrow is read from the same distance as the numbers it annotates, so it scales too; left at
   0.72rem it would be an 11px mark next to 46px digits on a 4K audience screen. */
.mp-sb .mp-sb-forecast { font-size: calc(15 * var(--mp-display-unit)); }

/* §4.4/§7.4 overflow containment. The rule is: horizontal overflow lives INSIDE the table's own wrapper, and
   the PAGE never grows a horizontal scrollbar at any size from 80% to 150%, at 1920x1080 or 3840x2160. Blocks
   are width:auto so they cannot push the page out on their own; what can is a table (intrinsically as wide as
   its content) or a flex item that refuses to shrink below its content. Hence: scroll containers on both table
   wrappers, and min-width:0 on the flex/table chain above them so the shrink actually happens. .mp-sb-full-wrap
   also carries the padding:0 that used to be an inline style on that .mp-card.

   The board ROOT deliberately gets min-width:0 ONLY, never max-width:100%: in Present / ?fullscreen=true it is
   position:fixed with inset:0 and its own padding, and a percentage max-width there resolves against the
   viewport and can reintroduce the very overflow it was meant to prevent. */
.mp-sb { min-width: 0; }
.mp-sb .mp-board-platform { min-width: 0; max-width: 100%; }
.mp-sb .mp-sb-condensed-wrap { min-width: 0; max-width: 100%; overflow-x: auto; }
.mp-sb .mp-sb-full-wrap { padding: 0; min-width: 0; max-width: 100%; overflow-x: auto; }

/* §7.5: neither Present nor ?fullscreen=true resets anything typographic — .mp-board-fullscreen sets only
   position/inset/z-index/overflow/padding/background and .mp-sb-present only padding (both above), and the
   scale itself is a custom property on <html> that no board-root class can shadow. So a screen that was set to
   125% shows 125% the moment it enters Present, and a bookmarked ?fullscreen=true kiosk URL comes up at 125%
   without ever painting 100% first. Checked, and deliberately left with NO rule of its own: adding a defensive
   font-size here would be the very kind of reset this note exists to rule out. */

/* Mobile (the existing 480px breakpoint above). A phone looking at the public scoreboard is not a venue
   display: the condensed board is designed to fit 390px, and 23px rows would blow that apart. These restate
   the pre-existing compact sizes at a specificity that beats the .mp-sb-scoped tokens above, so the phone
   layout is byte-for-byte what it was before this work package. The operator's Text size choice still applies
   to the board on a venue screen; it just does not get to shrink-wrap a phone. */
@media (max-width: 480px) {
    .mp-sb .mp-board-table th, .mp-sb .mp-board-table td { font-size: 0.82rem; }
    .mp-sb .mp-board-table .mp-sb-flightrow td { font-size: 0.78rem; }
    .mp-sb .mp-sb-name,
    .mp-sb .mp-board-table td .mp-sb-namecell { font-size: 0.82rem; max-width: 8rem; }
    .mp-sb .mp-sb-sticky { min-width: 7rem; max-width: 9rem; }
    .mp-sb .mp-sb-forecast { font-size: 0.78rem; }
    .mp-sb .mp-board-current { font-size: 1rem; }
    .mp-sb .mp-sb-current-name { font-size: 1.2rem; }
    .mp-sb .mp-sb-current-weight { font-size: 1.25rem; }
    .mp-sb .mp-sb-current-next { font-size: 1rem; }
}

/* ---- Inline editable run-board cells (edit happens in the cell, not a popover) ---- */
.mp-edit-cell { cursor: pointer; min-width: 2.6rem; }
.mp-edit-cell.editing { background: var(--mp-surface); outline: 2px solid var(--mp-accent); outline-offset: -2px; min-width: 150px; }
.mp-cell-val { display: block; }
/* The editor replaces the value in place: while editing, hide the displayed value and show the input overtop. The
   editor fills the (widened) cell exactly — width:100% with no min-width so it never spills past the cell's edges. */
.mp-edit-cell.editing .mp-cell-val { display: none; }
.mp-cell-edit { display: none; width: 100%; min-width: 0; box-sizing: border-box; }
.mp-edit-cell.editing .mp-cell-edit { display: block; }
.mp-cell-weight { flex: 1 1 3rem; min-width: 3rem; padding: 0.25rem 0.35rem; box-sizing: border-box;
    border: 1px solid var(--mp-border); border-radius: 6px; font-size: 0.95rem; background: var(--mp-bg); color: var(--mp-text); }
.mp-cell-actions { display: flex; gap: 0.2rem; flex: 1 1 100%; }
/* Collapsed non-active lift: click the summary to expand an editor for all 3 attempts. */
.mp-collapsed-cell .mp-cell-val { cursor: pointer; }
.mp-cell-edit-multi { min-width: 0; }
.mp-cell-edit-title { font-weight: 800; font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.04em;
    color: var(--mp-muted); margin-bottom: 0.3rem; }
.mp-cell-edit-row { display: flex; flex-wrap: wrap; align-items: center; gap: 0.3rem; margin-bottom: 0.3rem; }
.mp-cell-edit-row:last-child { margin-bottom: 0; }
.mp-cell-edit-lbl { width: 1rem; flex: none; color: var(--mp-muted); font-size: 0.8rem; text-align: right; }
.mp-cell-btn { flex: 1; padding: 0.25rem 0; border: 1px solid var(--mp-border); border-radius: 6px;
    background: var(--mp-bg); color: var(--mp-text); cursor: pointer; font-size: 1rem; line-height: 1; }
.mp-cell-btn:hover { background: var(--mp-bg); filter: brightness(1.1); }
.mp-cell-btn.good { color: var(--mp-good); border-color: var(--mp-good); }
.mp-cell-btn.nolift { color: var(--mp-nolift); border-color: var(--mp-nolift); }
.mp-cell-btn.warn { color: #d97706; border-color: #d97706; }
.mp-cmd-error { outline: 2px solid var(--mp-nolift) !important; }
.mp-linkbtn { background: none; border: none; padding: 0; color: var(--mp-accent); cursor: pointer;
    font-size: inherit; text-decoration: underline; }

/* Compact "set current" affordance + flight grouping separators. */
.mp-setcur { padding: 0.05rem 0.4rem; font-size: 0.8rem; line-height: 1.2; border: 1px solid var(--mp-border);
    border-radius: 5px; background: var(--mp-bg); color: var(--mp-muted); cursor: pointer; }
.mp-setcur:hover { border-color: var(--mp-accent); color: var(--mp-accent); }
.mp-flight-sep td { background: var(--mp-surface); font-weight: 800; padding: 0.45rem 0.6rem;
    border-top: 2px solid var(--mp-border); border-bottom: 1px solid var(--mp-border); }
.mp-flight-sep.current td { color: var(--mp-accent); box-shadow: inset 4px 0 0 var(--mp-accent); }
/* Presentation mode: the board goes full-bleed and the top menu bar is hidden; a faint Exit button stays. */
.mp-btn.mp-runboard-exit { display: none; }
/* justify-content: safe center vertically centres the content, falling back to top-alignment instead of clipping
   when it overflows; the extra top padding reserves the fixed Exit button's zone so it can never overlap the
   Good Lift button even when the board is taller than the screen. */
.mp-runboard.present { position: fixed; inset: 0; z-index: 1000; overflow: auto; padding: 3.5rem 0.75rem 0.5rem; background: var(--mp-bg); display: flex; flex-direction: column; justify-content: safe center; }
.mp-runboard.present .mp-board-head { display: none; }
.mp-runboard.present .mp-runboard-exit { display: inline-flex; position: fixed; top: 0.5rem; right: 0.5rem; z-index: 1100;
    opacity: 0.25; transition: opacity 0.15s; }
.mp-runboard.present .mp-runboard-exit:hover { opacity: 1; }

/* ---- Run-board current-lifter header (bar weight + name/meta left; No lift / Good lift / ☰ right) ---- */
/* Head: current lifter (name/weight/age/equipment/division) on the left, action buttons on the right. */
.mp-run-head { display: flex; justify-content: space-between; align-items: center; gap: 1rem; flex-wrap: wrap;
    background: var(--mp-surface); border: 1px solid var(--mp-border); border-left: 4px solid var(--mp-accent);
    border-radius: 10px; padding: 0.6rem 0.9rem; margin: 0.5rem 0; }
/* flex-basis 0 (not auto) is load-bearing: the head wraps, and wrap decisions use an item's BASE size, so a
   basis of auto would let a long untruncated name push the buttons onto a second row before shrinking is ever
   considered. With basis 0 the left block can never force a wrap — it grows into whatever the right-hand
   controls leave, and min-width:0 lets the name inside it ellipsis instead of overflowing. */
.mp-run-head-left { display: flex; flex-direction: column; gap: 0.1rem; min-width: 0; flex: 1 1 0; }
/* Body: the loaded bar (fixed ~500px) on the left, the run-sheet grid filling the rest on the right. */
.mp-run-body { display: flex; gap: 1rem; align-items: flex-start; }
.mp-run-grid { flex: 1 1 auto; min-width: 0; }
/* Left column under the head: the loaded bar with the next-lifter strip beneath it. */
/* The column was a FIXED 500px, which starved the Next/Then identity column: the card is a
   "minmax(0,1fr) minmax(12rem,13rem)" grid, so at 500px the 1fr identity track resolved to 249px and — after the
   "NEXT" tag (51px) and the badge stack — left the lifter name only 137px. "Oliver Thompson" measures 231px at
   100% and 277px at 120%, so an ordinary two-word name ellipsised to "Oliver ..." on every desktop screen even
   though the run-sheet table beside it had several hundred pixels of slack. §5.1 ranks the Next/Then name 4th in
   the distance-reading hierarchy, so the LAYOUT gives way, not the type (§5.2 forbids shrinking a configured
   size to fit). Now the column takes a share of the viewport instead: the floor is the old 500px, so every
   viewport at or below ~1315px is byte-identical to before (1280x720 regression shots included), and a 1920px
   screen gives the column 720px — enough for the name to render in full at 100%, 120% AND 150%. The mobile rule
   at the 720px breakpoint further down still overrides BOTH declarations back to flex: 1 1 100% / max-width: 100%. */
.mp-run-leftcol { flex: 0 0 clamp(31.25rem, 38vw, 45rem); max-width: 45rem; min-width: 0; display: flex; flex-direction: column; gap: 0.5rem; }
.mp-run-bar { display: flex; flex-direction: column; width: 100%; background: var(--mp-surface);
    border: 1px solid var(--mp-border); border-radius: 10px; padding: 0.5rem 0.8rem; }
/* display-board-typography §5.3: weight + rack callout side by side, wrapping the callout onto its own line
   underneath the weight rather than letting either one squeeze the other — "safe center" keeps both centred
   whichever way it lays out. Renders with only .mp-run-bar-top present when there is no rack callout (the Razor
   guards that), so an unset rack never reserves empty space here. */
.mp-run-bar-headline { display: flex; align-items: center; justify-content: center; flex-wrap: wrap; gap: 0.6rem 1rem; }
.mp-run-bar-top { text-align: center; font-size: calc(54 * var(--mp-display-unit)); font-weight: 900; color: var(--mp-accent);
    line-height: 1.05; font-variant-numeric: tabular-nums; }
.mp-run-bar-track { display: flex; align-items: center; gap: 4px; flex-wrap: nowrap; overflow-x: auto; min-height: 310px; }
/* §5.3: a prominent labelled callout, high-contrast against both good/no-lift colours (a distinct accent border+
   tint, not green/red) so a loader can find "what rack height" at a glance beside the weight it goes with. */
.mp-run-rack-callout { display: flex; flex-direction: column; align-items: center; line-height: 1.05;
    padding: 0.15rem 0.7rem; border: 2px solid var(--mp-accent); border-radius: 8px;
    background: color-mix(in srgb, var(--mp-accent) 16%, transparent); }
.mp-run-rack-label { font-size: calc(15 * var(--mp-display-unit)); font-weight: 800; text-transform: uppercase;
    letter-spacing: 0.06em; color: var(--mp-muted); }
.mp-run-rack-value { font-size: calc(37 * var(--mp-display-unit)); font-weight: 900; color: var(--mp-text);
    font-variant-numeric: tabular-nums; }
/* The bar shaft (inner end), the collar, and the sleeve end poking out past the collar — all centred on the loading axis. */
.mp-run-barshaft { flex: 0 0 auto; width: 30px; height: 33px; border-radius: 3px;
    background: linear-gradient(180deg, #d3d8df, #8b929c 55%, #6b7280); border: 1px solid rgba(0,0,0,0.5); }
.mp-run-barend { width: 38px; }   /* the sleeve end pokes out past the collar on the right */
/* Collar ≈ 3/4 the height of the 1.25 kg plate (≈104px) so the thin bar end clearly shows above/below it. */
.mp-run-collar { position: relative; flex: 0 0 auto; width: 26px; height: 78px; border-radius: 5px; margin: 0 1px;
    background: linear-gradient(180deg, #d3d8df, #9aa0aa 50%, #5b616b); border: 1px solid rgba(0,0,0,0.6);
    box-shadow: inset 0 0 0 3px rgba(255,255,255,0.18), inset 0 0 6px rgba(0,0,0,0.45); }
/* The locking screw/knob on top of the collar, so it clearly reads as a collar. */
.mp-run-collar::after { content: ""; position: absolute; left: 50%; top: -13px; transform: translateX(-50%);
    width: 11px; height: 15px; border-radius: 3px 3px 2px 2px;
    background: linear-gradient(180deg, #e2e6ec, #7d848f); border: 1px solid rgba(0,0,0,0.6);
    box-shadow: inset 0 1px 0 rgba(255,255,255,0.5); }
/* Each plate: weight centred, optional count for the biggest plate printed lower down (under the weight).
   §5.6: colour comes from the .mp-plate-ink-light/-dark class the C# side adds (PlateAppearance.InkCssClass) —
   this rule no longer hardcodes white, so the count text (which used to force its own #fff) and the weight label
   both inherit whichever ink the CONFIGURED plate colour actually needs. */
.mp-run-plate { position: relative; flex: 0 0 auto; display: flex; align-items: center; justify-content: center;
    min-width: 40px; padding: 0 3px; border-radius: 4px; border: 1.5px solid rgba(230, 237, 243, 0.9);
    font-weight: 800; line-height: 1; }
.mp-run-plate-wt { font-size: calc(16 * var(--mp-display-unit)); font-variant-numeric: tabular-nums; }
.mp-run-plate-count { position: absolute; left: 0; right: 0; bottom: 8px; text-align: center;
    font-size: 0.9rem; font-weight: 900; font-variant-numeric: tabular-nums; }
/* display-board-typography §5.2 fixes both tokens explicitly: the bar weight (54) now reads slightly larger than
   the lifter's name (44) — an intentional flip from the old fixed 2.85rem/2.6rem pair, because the weight is the
   number a loader is scanning for first. Truncates with an ellipsis instead of wrapping/overlapping the timer,
   attempt buttons, or status content on the right (mp-run-head-left already has min-width:0 so this flex child is
   free to shrink below its content width). */
.mp-run-name { font-size: calc(44 * var(--mp-display-unit)); font-weight: 900; line-height: 1.1; max-width: 100%;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.mp-run-sub { display: flex; gap: 0.5rem; align-items: baseline; flex-wrap: wrap; }
.mp-run-kg { font-size: 1.4rem; font-weight: 900; color: var(--mp-accent); }
.mp-run-meta { font-size: 0.9rem; margin-top: 0.1rem; }
.mp-run-head-right { display: flex; gap: 0.5rem; align-items: center; flex-wrap: wrap; justify-content: flex-end; }
.mp-btn.mp-run-good { background: var(--mp-good); color: #fff; font-size: 1.05rem; padding: 0.5rem 1.1rem; }
.mp-btn.mp-run-nolift { background: var(--mp-nolift); color: #fff; font-size: 1.05rem; padding: 0.5rem 1.1rem; }
/* Attempt countdown shown in line with the header; turns red and holds at 00 when time runs out. */
.mp-run-timer { font-variant-numeric: tabular-nums; font-weight: 800; font-size: 1.6rem; min-width: 2.4ch;
    text-align: center; color: var(--mp-accent); }
.mp-run-timer:empty { display: none; }
.mp-run-timer.expired { color: var(--mp-nolift); }
/* Next-two lifters under the bar, each a modestly larger card: identity on row 1, attempt weight on row 2, and a
   plate-loading column on the right spanning both rows. */
.mp-run-next { display: flex; flex-direction: column; gap: 0.5rem; background: var(--mp-surface);
    border: 1px solid var(--mp-border); border-radius: 10px; padding: 0.6rem 0.8rem; }
/* 2-row/2-col grid: left column (minmax(0,1fr)) holds identity (row 1) then weight (row 2); the right column is a
   reserved plate-loading lane, widened from the original 10.5–11rem (display-board-typography §5.3/§5.4: it now
   also has to fit a labelled "Rack n" pill above the plates, and §5.5's chips carry text instead of being bare
   colour swatches) sized for the widest realistic GROUPED loadout without clipping, and spans both rows via the
   named "plates" area so the pill + plate row can be vertically centred as one block across the card's full
   height. Empty plate data still renders inside this area (see markup), so the column's reserved width never
   collapses and the left text never jumps.

   The lane's MAX came back from 13rem to 12.5rem (200px): measured at the largest offered text size (150%) the
   widest thing it ever has to hold is the chip row at 186px (25 ×3 + 5 + 2.5 + 1.25 — the worst grouped loadout a
   20 kg bar with 2.5 kg collars produces) and the "RACK 15 / 7" pill at 182px, so 200px still clears both by
   ~14px while returning the difference to the starved identity track. Both the min and the max are still fixed
   lengths, so the lane is width-identical on a card with a rack pill and one without (§5.4). */
.mp-run-next-item { display: grid; grid-template-columns: minmax(0, 1fr) minmax(12rem, 12.5rem);
    grid-template-areas: "identity plates" "weight plates"; column-gap: 0.75rem; row-gap: 0.2rem;
    align-items: center; min-height: 5.75rem; padding: 0.35rem 0.1rem; }
.mp-run-next-item + .mp-run-next-item { border-top: 1px solid var(--mp-border); }
/* 0.45rem rather than 0.55: the two gaps here (tag→name, name→PB/record badges) are pure spacing, and at 150% the
   name needed every pixel of the identity track to render "Oliver Thompson" without an ellipsis. */
.mp-run-next-line1 { grid-area: identity; display: flex; align-items: baseline; gap: 0.45rem; min-width: 0; }
.mp-run-next-wt { grid-area: weight; justify-self: start; font-size: calc(29 * var(--mp-display-unit)); font-weight: 900;
    color: var(--mp-accent); font-variant-numeric: tabular-nums; }
.mp-run-next-tag { font-size: calc(13 * var(--mp-display-unit)); font-weight: 800; text-transform: uppercase;
    letter-spacing: 0.05em; color: var(--mp-muted); min-width: 3.2rem; }
.mp-run-next-name { font-size: calc(25 * var(--mp-display-unit)); font-weight: 800; color: var(--mp-text);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Plate-loading column: the "Rack n" pill (§5.4, when present) stacked above the plate-chip row (§5.5) — a column
   flex, not the old single row, so the pill sits directly above the stack instead of interleaved with it. The grid
   area already spans both rows (the card's full height); justify-content:center here vertically centres this whole
   block within that spanned height. align-items:flex-start keeps both the pill and the chip row anchored to the
   same left edge regardless of which is present. */
.mp-run-next-plates { grid-area: plates; align-self: stretch; display: flex; flex-direction: column;
    align-items: flex-start; justify-content: center; gap: 0.3rem; min-width: 0; }
/* §5.4: the pill only ever appears above the plate row (never inline with it, never in place of it) — a squat/bench
   attempt with no plates yet declared can still show a rack pill on its own. */
.mp-run-next-rack { display: inline-flex; align-items: baseline; gap: 0.3rem; padding: 0.05rem 0.4rem;
    border: 1px solid var(--mp-accent); border-radius: 5px;
    background: color-mix(in srgb, var(--mp-accent) 16%, transparent); }
.mp-run-next-rack-label { font-size: calc(13 * var(--mp-display-unit)); font-weight: 800; text-transform: uppercase;
    letter-spacing: 0.05em; color: var(--mp-muted); }
.mp-run-next-rack-value { font-size: calc(22 * var(--mp-display-unit)); font-weight: 900; color: var(--mp-text);
    font-variant-numeric: tabular-nums; }
/* The plate-chip row itself: proportional, colour-matched, colour-coded AND labelled chips (see .mp-run-next-plate
   below), wrapping at chip boundaries only if a narrower supported viewport truly needs it — chip height itself
   never shrinks to fit. */
.mp-run-next-plate-row { display: flex; align-items: center; justify-content: flex-start; gap: 3px; flex-wrap: wrap; }
/* §5.5: ONE chip per distinct denomination (PlateGrouping.Group already collapsed repeats into a ×N count) — no
   longer a bare colour swatch. width:auto + the C# side's inline min-width (a plain px floor, not display-unit —
   panel geometry stays resolution-driven per the §4.1 rule at the top of this file) means a larger font-scale
   setting simply grows the box via its own text instead of clipping against a fixed pixel width.

   The HEIGHT needed the same treatment and did not have it. The inline "height:N%" the Razor emits is a fraction
   of the chip ROW's height, and that row height is itself only as tall as the biggest chip's own text — so every
   denomination below the biggest was sized SHORTER than the label it contains. Measured at 1920x1080/100% before
   this rule: the 1.25 chip had 9px of content box for a 15px line box (scrollHeight 15 vs clientHeight 9), 2.5 had
   11 vs 16, 5 had 14 vs 18 — the labels painted straight over the chip's own border, which is the "the small chip's
   text spills out of its box" defect. min-height:fit-content makes the proportional percentage a FLOOR rather than
   a cap: a chip is never shorter than its own label (+ its ×N count line), while denominations with room to spare
   keep the proportional height that makes a 25 read visibly bigger than a 10. Type is untouched (§5.2). The 1px
   vertical padding is the same idea — a chip sized exactly to its glyph box reads as clipped even when it isn't,
   and the label's line box is fractional (1.1 x 22.5px = 24.75px at the 150% setting) so a zero-slack box still
   reports a rounded-up overflow. 2px of vertical padding absorbs both. */
.mp-run-next-plate { flex: 0 0 auto; display: flex; flex-direction: column; align-items: center; justify-content: center;
    width: auto; box-sizing: border-box; min-height: fit-content; padding: 2px 4px; border-radius: 3px;
    border: 1px solid rgba(230, 237, 243, 0.7); font-weight: 800; line-height: 1.1; }
.mp-run-next-plate-wt { font-size: calc(15 * var(--mp-display-unit)); font-variant-numeric: tabular-nums; }
.mp-run-next-plate-count { font-size: calc(11 * var(--mp-display-unit)); opacity: 0.92; font-variant-numeric: tabular-nums; }
.mp-run-next-plates-empty { font-size: 1rem; }
.mp-flight-select {
    width: auto; padding: 0.45rem 0.6rem; font-size: 0.9rem; border-radius: 8px;
    background: var(--mp-bg); color: var(--mp-text); border: 1px solid var(--mp-border);
}
.mp-flight-select:hover { border-color: color-mix(in srgb, var(--mp-accent) 45%, var(--mp-border)); }
.mp-flight-select:focus { outline: none; border-color: var(--mp-accent); box-shadow: 0 0 0 2px color-mix(in srgb, var(--mp-accent) 25%, transparent); }

/* display-board-typography §5.5: the run-sheet grid body scales with the Text size control too — scoped under
   .mp-runboard (not the bare .mp-board-table this file's "Meet-day boards" section defines, which Scoreboard.razor
   also renders through and must NOT pick up --mp-display-unit sizing meant for the run board's own control) so
   only RunMeet's own table is affected. Headers stay a step smaller than the body, same relative relationship the
   original 0.35rem/0.55rem padding-only rule implied without ever setting an explicit header size. */
.mp-runboard .mp-board-table td { font-size: calc(17 * var(--mp-display-unit)); }
.mp-runboard .mp-board-table th { font-size: calc(14 * var(--mp-display-unit)); }

/* ============================================================================================================
   RP WP5 §6: run-board PB/national-record attempt-indicator badges + tri-state Indicators popover.
   RunMeet.razor is static SSR (no InteractiveServer circuit), so — unlike Scoreboard.razor.css's WP4 rules, which
   filter badges SERVER-SIDE before they ever reach the DOM — every badge here always renders, and run-board.js
   toggles "hide-pb"/"hide-record" classes on the .mp-runboard root to apply the effective tri-state filter
   entirely client-side (instant, no page reload). Visual language (icon/short-text/status colour) intentionally
   mirrors Scoreboard.razor.css's .mp-sb-annot rules so the two boards read as one system.
   ============================================================================================================ */

/* §6.1 effective filtering: hides only the matching KIND — PB/record badges everywhere on the board, including the
   current-lifter prominent callout (mp-rb-pb/mp-rb-record double as both the styling AND the hide-toggle marker,
   same convention as the reference mock's .hide-pb .badge.pb rule). */
.mp-runboard.hide-pb .mp-rb-pb { display: none !important; }
.mp-runboard.hide-record .mp-rb-record { display: none !important; }
/* The multi-record secondary line ("N eligible records · …") is record-only supplementary text, not a badge —
   still respects the Records toggle so it never contradicts a hidden record badge. */
.mp-runboard.hide-record .mp-rb-record-fact { display: none !important; }

/* §6.3 compact per-cell/card badges — rendered on the value's OWN text line (never on a line beneath it) so a badged
   cell is never taller than its badge-less neighbours and grid rows keep their natural height. Mirrors
   Scoreboard.razor.css's .mp-sb-annot-stack rule, including the three things that rule depends on: display:inline
   (an atomic inline box establishes its own line box even when empty, which grew annotated rows by a full line),
   white-space:nowrap on the cells that carry a badge so a badge can never be pushed to a second line, and icon-only
   badges in the narrow grid cells (the type word stays in title/aria-label). */
.mp-rb-annot-stack {
    display: inline;
}
/* Next/Then card variant: the cards have room for the full "★PB"/"▲NR" wording, so only the cell badges go icon-only
   (see .mp-rb-annot-label below); this variant just needs a slightly wider gap from the lifter name. */
.mp-rb-annot-stack-inline { margin-left: 0.2rem; }

/* Only cells that really carry a badge opt out of wrapping — every other cell keeps its normal wrapping and height.
   The displayed value is a block by default (.mp-cell-val above, so the in-cell editor can replace it in place), and a
   block always ends its line — badges after it could never share it. In badge-bearing cells only, the value goes inline
   so the badges land beside it; .mp-cell-edit stays a block, so the editor still opens on its own line underneath.
   :not(.editing) matters: this selector outranks ".mp-edit-cell.editing .mp-cell-val { display: none }", so without it
   an open editor would show its old value alongside the input. */
.mp-runboard td:has(.mp-rb-annot) { white-space: nowrap; }
.mp-runboard td:has(.mp-rb-annot):not(.editing) .mp-cell-val { display: inline; }

.mp-rb-annot {
    display: inline-flex; align-items: center; gap: 0.15rem; margin-left: 0.2rem; padding: 0 0.3rem;
    border: 1px solid currentColor; border-radius: 999px; font-size: 0.6rem; font-weight: 900; letter-spacing: 0.04em;
    text-transform: uppercase; line-height: 1.55; white-space: nowrap; vertical-align: middle;
}

/* Icon-only inside the dense grid cells; the Next/Then cards and the prominent current-lifter callout keep the word. */
.mp-runboard td .mp-rb-annot-label {
    position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap;
}
/* Kind: PB (star) vs national record (triangle) — distinct hues/icons/text, never colour alone (§10). */
.mp-rb-annot.mp-rb-pb { color: var(--mp-accent, #eab308); }
.mp-rb-annot.mp-rb-record { color: #b57bff; }
/* Status shading layered on top of the kind colour. */
.mp-rb-annot.mp-rb-annot-ratified { background: color-mix(in srgb, var(--mp-good, #16a34a) 20%, transparent); }
.mp-rb-annot.mp-rb-annot-pending { background: color-mix(in srgb, currentColor 15%, transparent); }
.mp-rb-annot.mp-rb-annot-failed { color: var(--mp-muted, #9ca3af); opacity: 0.7; text-decoration: line-through; }
.mp-rb-annot.mp-rb-annot-superseded { color: var(--mp-muted, #9ca3af); opacity: 0.7; }

/* §6.2 current-lifter prominent callout: a larger variant of the same badge language, plus the threshold/secondary
   text lines beneath the name. */
.mp-run-name-row { display: flex; align-items: center; gap: 0.6rem; flex-wrap: wrap; }
.mp-rb-annot-large { font-size: 0.78rem; padding: 0.2rem 0.55rem; border-radius: 7px; }
.mp-run-ind-secondary, .mp-run-ind-threshold { font-size: 0.85rem; margin-top: 0.1rem; }

/* §6.1 tri-state Indicators popover — plain JS/data-attribute toggling (run-board.js), CSS layout mirrors
   Scoreboard.razor.css's WP4 .mp-ind-popover positioning for visual consistency between the two toolbars. */
/* display-board-typography: the Text size control (.mp-scale-wrap / .mp-scale-popover) is a SEPARATE control that
   happens to want the same anchored-popover geometry, so it is listed alongside here rather than reusing the
   Indicators classes. It briefly did reuse them, and that is a trap worth naming: ".mp-ind-wrap" means "the
   Indicators control", and several UI tests locate that control as `.mp-ind-wrap > button` — a second control
   wearing the class turned every one of those into a strict-mode violation. Shared LOOK, separate NAME. */
.mp-ind-wrap, .mp-scale-wrap { position: relative; display: inline-flex; }
.mp-ind-popover, .mp-scale-popover {
    position: absolute; right: 0; top: calc(100% + 6px); z-index: 40; width: min(22rem, 90vw);
    margin-bottom: 0; box-shadow: 0 14px 38px rgba(0, 0, 0, 0.45);
}
.mp-ind-popover[hidden], .mp-scale-popover[hidden] { display: none; }
.mp-ind-row { display: grid; grid-template-columns: 7rem 1fr; align-items: center; gap: 0.5rem; margin-top: 0.6rem; }
.mp-ind-row > span { font-size: 0.8rem; font-weight: 700; }
.mp-ind-popover .mp-segmented { width: 100%; }
.mp-ind-popover .mp-segmented button { flex: 1; justify-content: center; }
@media (max-width: 650px) {
    .mp-ind-popover, .mp-scale-popover { position: fixed; left: 0.75rem; right: 0.75rem; top: 4.5rem; width: auto; }
}
/* §6.4: the Indicators control lives inside .mp-board-head, already hidden by the existing
   .mp-runboard.present .mp-board-head rule above — badges (outside mp-board-head) stay visible. */

/* Stacked per-division values (Division / Points / Place) — one line per division a lifter is entered in. */
.mp-stack { white-space: nowrap; vertical-align: top; }
.mp-stack div { line-height: 1.25; }
.mp-stack div + div { border-top: 1px dotted var(--mp-border); }

/* Platform / loading display (huge, chromeless). */
.mp-display { min-height: 100vh; display: flex; flex-direction: column; gap: 1.5rem; padding: 2rem 2.5rem; background: var(--mp-bg); color: var(--mp-text); }
.mp-display-top { display: flex; justify-content: space-between; align-items: baseline; }
.mp-display-name { font-size: 5rem; font-weight: 900; line-height: 1; letter-spacing: -0.02em; }
.mp-display-weight { font-size: 9rem; font-weight: 900; color: var(--mp-accent); line-height: 1; }
.mp-display-sub { font-size: 1.6rem; color: var(--mp-muted); }
.mp-display-next { font-size: 2rem; }
.mp-display-flash { position: fixed; inset: 0; display: flex; align-items: center; justify-content: center; font-size: 10rem; font-weight: 900; z-index: 1100; }
.mp-display-flash.good { background: var(--mp-good); color: #fff; }
.mp-display-flash.nolift { background: var(--mp-nolift); color: #fff; }
.mp-plate-bar { display: flex; align-items: center; justify-content: center; gap: 3px; margin: 1rem 0; }
.mp-plate { display: inline-block; border-radius: 3px; border: 1px solid rgba(0,0,0,0.5); }
.mp-plate-axle { width: 120px; height: 12px; background: #9ca3af; border-radius: 6px; }

/* ---- Platform display (LiftingCast-style: one-side bar + flight mini-scoreboard) ---- */
.mp-pf-grid { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.05fr); gap: 1.75rem; align-items: start; }
.mp-pf-head { display: flex; justify-content: space-between; align-items: flex-end; gap: 1rem; }
.mp-pf-name { font-size: 3.6rem; font-weight: 900; line-height: 1; letter-spacing: -0.02em; }
.mp-pf-weight { font-size: 7rem; font-weight: 900; color: var(--mp-accent); line-height: 0.9; white-space: nowrap; }
.mp-pf-kg { font-size: 2.2rem; margin-left: 0.4rem; color: var(--mp-muted); }
.mp-onebar { display: flex; align-items: flex-end; gap: 4px; min-height: 150px; margin: 0.75rem 0 0.25rem; padding-left: 0.25rem; }
.mp-onebar-collar { width: 18px; height: 64px; background: #9ca3af; border-radius: 3px; align-self: center; }
/* display-board-typography §5.6/§5.7: colour comes from the .mp-plate-ink-light/-dark class the C# side now adds
   (PlateAppearance.InkCssClass) — no longer a hardcoded white, so a pale configured colour (silver/white/light
   yellow) gets dark ink here exactly like the run board's plates. The bare-element rule keeps NO default text
   colour at all (the ink class is unconditionally added by PlateBig, so one always applies); PlatformDisplay has no
   --mp-display-unit (that block only covers .mp-runboard/.mp-sb — see the top of this file), so this size stays a
   plain rem token. */
.mp-plate-big { display: flex; align-items: center; justify-content: center; min-width: 46px; border-radius: 4px;
    border: 1px solid rgba(0,0,0,0.55); font-weight: 900; font-size: 1.5rem; }
/* §5.5/§5.7: one labelled chip per distinct denomination (PlateGrouping.Group), not a bare colour swatch — the
   platform display has no --mp-display-unit token (plain rem here, same reason as .mp-plate-big above), sized to
   stay legible at the platform's normal viewing distance without the run board's operator-controlled scale. */
.mp-minibar { display: inline-flex; align-items: center; gap: 3px; }
.mp-pf-mini-plate { display: inline-flex; flex-direction: column; align-items: center; justify-content: center;
    width: auto; min-width: 1.6rem; box-sizing: border-box; padding: 0 0.2rem; border-radius: 3px;
    border: 1px solid rgba(0,0,0,0.5); font-weight: 800; line-height: 1.1; }
.mp-pf-mini-plate-wt { font-size: 0.72rem; font-variant-numeric: tabular-nums; }
.mp-pf-mini-plate-count { font-size: 0.6rem; opacity: 0.9; font-variant-numeric: tabular-nums; }
.mp-pf-next { width: 100%; margin-top: 1rem; font-size: 1.4rem; }
.mp-pf-next th { text-align: left; color: var(--mp-muted); font-size: 1rem; text-transform: uppercase; letter-spacing: 0.04em; }
.mp-pf-next td, .mp-pf-next th { padding: 0.45rem 0.6rem; border-bottom: 1px solid var(--mp-border); }
/* §5.7: a modest legibility bump for the upcoming rack column — the "—" fallback semantics (Razor's own
   `?? "—"`) are untouched; this only changes how the value LOOKS once it's there. */
.mp-pf-next-rack { font-weight: 800; font-size: 1.05em; font-variant-numeric: tabular-nums; }
.mp-pf-board { width: 100%; font-size: 1.25rem; font-variant-numeric: tabular-nums; }
.mp-pf-board th { text-align: right; color: var(--mp-muted); font-size: 0.95rem; padding: 0.3rem 0.5rem; border-bottom: 2px solid var(--mp-border); }
.mp-pf-board th:first-child, .mp-pf-board td:first-child { text-align: left; }
.mp-pf-board td { text-align: right; padding: 0.32rem 0.5rem; border-bottom: 1px solid var(--mp-border); }
.mp-pf-lifter { font-weight: 700; }

/* ---- OBS overlay: detailed broadcast composition (WP6 §9.2/§9.3 — docs/specs/obs-overlay-mock.html is the
   authoritative visual reference: gold/dark panel system, top-left profile, top-centre decision lights, top-right
   up-next, 150px bottom banner). Panels stay permanently in the DOM (Overlay.razor never @if-removes one) and
   toggle a "collapsed"/"visible" class so the slide/collapse transitions below actually animate. ---- */
body:has(.mp-overlay-root) { background: transparent !important; overflow: hidden; }
.mp-overlay-root {
    position: fixed; inset: 0; overflow: hidden;
    color: var(--mp-text);
    font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
    /* §9.2 resolution support (720p/1080p/4K without cropping or tiny text): every px dimension below is expressed
       as calc(N * var(--s)) where N is the 1920×1080 design value in px and --s is the "scaled pixel" LENGTH unit
       (100vh/1080 — exactly 1px at 1080p; note number×length is the only valid calc multiplication, so the design
       value is written unitless). 1080p renders pixel-identical to the design, 4K exactly 2×, 720p ~0.667×, all
       proportionally from the viewport HEIGHT (aspect-safe: an ultrawide keeps 1080p-size panels rather than
       blowing them up off the canvas). */
    --s: calc(100vh / 1080);
    /* Typography WP3 §6.3: --sf is the TEXT unit, --s stays the GEOMETRY unit. --mp-ovl-font-scale is a plain
       decimal factor (0.80–1.50, default 1.00) set inline on this element by Overlay.razor from the OBS
       browser-source URL's fontScale/scale query params (see DisplayScale.ResolveOverlayFontScale) — a broadcaster
       who wants larger captions for a small preview window, or smaller text for a dense composition, adjusts ONLY
       what they read. If font-size stayed on --s, that request would also inflate every panel's width/height/
       padding/border-radius/gap — geometry that has nothing to do with legibility and would push panels off the
       16:9 canvas or overlap them (§6.4). Splitting the unit means every OTHER --s-based declaration below (widths,
       heights, padding, margins, gaps, border-radius, offsets, the referee-light diameter, the banner height,
       transition durations) is completely unaffected by fontScale — only rules that opt in via --sf grow or shrink.
       The `, 1` fallback keeps this token (and therefore every --sf-based font-size) safe even if the inline
       custom property is ever missing entirely (e.g. a stylesheet-only preview render), defaulting to 1x = --s. */
    --sf: calc(var(--s) * var(--mp-ovl-font-scale, 1));
    /* Derived panel tokens, computed from the theme's --mp-* vars (set inline on this element by Overlay.razor) so
       a theme's colours are the source of truth and the mock's gold/dark reads as the DEFAULT palette (its --mp-accent
       default is already the barbell gold above). */
    --ovl-panel: linear-gradient(145deg, color-mix(in srgb, var(--mp-surface) 94%, white 4%), color-mix(in srgb, var(--mp-bg) 90%, black 12%));
    --ovl-good-dark: color-mix(in srgb, var(--mp-good) 60%, black);
    --ovl-nolift-dark: color-mix(in srgb, var(--mp-nolift) 60%, black);
    --ovl-line: color-mix(in srgb, white 15%, transparent);
    --ovl-ease: cubic-bezier(.22, .75, .18, 1);
}

/* Shared floating-panel look for all four panels. */
.mp-ovl-profile, .mp-ovl-decision, .mp-ovl-next, .mp-ovl-banner {
    border: 1px solid color-mix(in srgb, var(--mp-accent) 75%, transparent);
    background: var(--ovl-panel);
    box-shadow: 0 16px 50px rgba(0,0,0,0.48), inset 0 0 0 1px rgba(255,255,255,0.035);
    backdrop-filter: blur(13px);
}

/* ---- Top-left: lifter profile — image + identity + OPL stats + latest-three history ---- */
.mp-ovl-profile {
    position: absolute; top: 3.2vh; left: 1.3vw;
    display: grid; grid-template-rows: minmax(0,1fr) auto;
    width: min(31vw, calc(575 * var(--s))); height: min(64vh, calc(650 * var(--s))); min-height: calc(590 * var(--s));
    overflow: hidden; border-radius: calc(12 * var(--s)); transform-origin: left center;
    /* No `width` in the transition list (the mock had it): the collapse animates via transform/opacity, and a width
       transition also fires on viewport-driven min()/var(--s) changes, where it can freeze at currentTime 0 in
       non-compositing contexts (hidden tabs / OBS preview) leaving the panel stuck at the previous viewport's width. */
    transition: transform 680ms var(--ovl-ease), opacity 420ms ease;
}
.mp-ovl-profile.collapsed { transform: translateX(calc(-100% - 2vw)) scaleX(0.74); opacity: 0; pointer-events: none; }
.mp-ovl-profile-inner { display: grid; grid-template-columns: 42% minmax(0,58%); width: 100%; min-height: 0; overflow: hidden; }
.mp-ovl-profile-image {
    position: relative; width: 100%; height: 100%; min-height: 0; overflow: hidden; isolation: isolate;
    background: radial-gradient(circle at 50% 20%, rgba(255,255,255,0.12), transparent 28%),
        linear-gradient(180deg, color-mix(in srgb, var(--mp-surface) 80%, white 6%), color-mix(in srgb, var(--mp-bg) 85%, black 15%));
}
.mp-ovl-profile-image img, .mp-ovl-profile-image .mp-ovl-silhouette { position: absolute; inset: 0; display: block; width: 100%; height: 100%; object-fit: cover; object-position: center top; }
.mp-ovl-profile-copy { min-width: 0; min-height: 0; padding: calc(24 * var(--s)) calc(22 * var(--s)) calc(18 * var(--s)); overflow: hidden; }
.mp-ovl-name-row { display: flex; align-items: center; gap: calc(10 * var(--s)); min-width: 0; }
.mp-ovl-athlete-name { min-width: 0; margin: 0; overflow: hidden; font-size: calc(32 * var(--sf)); line-height: 1; letter-spacing: 0.02em; text-overflow: ellipsis; text-transform: uppercase; white-space: nowrap; }
.mp-ovl-country { flex: 0 0 auto; color: var(--mp-muted); font-size: calc(16 * var(--sf)); font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em; white-space: nowrap; }
/* Typography WP3 §6.4: nowrap+ellipsis (not multi-line wrap) so a long gym/team/coach line never grows the profile
   panel taller and pushes the OPL stats/history below it out of view at 150% scale — a block-level div under a
   block container needs no extra min-width:0 for this to engage. */
.mp-ovl-team { margin: calc(9 * var(--s)) 0 calc(16 * var(--s)); overflow: hidden; color: var(--mp-accent); font-size: calc(15 * var(--sf)); font-weight: 750; letter-spacing: 0.07em; text-overflow: ellipsis; text-transform: uppercase; white-space: nowrap; }
/* Typography WP3 §6.4: the bio is explicitly LOWER-priority content (§6.4) — clamped to a fixed 3 LINES (not a
   fixed height/font-size) so it scales proportionally with --sf like everything else but can never grow past 3
   lines' worth of height and push the section-heading/stat-grid/history below it out of the panel, however long
   the lifter's bio text or however large fontScale is. -webkit-line-clamp is the only cross-engine way to clip at
   a line count rather than a pixel height (Chromium/OBS's embedded browser both support it despite the -webkit-
   prefix; there is no unprefixed equivalent with the same behaviour). */
.mp-ovl-bio {
    display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3; overflow: hidden;
    margin: 0 0 calc(16 * var(--s)); color: color-mix(in srgb, var(--mp-text) 88%, transparent); font-size: calc(15 * var(--sf)); line-height: 1.48;
}
.mp-ovl-section-heading { margin: calc(10 * var(--s)) 0 calc(8 * var(--s)); color: var(--mp-accent); font-size: calc(15 * var(--sf)); font-weight: 850; letter-spacing: 0.08em; line-height: 1.2; text-transform: uppercase; }
.mp-ovl-stat-grid { display: grid; grid-template-columns: minmax(0,1fr) auto; gap: calc(7 * var(--s)) calc(14 * var(--s)); padding-top: calc(11 * var(--s)); border-top: 1px solid var(--ovl-line); color: var(--mp-muted); font-size: calc(13 * var(--sf)); line-height: 1.15; text-transform: uppercase; }
.mp-ovl-stat-grid strong { color: var(--mp-text); text-align: right; white-space: nowrap; }
.mp-ovl-history { min-height: calc(150 * var(--s)); padding: calc(11 * var(--s)) calc(14 * var(--s)) calc(13 * var(--s)); overflow: hidden; border-top: 1px solid var(--ovl-line); background: rgba(0,0,0,0.25); }
.mp-ovl-history .mp-ovl-section-heading { margin-top: 0; }
.mp-ovl-history-table { display: grid; grid-template-columns: minmax(calc(90 * var(--s)),1.6fr) 0.6fr repeat(5, 0.62fr); gap: calc(6 * var(--s)); align-items: center; color: color-mix(in srgb, var(--mp-text) 90%, transparent); font-size: calc(12 * var(--sf)); line-height: 1.2; margin-bottom: calc(6 * var(--s)); }
.mp-ovl-history-table span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mp-ovl-history-table.header { color: var(--mp-muted); text-transform: uppercase; }
.mp-ovl-history-empty { color: var(--mp-muted); font-size: calc(12.5 * var(--sf)); padding-top: calc(5 * var(--s)); }

/* ---- Top-centre: temporary referee-decision panel — visible only during DecisionHold ---- */
.mp-ovl-decision {
    position: absolute; top: 3.5vh; left: 50%;
    width: min(32vw, calc(560 * var(--s))); padding: calc(22 * var(--s)) calc(28 * var(--s));
    border-radius: calc(11 * var(--s)); text-align: center; opacity: 0; pointer-events: none;
    transform: translateX(-50%) translateY(-14px) scale(0.96);
    transition: transform 430ms var(--ovl-ease), opacity 430ms ease;
}
.mp-ovl-decision.visible { opacity: 1; transform: translateX(-50%) translateY(0) scale(1); }
.mp-ovl-decision-lift { margin-bottom: calc(10 * var(--s)); font-size: calc(28 * var(--sf)); font-weight: 850; letter-spacing: 0.08em; text-transform: uppercase; }
.mp-ovl-lights { display: flex; justify-content: center; gap: calc(38 * var(--s)); margin: calc(6 * var(--s)) 0 calc(12 * var(--s)); }
.mp-ovl-light { width: calc(95 * var(--s)); aspect-ratio: 1; border-radius: 50%; background: #fff;
    box-shadow: 0 0 0 3px rgba(255,255,255,0.22), 0 0 26px rgba(255,255,255,0.75), inset 0 -8px 16px rgba(0,0,0,0.2); }
.mp-ovl-light.nolift {
    background: var(--mp-nolift);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--mp-nolift) 25%, transparent), 0 0 29px color-mix(in srgb, var(--mp-nolift) 78%, transparent), inset 0 -8px 16px rgba(70,0,0,0.38);
}
.mp-ovl-light.empty { background: color-mix(in srgb, var(--mp-text) 12%, transparent); box-shadow: none; opacity: 0.4; }
.mp-ovl-decision-text {
    display: inline-flex; align-items: center; justify-content: center; min-width: calc(220 * var(--s)); padding: calc(7 * var(--s)) calc(18 * var(--s));
    border: 1px solid var(--mp-accent); border-radius: calc(7 * var(--s)); color: var(--mp-accent); background: rgba(0,0,0,0.78);
    font-size: calc(27 * var(--sf)); font-weight: 900; letter-spacing: 0.06em; text-transform: uppercase;
}
.mp-ovl-decision-text.bad { color: #ff727b; border-color: #ff5561; }

/* ---- Top-right: up-next panel — default five from the authoritative run order ---- */
.mp-ovl-next {
    position: absolute; top: 3.4vh; right: 1.3vw;
    width: min(27vw, calc(480 * var(--s))); max-height: calc(540 * var(--s)); overflow: hidden; border-radius: calc(16 * var(--s));
    transform-origin: top right;
    /* No `max-height` in the transition list (the mock had it): the collapse reads as scaleY+opacity, and a
       max-height transition also fires on viewport-driven var(--s) changes, where it can freeze at currentTime 0
       in non-compositing contexts and clip the panel at the previous viewport's cap. */
    transition: transform 620ms var(--ovl-ease), opacity 350ms ease;
}
.mp-ovl-next.collapsed { max-height: calc(42 * var(--s)); opacity: 0; pointer-events: none; transform: translateY(-18px) scaleY(0.08); }
.mp-ovl-next-head { display: flex; align-items: center; justify-content: space-between; padding: calc(13 * var(--s)) calc(17 * var(--s)); border-bottom: 1px solid var(--ovl-line);
    font-size: calc(19 * var(--sf)); font-weight: 850; letter-spacing: 0.04em; text-transform: uppercase; }
.mp-ovl-next-row { display: grid; grid-template-columns: calc(28 * var(--s)) 1fr auto; gap: calc(11 * var(--s)); align-items: center; min-height: calc(65 * var(--s)); padding: calc(8 * var(--s)) calc(14 * var(--s)); border-bottom: 1px solid rgba(255,255,255,0.1); }
.mp-ovl-next-row:last-child { border-bottom: 0; }
.mp-ovl-next-number { color: color-mix(in srgb, var(--mp-text) 90%, transparent); font-size: calc(15 * var(--sf)); font-weight: 750; }
/* Typography WP3 §6.4: min-width:0 on the grid item is required for the name/meta ellipsis rules below to actually
   engage — .mp-ovl-next-row is a CSS grid with this wrapper in the `1fr` middle column, and a grid item's default
   min-width is `auto` (its content's min-content size), which at 150% scale is wide enough for a long lifter name
   to push the attempt badge in the `auto` third column right out to (or past) the panel's edge instead of letting
   the name itself ellipsise. */
.mp-ovl-next-copy { min-width: 0; }
.mp-ovl-next-name { overflow: hidden; font-size: calc(17 * var(--sf)); font-weight: 720; text-overflow: ellipsis; white-space: nowrap; }
.mp-ovl-next-meta { overflow: hidden; margin-top: calc(2 * var(--s)); color: var(--mp-muted); font-size: calc(12 * var(--sf)); text-overflow: ellipsis; text-transform: uppercase; white-space: nowrap; }
.mp-ovl-next-attempt span { display: inline-block; min-width: calc(64 * var(--s)); padding: calc(6 * var(--s)) calc(9 * var(--s)); border-radius: calc(5 * var(--s)); background: color-mix(in srgb, var(--mp-surface) 70%, black 15%);
    font-size: calc(14 * var(--sf)); font-weight: 760; text-align: center; }
.mp-ovl-next-attempt .entered { background: var(--ovl-good-dark); }
.mp-ovl-next-empty { padding: calc(14 * var(--s)); color: var(--mp-muted); font-size: calc(13 * var(--sf)); text-align: center; text-transform: uppercase; }

/* ---- Bottom: information banner (150px at the 1080p design canvas, --s-scaled) — persistent except while every
   panel is mid-transition ---- */
.mp-ovl-banner {
    position: absolute; left: 1.25vw; right: 1.25vw; bottom: 3.25vh;
    display: grid; grid-template-columns: 1.15fr 0.75fr 0.83fr 1.65fr 1.05fr;
    height: calc(150 * var(--s)); overflow: hidden; border-radius: calc(14 * var(--s)); transform-origin: left center;
    clip-path: inset(0 0 0 0 round calc(14 * var(--s)));
    transition: transform 680ms var(--ovl-ease), opacity 360ms ease, clip-path 680ms var(--ovl-ease);
}
.mp-ovl-banner.collapsed-left { opacity: 0; pointer-events: none; transform: scaleX(0.02); clip-path: inset(0 98% 0 0 round calc(14 * var(--s))); }
.mp-ovl-banner-section { display: flex; flex-direction: column; justify-content: center; min-width: 0; min-height: 0; padding: calc(10 * var(--s)) calc(12 * var(--s)); overflow: hidden; border-right: 1px solid rgba(255,255,255,0.13); }
.mp-ovl-banner-section:last-child { border-right: 0; }
.mp-ovl-identity { display: grid; grid-template-columns: calc(62 * var(--s)) minmax(0,1fr); gap: calc(11 * var(--s)); align-items: center; min-height: 0; }
.mp-ovl-avatar {
    position: relative; width: calc(62 * var(--s)); height: calc(92 * var(--s)); overflow: hidden; border: 1px solid rgba(255,255,255,0.19); border-radius: calc(8 * var(--s));
    background: linear-gradient(color-mix(in srgb, var(--mp-surface) 80%, white 6%), color-mix(in srgb, var(--mp-bg) 85%, black 15%));
}
.mp-ovl-avatar img, .mp-ovl-avatar .mp-ovl-silhouette { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; display: block; }
/* Typography WP3 §6.4: same min-width:0-on-the-grid-item fix as .mp-ovl-next-copy — .mp-ovl-identity is a CSS grid
   with this wrapper filling the minmax(0,1fr) second column, so without an explicit min-width:0 the wrapper (and
   the name/team ellipsis rules inside it) would refuse to shrink below content width at 150% scale. */
.mp-ovl-identity-copy { min-width: 0; }
.mp-ovl-identity-name { overflow: hidden; font-size: calc(21 * var(--sf)); font-weight: 880; line-height: 1; text-overflow: ellipsis; text-transform: uppercase; white-space: nowrap; }
.mp-ovl-identity-team { overflow: hidden; margin-top: calc(7 * var(--s)); color: var(--mp-accent); font-size: calc(11 * var(--sf)); font-weight: 800; letter-spacing: 0.05em; line-height: 1.25; text-overflow: ellipsis; text-transform: uppercase; white-space: nowrap; }
.mp-ovl-compact-stats { display: grid; grid-template-columns: 1fr auto; gap: calc(6 * var(--s)) calc(9 * var(--s)); color: var(--mp-muted); font-size: calc(11 * var(--sf)); line-height: 1.1; text-transform: uppercase; }
.mp-ovl-compact-stats strong { color: var(--mp-text); text-align: right; white-space: nowrap; }
.mp-ovl-attempt-heading, .mp-ovl-placing-heading { flex: 0 0 auto; margin-bottom: calc(4 * var(--s)); color: var(--mp-accent); font-size: calc(11 * var(--sf)); font-weight: 850; letter-spacing: 0.07em; line-height: 1.1; text-align: center; text-transform: uppercase; }
.mp-ovl-best-lifts { display: grid; grid-template-columns: repeat(4,1fr); overflow: hidden; border: 1px solid color-mix(in srgb, var(--mp-accent) 25%, transparent); border-radius: calc(8 * var(--s)); }
.mp-ovl-best-lifts div { padding: calc(8 * var(--s)) calc(4 * var(--s)); text-align: center; border-right: 1px solid rgba(255,255,255,0.12); }
.mp-ovl-best-lifts div:last-child { border-right: 0; }
.mp-ovl-best-lifts small { display: block; margin-bottom: calc(4 * var(--s)); color: var(--mp-accent); font-size: calc(9 * var(--sf)); text-transform: uppercase; }
.mp-ovl-best-lifts strong { font-size: calc(14 * var(--sf)); }
.mp-ovl-attempt-wrap { position: relative; justify-content: flex-start; gap: 0; }
/* RP WP6 §7.1/§7.2: the dedicated attempt callout. The kicker (lift/attempt/weight) always renders; the PB and
   record badge lines are ALWAYS in the DOM at a fixed reserved size (mp-ovl-callout-empty only flips visibility),
   so toggling the meet's indicator defaults or an annotation appearing/disappearing never changes this block's
   height and never moves the attempt cells below it or the banner sections beside it (§7.2 no-layout-jump). */
.mp-ovl-callout-kicker { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.mp-ovl-callout-badges { display: flex; flex-direction: column; align-items: flex-start; gap: calc(3 * var(--s)); margin: calc(4 * var(--s)) 0 calc(6 * var(--s)); }
.mp-ovl-callout-badge {
    display: flex; align-items: center; max-width: 100%; min-height: calc(19 * var(--s)); padding: 0 calc(8 * var(--s));
    overflow: hidden; border: 1px solid currentColor; border-radius: 999px; font-size: calc(10.5 * var(--sf));
    font-weight: 900; letter-spacing: 0.04em; line-height: 1; text-overflow: ellipsis; text-transform: uppercase; white-space: nowrap;
}
/* Reserves the same box (visibility, not removal — §7.2) so a disabled/absent kind leaves no visible trace. */
.mp-ovl-callout-badge.mp-ovl-callout-empty { visibility: hidden; }
/* Kind colour (never colour alone — §10; both lines always carry full "PB"/"NATIONAL RECORD" text too) — same
   palette as Scoreboard.razor.css/RunMeet.razor's .mp-sb-annot/.mp-rb-annot rules, so every surface reads as one
   system. */
.mp-ovl-callout-badge.mp-ovl-callout-pb { color: var(--mp-accent); }
.mp-ovl-callout-badge.mp-ovl-callout-record { color: #b57bff; }
/* Status shading layered on top of the kind colour — order matters: these come AFTER the kind rules above so a
   failed/superseded annotation always mutes regardless of kind (mirrors the board CSS's cascade order). */
.mp-ovl-callout-badge.mp-ovl-callout-ratified { background: color-mix(in srgb, var(--mp-good) 22%, transparent); }
.mp-ovl-callout-badge.mp-ovl-callout-pending { background: color-mix(in srgb, currentColor 16%, transparent); }
.mp-ovl-callout-badge.mp-ovl-callout-failed { color: var(--mp-muted); opacity: 0.72; text-decoration: line-through; }
.mp-ovl-callout-badge.mp-ovl-callout-superseded { color: var(--mp-muted); opacity: 0.72; }
.mp-ovl-attempts { display: grid; grid-template-columns: repeat(3, minmax(0,1fr)); flex: 1 1 auto; gap: calc(7 * var(--s)); min-height: 0; overflow: hidden; }
.mp-ovl-attempt {
    position: relative; display: flex; flex-direction: column; align-items: center; justify-content: center; min-width: 0; min-height: 0; overflow: hidden;
    border: 1px solid rgba(255,255,255,0.14); border-radius: calc(7 * var(--s)); background: color-mix(in srgb, var(--mp-surface) 75%, black 15%);
}
.mp-ovl-attempt.good { background: linear-gradient(145deg, var(--mp-good), var(--ovl-good-dark)); }
.mp-ovl-attempt.bad { background: linear-gradient(145deg, var(--mp-nolift), var(--ovl-nolift-dark)); }
.mp-ovl-attempt.current { border-color: var(--mp-accent); background: rgba(17,20,23,0.96); box-shadow: inset 0 0 20px color-mix(in srgb, var(--mp-accent) 6%, transparent); }
.mp-ovl-attempt small { display: block; max-width: 95%; margin-bottom: calc(3 * var(--s)); overflow: hidden; color: color-mix(in srgb, var(--mp-text) 92%, transparent); font-size: calc(9 * var(--sf)); font-weight: 850; line-height: 1.05; text-align: center; text-overflow: ellipsis; text-transform: uppercase; white-space: nowrap; }
.mp-ovl-attempt strong { font-size: calc(26 * var(--sf)); line-height: 1; }
.mp-ovl-attempt.bad::after { content: ""; position: absolute; width: 135%; height: calc(3 * var(--s)); background: rgba(255,255,255,0.72); transform: rotate(-27deg); }
.mp-ovl-placing {
    display: grid; grid-template-columns: minmax(0,1fr) calc(22 * var(--s)) minmax(0,1fr); flex: 1 1 auto; align-items: center; min-height: 0; overflow: hidden;
    border: 1px solid color-mix(in srgb, var(--mp-accent) 28%, transparent); border-radius: calc(8 * var(--s)); background: rgba(0,0,0,0.22);
}
.mp-ovl-place-card { min-width: 0; text-align: center; }
.mp-ovl-place-card small { display: block; margin-bottom: calc(3 * var(--s)); overflow: hidden; color: color-mix(in srgb, var(--mp-text) 88%, transparent); font-size: calc(9 * var(--sf)); line-height: 1.05; text-overflow: ellipsis; text-transform: uppercase; white-space: nowrap; }
.mp-ovl-place-card strong { font-size: calc(30 * var(--sf)); line-height: 1; white-space: nowrap; }
.mp-ovl-place-card.forecast strong { color: var(--mp-accent); }
.mp-ovl-arrow { color: var(--mp-accent); font-size: calc(21 * var(--sf)); line-height: 1; text-align: center; }

@media (max-aspect-ratio: 16/10) {
    .mp-ovl-profile { width: 32vw; }
    .mp-ovl-next { width: 30vw; }
    .mp-ovl-banner { grid-template-columns: 1.05fr 0.72fr 0.82fr 1.62fr 1fr; }
}

/* Auto-save status indicator. */
.mp-autosave-status { font-size: 0.85rem; font-weight: 600; color: var(--mp-muted); }
.mp-autosave-status[data-state="saved"] { color: var(--mp-good); }
.mp-autosave-status[data-state="pending"] { color: var(--mp-accent); }

.mp-card {
    background: var(--mp-surface);
    border: 1px solid var(--mp-border);
    border-radius: 12px;
    padding: 1.25rem 1.4rem;
    margin-bottom: 1rem;
}
.mp-card h3 { margin-top: 0; }

/* min(100%, 280px) — not a bare 280px — so the track can shrink with its container: a hard 280px floor forces the
   grid wider than a .mp-card on a 320px viewport and pages the whole document sideways (seen on /enter's handler
   checkbox row). Same recipe as .mp-dash-grid/.mp-public-meet-grid. */
.mp-grid { display: grid; gap: 1rem; grid-template-columns: repeat(auto-fill, minmax(min(100%, 280px), 1fr)); }

/* ==== Setup tab professional redesign (WP2, docs/specs/setup-redesign/*) ====
   Everything below is scoped under .mp-setup-scope (the /manage?tab=setup root — see ManageMeet.razor) so the
   dark-control rewrite and the 12-col shell don't regress any other page. The three lower tools (EntryFormEditor /
   OplImportPanel / RecordBookPanel) render inside this scope too and already reuse .mp-card/.mp-setup-sec/
   .mp-setup-head/.mp-setup-grid/.mp-setup-check/.mp-setup-chips/.form-control — restyling those shared classes
   here restyles the tools consistently for free, without touching their internals (WP0 §2 rule 5). */

/* ---- Page header (SetupPageHeader.razor) — eyebrow + title + counts strip, replaces .mp-setup-overview ---- */
.mp-setup-pagehead {
    display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 1.5rem; align-items: center;
    margin: 0 0 1rem; padding: 1.1rem 1.2rem; border: 1px solid var(--mp-border); border-radius: 12px;
    background: linear-gradient(105deg, color-mix(in srgb, var(--mp-accent) 11%, transparent), transparent 42%), var(--mp-surface);
    box-shadow: 0 12px 28px rgba(0,0,0,0.17);
}
.mp-setup-pagehead-copy { min-width: 0; }
.mp-setup-eyebrow {
    display: block; margin-bottom: 0.25rem; color: var(--mp-accent); font-size: 0.68rem; font-weight: 800;
    letter-spacing: 0.09em; text-transform: uppercase;
}
.mp-setup-pagehead h2 { margin: 0; font-size: clamp(1.25rem, 1.8vw, 1.6rem); letter-spacing: -0.02em; }
.mp-setup-pagehead p { margin: 0.35rem 0 0; max-width: 48rem; color: var(--mp-muted); font-size: 0.85rem; }
.mp-setup-stats {
    display: grid; grid-template-columns: repeat(4, minmax(4.6rem, 1fr)); margin: 0; overflow: hidden;
    border: 1px solid var(--mp-border); border-radius: 9px; background: color-mix(in srgb, var(--mp-bg) 70%, transparent);
}
.mp-setup-stats div { min-width: 4.6rem; padding: 0.55rem 0.8rem; text-align: center; border-left: 1px solid var(--mp-border); }
.mp-setup-stats div:first-child { border-left: 0; }
.mp-setup-stats dt { color: var(--mp-muted); font-size: 0.62rem; font-weight: 750; letter-spacing: 0.05em; text-transform: uppercase; }
.mp-setup-stats dd { margin: 0.1rem 0 0; color: var(--mp-text); font-size: 1.05rem; font-weight: 850; font-variant-numeric: tabular-nums; }

/* ---- Explicit row layout (setup re-layout — replaces the retired 12-column .mp-setup-shell/.mp-setup-c8/
   .mp-setup-c6/.mp-setup-c4/.mp-setup-c4-stack/.mp-setup-c12 auto-flow grid). The old shell placed cards by a bare
   column SPAN and let sparse auto-placement decide what landed next to what — which is exactly what forced the old
   c4-stack wrapper (stacking Scoring & running rules under Registration & visibility inside one grid column) and
   still left a blank gutter under Schedule whenever that stacked column ran taller than Schedule itself. Each
   .mp-setup-row now names its own siblings explicitly (ManageMeet.razor's mp-setup-layout) — a pair, a trio, or (for
   the two variable-length full-width cards, Overalls and Competition catalogues) no row wrapper at all — so a row's
   membership is stated in markup, not inferred from column arithmetic.

   Equal card heights within a row come ONLY from the grid's own `align-items: stretch` (the default, restated
   below for clarity) plus `height: 100%` on the card itself — no fixed heights, no CSS masonry/multicolumn, no
   grid-auto-flow:dense, no absolute positioning, no JS measurement. A block-level card with height:100% simply
   fills its stretched grid cell, so its background/border/shadow reach the row's shared bottom edge even when its
   own content is shorter than its neighbour. */
.mp-setup-layout { display: grid; gap: 1rem; }
.mp-setup-row { display: grid; gap: 1rem; align-items: stretch; min-width: 0; }
.mp-setup-row--pair { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.mp-setup-row--trio { grid-template-columns: repeat(3, minmax(0, 1fr)); }
/* Every row's direct children ARE the section components' own root .mp-card element (Blazor renders a component's
   root markup straight into its parent's child list, with no wrapper element in between) — CommsSummaryCard's root
   carries .mp-card too (alongside its own .mp-comms-summary-card modifier), so this one selector reaches all three
   trio cards as well as both pair rows. */
.mp-setup-row > .mp-card { height: 100%; min-width: 0; }
/* .mp-card carries its own margin-bottom:1rem globally (kept for the many plain, non-setup .mp-card usages
   elsewhere in this codebase) — inside .mp-setup-layout the grid `gap` already owns ALL vertical spacing between
   rows and between the two full-width cards, so a card keeping its own margin here would double it. Scoped to
   exactly the two places a setup card can be a grid item (a bare row, or the layout's own direct child for the
   full-width cards) rather than a broad `.mp-setup-scope .mp-card`, so a .mp-card that might one day render INSIDE
   a section's own body content is never silently affected by this override. */
.mp-setup-layout > .mp-card,
.mp-setup-row > .mp-card { margin-bottom: 0; }

@media (max-width: 1179px) {
    /* Tablet and mobile always stack one card per row in DOM/keyboard order — never a cramped 50%/33% card
       (fable-spec §4.2/§4.3). height:100% is undone too: a natural-height card stacked above its row sibling must
       not stretch to match a taller one once they are no longer sharing a row baseline. */
    .mp-setup-row--pair, .mp-setup-row--trio { grid-template-columns: minmax(0, 1fr); }
    .mp-setup-row > .mp-card { height: auto; }
}

/* .mp-setup-wide: still used standalone (NOT inside the retired 12-col shell) as a full-width field span inside a
   card's own .mp-setup-grid (repeat(auto-fit, minmax(...,1fr))) — e.g. Meet name, the address lookup row, and
   EntryFormEditor's custom-field help/options rows. grid-column:1/-1 spans every implicit column regardless of how
   many the surrounding grid currently has, so it needed no change for the row-layout re-work. */
.mp-setup-wide { grid-column: 1 / -1; }

/* ---- Dark control base + full state coverage (fable-spec §6.2/§6.3) ----
   rest / hover / focus-visible / filled / placeholder / disabled / read-only / invalid, for text, number, select,
   password, search, colour inputs and the MultiSelectDropdown trigger. No input stays a harsh white box.
   Email notifications WP4 (WP0 §1.3: "new scope class .mp-comms-scope mirrors it") — every selector below also
   matches under .mp-comms-scope so Communications/Settings/Compose/Providers get the identical dark controls
   without a second, drifting copy of this block. */
.mp-setup-scope .form-control,
.mp-setup-scope .mp-multiselect > summary.msd-control,
.mp-comms-scope .form-control,
.mp-comms-scope .mp-multiselect > summary.msd-control {
    display: block; width: 100%; min-height: 2.35rem; padding: 0 0.65rem; color: var(--mp-text);
    background: var(--mp-control-bg); border: 1px solid var(--mp-control-border); border-radius: 7px;
    box-shadow: inset 0 1px 1px rgba(0,0,0,0.2); outline: none;
    transition: border-color .14s ease, background-color .14s ease, box-shadow .14s ease;
}
.mp-setup-scope input[type="color"].form-control, .mp-comms-scope input[type="color"].form-control { padding: 0.2rem; cursor: pointer; }
.mp-setup-scope .form-control::placeholder, .mp-comms-scope .form-control::placeholder { color: var(--mp-control-placeholder); opacity: 1; }
.mp-setup-scope .form-control:hover:not(:disabled):not([readonly]),
.mp-setup-scope .mp-multiselect > summary.msd-control:hover,
.mp-comms-scope .form-control:hover:not(:disabled):not([readonly]),
.mp-comms-scope .mp-multiselect > summary.msd-control:hover { background: var(--mp-control-bg-hover); border-color: #435164; }
.mp-setup-scope .form-control:focus-visible,
.mp-setup-scope .form-control:focus,
.mp-setup-scope .mp-multiselect[open] > summary.msd-control,
.mp-comms-scope .form-control:focus-visible,
.mp-comms-scope .form-control:focus,
.mp-comms-scope .mp-multiselect[open] > summary.msd-control {
    border-color: var(--mp-control-border-focus); background: #19212b;
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--mp-control-border-focus) 22%, transparent), inset 0 1px 1px rgba(0,0,0,0.2);
}
.mp-setup-scope .form-control:disabled, .mp-setup-scope .form-control[disabled],
.mp-comms-scope .form-control:disabled, .mp-comms-scope .form-control[disabled] {
    opacity: 0.55; cursor: not-allowed; background: color-mix(in srgb, var(--mp-control-bg) 65%, var(--mp-bg));
}
.mp-setup-scope .form-control[readonly], .mp-comms-scope .form-control[readonly] { background: transparent; border-style: dashed; color: var(--mp-muted); }
.mp-setup-scope .form-control.invalid, .mp-setup-scope .form-control[aria-invalid="true"],
.mp-comms-scope .form-control.invalid, .mp-comms-scope .form-control[aria-invalid="true"] {
    border-color: var(--mp-nolift);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--mp-nolift) 18%, transparent), inset 0 1px 1px rgba(0,0,0,0.2);
}
.mp-setup-scope .validation-message, .mp-comms-scope .validation-message { display: block; margin-top: 0.3rem; color: var(--mp-nolift); font-size: 0.78rem; font-weight: 700; }
.mp-setup-scope select.form-control, .mp-comms-scope select.form-control {
    appearance: none; -webkit-appearance: none;
    background-image: linear-gradient(45deg, transparent 50%, #7d8999 50%), linear-gradient(135deg, #7d8999 50%, transparent 50%);
    background-position: calc(100% - 15px) 52%, calc(100% - 10px) 52%; background-size: 4px 4px, 4px 4px; background-repeat: no-repeat;
    padding-right: 1.7rem;
}
.mp-setup-scope input[type="search"].form-control, .mp-comms-scope input[type="search"].form-control { padding-left: 2.1rem; }
.mp-setup-scope input[type="checkbox"], .mp-comms-scope input[type="checkbox"] { accent-color: var(--mp-accent); width: 15px; height: 15px; }
/* File inputs (OplImportPanel/RecordBookPanel CSV uploads — fable-spec §6.3/§9.4 explicitly names "file" in the
   required dark-control coverage list): the <input> box itself already picks up .form-control above, but the
   "Choose File" affordance is a distinct native pseudo-element that ignores the input's own background/border, so
   without this rule it stays a plain white OS button against the dark card — confirmed via the WP4 evidence
   captures. Both the standard and the WebKit/Blink-prefixed selector are needed (Chromium, which Playwright and
   most directors' browsers use, still only recognises the prefixed one). */
.mp-setup-scope input[type="file"].form-control { padding: 0.3rem 0.65rem; cursor: pointer; }
/* Kept as two separate rules deliberately, NOT a comma-separated group: a plain (non-:is()) selector list is
   invalidated as a whole if any browser doesn't recognise one of its selectors, so grouping the standard and the
   -webkit- form together silently dropped BOTH in Chromium (confirmed — the button rendered as a stock white OS
   control until this was split; Playwright/most directors run Chromium, which needs the prefixed selector). */
.mp-setup-scope input[type="file"].form-control::-webkit-file-upload-button {
    margin-right: 0.65rem; padding: 0.35rem 0.7rem; color: var(--mp-text); font: inherit; font-weight: 700;
    background: var(--mp-nested-surface); border: 1px solid var(--mp-control-border); border-radius: 6px; cursor: pointer;
    transition: background-color .14s ease, border-color .14s ease;
}
.mp-setup-scope input[type="file"].form-control::file-selector-button {
    margin-right: 0.65rem; padding: 0.35rem 0.7rem; color: var(--mp-text); font: inherit; font-weight: 700;
    background: var(--mp-nested-surface); border: 1px solid var(--mp-control-border); border-radius: 6px; cursor: pointer;
    transition: background-color .14s ease, border-color .14s ease;
}
.mp-setup-scope input[type="file"].form-control:hover::-webkit-file-upload-button { background: var(--mp-control-bg-hover); border-color: #435164; }
.mp-setup-scope input[type="file"].form-control:hover::file-selector-button { background: var(--mp-control-bg-hover); border-color: #435164; }

/* ---- Card shell + header (shared by the 8 new sections AND the 3 lower tools) ----
   WP4 (Overalls divisions-menu clipping fix): overflow:hidden used to live on the WHOLE card purely so its own
   top corners stayed rounded under the header's flush top edge — but that ALSO clipped any descendant that needs
   to paint outside the card's own box, like an open MultiSelectDropdown menu (.msd-menu, position:absolute inside
   .mp-multiselect — see ScoringRunningSection.razor's overalls divisions field). The corner clip now lives on
   .mp-setup-head alone (matching top border-radius + its own overflow:hidden) — the card's own background already
   follows its border-radius natively with no overflow rule needed, and every OTHER direct child is already inset
   by the .mp-setup-sec > * margin rule below, so nothing else ever touched the rounded corners in the first place
   (confirmed against every current .mp-setup-sec usage, including the header-less lower tools and Results.razor's
   plain h3+table cards). position:relative is the positioning context the .mp-setup-sec:has(.mp-multiselect[open])
   rule further down promotes with z-index while a menu is open. */
.mp-setup-sec {
    padding: 0; border-radius: 12px; position: relative;
    box-shadow: 0 12px 28px rgba(0,0,0,0.17);
}
.mp-setup-head {
    display: flex; align-items: flex-start; gap: 0.7rem; flex-wrap: wrap; margin: 0 0 0.9rem;
    padding: 1rem 1.1rem 0.75rem; border-bottom: 1px solid color-mix(in srgb, var(--mp-border) 85%, transparent);
    border-radius: 12px 12px 0 0; overflow: hidden;
}
.mp-setup-head::before {
    content: ""; align-self: stretch; width: 3px; min-height: 1.25rem; border-radius: 999px; background: var(--mp-accent);
}
.mp-setup-head h3 { margin: 0; font-size: 1rem; letter-spacing: -0.01em; }
.mp-setup-head .mp-muted { flex: 1 1 14rem; font-size: 0.78rem; line-height: 1.4; }
.mp-setup-card-icon {
    flex: 0 0 auto; width: 28px; height: 28px; display: grid; place-items: center; margin-top: -0.05rem;
    border: 1px solid #344150; border-radius: 8px; background: var(--mp-nested-surface); color: var(--mp-accent);
    font-size: 0.7rem; font-weight: 800;
}
.mp-setup-card-titles { min-width: 0; }
.mp-setup-card-titles h3 { margin: 0; font-size: 1rem; letter-spacing: -0.01em; }
.mp-setup-card-titles .mp-muted { display: block; margin-top: 0.15rem; font-size: 0.78rem; line-height: 1.4; }
/* Section bodies (everything after the header) get consistent side/bottom padding; the header owns its own
   top/side padding when present (my 8 new sections + EntryFormEditor). OplImportPanel/RecordBookPanel don't use
   .mp-setup-head at all (their own .mp-compact-row IS the first child) so the first-child rule gives them the
   top inset the old uniform `.mp-setup-sec { padding: 1rem 1.1rem }` used to provide. */
.mp-setup-sec > *:not(.mp-setup-head) { margin-left: 1.1rem; margin-right: 1.1rem; }
.mp-setup-sec > *:not(.mp-setup-head):first-child { margin-top: 1.1rem; }
.mp-setup-sec > *:last-child { margin-bottom: 1.1rem; }
.mp-setup-sec > .mp-setup-head + * { margin-top: 0; }

.mp-setup-grid {
    display: grid; gap: 0.7rem 0.8rem;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 175px), 1fr)); align-items: end;
}
.mp-setup-grid label.mp-muted { display: block; margin-bottom: 0.22rem; font-size: 0.72rem; font-weight: 700; letter-spacing: 0.015em; }
.mp-setup-sec h4 {
    margin: 0.9rem 0 0.4rem !important; color: var(--mp-muted); font-size: 0.7rem;
    font-weight: 800; letter-spacing: 0.055em; text-transform: uppercase;
}
.mp-setup-check {
    display: flex; align-items: center; gap: 0.5rem; min-height: 2.35rem; padding: 0.45rem 0.6rem;
    border: 1px solid var(--mp-control-border); border-radius: 8px; background: var(--mp-nested-surface); white-space: normal;
}
.mp-setup-check input { flex: 0 0 auto; }
.mp-setup-sec .mp-btn.danger[title^="Remove"] {
    display: inline-grid; place-items: center; flex: 0 0 2.35rem; width: 2.35rem; min-width: 2.35rem;
    height: 2.35rem; padding: 0; line-height: 1;
}
.mp-setup-divider { height: 1px; background: var(--mp-border); margin: 0.85rem 0; }
.mp-setup-subhead { font-size: 0.75rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em; margin-top: 0.4rem; color: var(--mp-muted); }
.mp-setup-addrow { display: flex; gap: 0.4rem; flex-wrap: wrap; align-items: center; }
.mp-setup-addrow .form-control { flex: 1 1 6rem; min-width: 5rem; }

/* ---- Toggle-switch rows (Public meet / self-registration / live+final results / attempt options) ----
   Still a real, keyboard-operable, labelled <input type=checkbox> — only its appearance changes to a pill switch. */
.mp-setup-toggle-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 0.55rem; }
.mp-setup-toggle {
    display: flex; align-items: center; justify-content: space-between; gap: 0.6rem; min-height: 2.65rem;
    padding: 0.5rem 0.65rem; border: 1px solid var(--mp-control-border); border-radius: 8px;
    background: var(--mp-nested-surface); cursor: pointer; font-size: 0.82rem; font-weight: 650;
}
.mp-setup-toggle input[type="checkbox"] {
    appearance: none; -webkit-appearance: none; flex: 0 0 auto; width: 34px; height: 20px; margin: 0;
    border-radius: 999px; background: #293443; border: 1px solid #3b4859; position: relative; cursor: pointer;
    transition: background-color .15s ease, border-color .15s ease;
}
.mp-setup-toggle input[type="checkbox"]::after {
    content: ""; position: absolute; width: 14px; height: 14px; border-radius: 50%; background: #7c8999;
    left: 2px; top: 2px; transition: left .15s ease, background-color .15s ease;
}
.mp-setup-toggle input[type="checkbox"]:checked { background: rgba(240,185,77,.25); border-color: #a87a28; }
.mp-setup-toggle input[type="checkbox"]:checked::after { left: 16px; background: var(--mp-accent); }
.mp-setup-toggle input[type="checkbox"]:focus-visible { outline: 2px solid var(--mp-control-border-focus); outline-offset: 2px; }
.mp-setup-toggle input[type="checkbox"]:disabled { opacity: 0.5; cursor: not-allowed; }

/* ---- Attempt indicators (AttemptIndicatorsSection.razor — PB/record spec §4) ----
   .mp-ai-rule reuses .mp-setup-toggle's switch look (same selector above styles its checkbox) but stacks the two
   rows in one column and allows a wrapping help line under each label, which the 2-up .mp-setup-toggle-grid has no
   room for. The summary pills' live text (§4.1 "updates immediately") is pure CSS: each .mp-ai-eff holds four
   spans, and exactly one is shown depending on the two switches' :checked state — no JS, no interactive render
   mode, matching this static-SSR page (same ":has()"-driven-visibility technique as .mp-cf-panel above). */
.mp-ai-rules { display: flex; flex-direction: column; gap: 0.5rem; }
.mp-ai-rule { align-items: flex-start; }
.mp-ai-rule-text { display: flex; flex-direction: column; gap: 0.2rem; padding-right: 0.5rem; }
.mp-ai-rule-text strong { font-size: 0.85rem; font-weight: 650; }
.mp-ai-rule-text small { font-size: 0.74rem; font-weight: 400; line-height: 1.35; color: var(--mp-muted); }
.mp-ai-rule input[type="checkbox"] { margin-top: 0.2rem; }

.mp-ai-summary-row { display: flex; flex-wrap: wrap; gap: 0.4rem; margin-top: 0.85rem; }
.mp-ai-pill {
    display: inline-flex; align-items: center; gap: 0.25rem; width: max-content; max-width: 100%;
    padding: 0.2rem 0.6rem; border-radius: 999px; font-size: 0.76rem; font-weight: 500;
    background: var(--mp-nested-surface); border: 1px solid var(--mp-border); color: var(--mp-muted);
}
.mp-ai-pill .mp-ai-eff { color: var(--mp-text); font-weight: 700; }
.mp-ai-eff span { display: none; }
.mp-ai-card:has(#ai-pb-switch:checked):has(#ai-record-switch:checked) .mp-ai-eff .mp-ai-both { display: inline; }
.mp-ai-card:has(#ai-pb-switch:checked):has(#ai-record-switch:not(:checked)) .mp-ai-eff .mp-ai-pbonly { display: inline; }
.mp-ai-card:has(#ai-pb-switch:not(:checked)):has(#ai-record-switch:checked) .mp-ai-eff .mp-ai-nronly { display: inline; }
.mp-ai-card:has(#ai-pb-switch:not(:checked)):has(#ai-record-switch:not(:checked)) .mp-ai-eff .mp-ai-none { display: inline; }

.mp-ai-notice {
    background: color-mix(in srgb, var(--mp-info) 14%, var(--mp-surface)); border: 1px solid var(--mp-info);
    border-radius: 8px; padding: 0.6rem 0.9rem; font-size: 0.85rem; margin-top: 0.6rem;
}

/* ---- Schedule & structure (ScheduleStructureSection.razor) — compact 50%-width card layout ----
   Setup re-layout: this card now renders at half the setup width instead of the old 8/12 span, so its interior
   needs its OWN local breakpoint rather than reacting to the page viewport — a container query on a wrapper INSIDE
   the card (deliberately not on .mp-setup-sec itself: that element is the positioning context the unrelated
   .mp-setup-sec:has(.mp-multiselect[open]) z-index rule promotes, and giving it its own containment context too
   would complicate that rule for no benefit here). Below ~560px of the card's OWN content width the Days/Platforms
   panels stack; at or above it they sit side by side (fable-spec §3.3/§4.4). */
.mp-setup-inventory-cq { container-type: inline-size; container-name: mp-setup-inventory; }
.mp-setup-inventory-grid { display: grid; gap: 0.6rem; grid-template-columns: 1fr; }
@container mp-setup-inventory (min-width: 560px) {
    .mp-setup-inventory-grid { grid-template-columns: 1fr 1fr; }
}
.mp-setup-mini-panel { border: 1px solid var(--mp-border); border-radius: 9px; background: var(--mp-nested-surface); overflow: hidden; }
.mp-setup-mini-head { margin: 0; padding: 0.55rem 0.65rem; color: var(--mp-muted); border-bottom: 1px solid var(--mp-border); font-size: 0.68rem; font-weight: 760; text-transform: uppercase; letter-spacing: 0.05em; }
.mp-setup-mini-list { list-style: none; margin: 0; padding: 0.35rem; }
.mp-setup-mini-list li { display: flex; gap: 0.4rem; align-items: center; padding: 0.2rem 0.2rem; }
.mp-setup-mini-addrow { display: flex; gap: 0.4rem; padding: 0.5rem; border-top: 1px solid var(--mp-border); }

/* ---- Per-day sessions/flights disclosure (fable-spec §3.3/§4.4) — one native <details> per day replaces the old
   flat "Sessions & flights" panel that used to list every day at once, which is exactly the shape that produced a
   tall Schedule card with a large empty gutter beside it once the card shrank to 50% width. The first day (by
   Order) renders open server-side; later days start collapsed but still show "N sessions · N flights" in their
   summary, so their content is knowable without opening them (fable-spec §5 large-profile requirement). Purely
   native open/close — no JS, and nothing here transitions, so prefers-reduced-motion needs no extra rule. */
.mp-setup-schedule-days { display: grid; gap: 0.5rem; margin-top: 0.7rem; }
.mp-setup-day { border: 1px solid var(--mp-border); border-radius: 9px; background: var(--mp-nested-surface); overflow: hidden; }
.mp-setup-day > summary {
    display: flex; align-items: center; justify-content: space-between; gap: 0.6rem; list-style: none;
    padding: 0.6rem 0.65rem; cursor: pointer; font-size: 0.82rem; font-weight: 700;
}
.mp-setup-day > summary::-webkit-details-marker { display: none; }
.mp-setup-day > summary::after { content: "▾"; flex: 0 0 auto; color: var(--mp-muted); font-size: 0.7rem; }
.mp-setup-day[open] > summary::after { content: "▴"; }
.mp-setup-day[open] > summary { border-bottom: 1px solid var(--mp-border); }
.mp-setup-day-counts { color: var(--mp-muted); font-size: 0.72rem; font-weight: 600; white-space: nowrap; }
.mp-setup-day-body { padding: 0.55rem 0.65rem 0.6rem; }
.mp-setup-flight-pill { display: inline-flex; gap: 0.2rem; align-items: center; }

/* ---- Competition catalogues (CompetitionCataloguesSection.razor) — 4-cell grid per the mock ---- */
/* align-items:start (grid default is stretch): with real content, "Weight classes" is reliably taller than the
   other three catalogues (sex-segmented lists + a 3-field add-row vs. their single-field add-rows) — stretching
   every card to match turned Age divisions/Equipment/Events into mostly-empty boxes (confirmed in the 1440x1000
   evidence capture). Letting each catalogue size to its own content removes that dead space. */
.mp-setup-catalog-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 0.65rem; align-items: start; }
.mp-setup-catalog {
    min-height: 7rem; padding: 0.7rem 0.75rem; border: 1px solid var(--mp-border); border-radius: 9px;
    background: linear-gradient(160deg, rgba(255,255,255,0.018), transparent 44%), var(--mp-nested-surface);
}
.mp-setup-catalog-top { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; margin-bottom: 0.5rem; }
.mp-setup-catalog-top b { font-size: 0.82rem; }
.mp-setup-catalog-top .mp-muted { font-size: 0.72rem; }
.mp-setup-catalog .mp-setup-subhead:first-of-type { margin-top: 0; }
@media (max-width: 1099px) { .mp-setup-catalog-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 560px) { .mp-setup-catalog-grid { grid-template-columns: 1fr; } }

/* ---- Overall add-form: name and divisions each take a fixed half — the divisions box grows in height (chips
   wrap) as more are chosen, without either box changing width. ---- */
.mp-setup-overalls { display: flex; flex-direction: column; gap: 0.7rem; margin-top: 0.5rem; }
.mp-setup-overall-row { display: flex; flex-direction: column; gap: 0.35rem; }
.mp-ov-namerow { display: grid; grid-template-columns: 1fr 1fr; gap: 0.5rem; align-items: start; }
.mp-ov-namerow > .form-control { width: 100%; min-width: 0; }
.mp-ov-namerow > .mp-multiselect { width: 100%; min-width: 0; }

/* WP4: Formula / Age coefficient / Grouping (Split by sex) / Remove / Add share one >=38px control baseline.
   Root cause was two-fold: (1) .mp-setup-addrow's shared align-items:center vertically CENTRES children instead
   of bottom-aligning them, so a short bare control floats mid-row against a taller labelled <div><label/><select/>
   </div> sibling instead of sharing its bottom edge; (2) the checkbox had no label-above at all, unlike Formula/
   Age coefficient. .mp-setup-addrow itself is untouched (the catalogue add-rows and schedule add-forms that also
   use it are already uniform-height, bare-control rows and already look correct centred) — .mp-ov-addrow is a
   scoped modifier applied ONLY to the overalls row, so this fix can't regress those. flex-end bottom-aligns every
   child regardless of its own height; wrapping "Split by sex" in the same label-above-control shape as Formula/
   Age coefficient (see ScoringRunningSection.razor) makes the three fields structurally identical, and Remove/Add
   get an explicit 38px floor so a short bare button can't float above the shared baseline either. row-gap covers
   the 2-columns-then-1 reflow as flex-wrap drops items to new lines at narrow widths. */
.mp-ov-addrow { align-items: flex-end; row-gap: 0.5rem; }
.mp-ov-addrow > div { flex: 1 1 6.5rem; min-width: 5.75rem; }
.mp-ov-addrow .form-control, .mp-ov-addrow .mp-setup-check { min-height: 38px; }
.mp-ov-addrow > .mp-btn { min-height: 38px; flex: 0 0 auto; }
.mp-ov-addrow > .mp-btn.danger[title^="Remove"] { width: 38px; height: 38px; flex: 0 0 38px; }

/* ---- FU-D: per-row Eligibility disclosure (results handoff §5.3) — collapsed by default, native <details>, no
   JS required to open/close. Its own Events/Equipment MultiSelectDropdowns are each a SEPARATE <details
   class="mp-multiselect"> nested one level inside this one; that nesting needed no changes to the existing
   card-elevation z-index chain (.mp-setup-scope .mp-setup-sec:has(.mp-multiselect[open]) → .mp-multiselect[open]
   → .msd-menu, above) because :has() matches a descendant .mp-multiselect[open] at any depth, and .msd-menu
   positions itself relative to its own immediate .mp-multiselect ancestor, not this one. */
.mp-ov-eligibility { margin-top: 0.15rem; border: 1px solid var(--mp-control-border); border-radius: 8px; background: var(--mp-nested-surface); }
.mp-ov-eligibility > summary {
    list-style: none; cursor: pointer; display: flex; align-items: center; gap: 0.5rem;
    min-height: 38px; padding: 0 0.7rem; font-size: 0.78rem; font-weight: 700;
}
.mp-ov-eligibility > summary::-webkit-details-marker { display: none; }
.mp-ov-eligibility > summary::before { content: "▸"; font-size: 0.65rem; color: var(--mp-muted); transition: transform .15s ease; }
.mp-ov-eligibility[open] > summary::before { transform: rotate(90deg); }
.mp-ov-eligibility-hint { font-weight: 600; }
.mp-ov-eligibility-body { align-items: flex-end; row-gap: 0.5rem; padding: 0 0.7rem 0.7rem; }
.mp-ov-eligibility-body > div { flex: 1 1 9rem; min-width: 8.5rem; }
.mp-ov-eligibility-body .form-control, .mp-ov-eligibility-body .mp-multiselect { min-height: 38px; }
.mp-ov-eligibility-help { margin: 0 0.7rem 0.7rem; font-size: 0.72rem; }

/* ---- Per-award ranking rule ("Respect category placing order"). Deliberately NOT inside the Eligibility
   disclosure and not squeezed into the compact add-row: it changes what the published ladder MEANS, so its help
   text stays on screen where the director makes the choice. Same nested-surface treatment as the disclosure
   above so the row reads as part of the award, not as a page-level setting. */
.mp-ov-ranking { margin-top: 0.15rem; padding: 0.55rem 0.7rem; border: 1px solid var(--mp-control-border);
    border-radius: 8px; background: var(--mp-nested-surface); }
.mp-ov-ranking > .mp-setup-check { font-size: 0.78rem; font-weight: 700; }
.mp-ov-ranking-help { margin: 0.3rem 0 0; max-width: 62rem; font-size: 0.72rem; }

/* ---- Setup-tab multiselect menu: paints above its own card, the next card, and the sticky save bar ----
   .mp-setup-sec no longer clips its children (see the card-shell rule above) — this elevates ONLY the card that
   currently owns an open menu (:has()), so the normal/closed stacking order is untouched. manage-structure.js
   additionally promotes the open menu to position:fixed with viewport-clamped coordinates (flips upward near the
   bottom of a short viewport, clamps max-height so a long option list always scrolls internally instead of
   overflowing the screen) — these z-index rules are both the non-JS fallback AND what actually governs paint
   order either way, since the JS only ever changes position/top/left/width/max-height, never z-index. Reference
   stacking (fable mock): card-with-open-menu 160 -> open .mp-multiselect 180 -> .msd-menu 200, above the sticky
   save bar (.mp-savebar, z-index 60 in this codebase — either order of magnitude, 200 clears it). */
.mp-setup-scope .mp-setup-sec:has(.mp-multiselect[open]) { z-index: 160; }
.mp-setup-scope .mp-multiselect[open] { z-index: 180; }
.mp-setup-scope .msd-menu { z-index: 200; }

/* ---- Bars &amp; collars: one row per lift — bar name (wide) + empty-bar weight (narrow). ---- */
.mp-setup-bar-rows { display: flex; flex-direction: column; gap: 0.5rem; }
.mp-setup-bar-row { display: grid; grid-template-columns: 1fr 5.5rem; gap: 0.75rem; align-items: end; }
.mp-setup-bar-row label.mp-muted { display: block; font-size: 0.8rem; margin-bottom: 0.15rem; }
.mp-setup-bar-row-collar > div:first-child { min-height: 2.35rem; display: flex; align-items: end; }

/* ---- Plate inventory: dense 4-column grid, full 14-denomination catalogue (fable-spec §4.2 — no chips). ---- */
.mp-setup-plates { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 0.4rem; }
.mp-setup-plate-row {
    display: flex; align-items: center; gap: 0.45rem; padding: 0.4rem 0.5rem; cursor: pointer;
    border: 1px solid var(--mp-border); border-radius: 7px; background: var(--mp-nested-surface);
}
.mp-setup-plate-kg { flex: 1; font-variant-numeric: tabular-nums; font-size: 0.82rem; }
.mp-setup-plate-row input[type="checkbox"] { width: 15px; height: 15px; }
.mp-setup-plate-row input[type="color"] { width: 2rem; height: 1.45rem; padding: 0; border: 1px solid var(--mp-control-border); border-radius: 4px; background: none; }
@media (max-width: 1099px) { .mp-setup-plates { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (max-width: 560px) { .mp-setup-plates { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

/* ---- Address lookup: suggestion dropdown anchored under the search input. ---- */
.mp-addr-wrap { position: relative; }
.mp-addr-wrap label.mp-muted { display: flex; justify-content: space-between; gap: 0.5rem; }
.mp-addr-results { position: absolute; left: 0; right: 0; top: 100%; z-index: 60; background: var(--mp-surface);
    border: 1px solid var(--mp-border); border-radius: 8px; margin-top: 2px; overflow: hidden;
    box-shadow: 0 8px 24px rgba(0,0,0,0.45); }
.mp-addr-item { display: block; width: 100%; text-align: left; background: none; border: 0; color: var(--mp-text);
    padding: 0.45rem 0.7rem; font-size: 0.85rem; cursor: pointer; border-bottom: 1px solid var(--mp-border); }
.mp-addr-item:last-child { border-bottom: 0; }
.mp-addr-item:hover { background: color-mix(in srgb, var(--mp-accent) 14%, var(--mp-surface)); }

.mp-setup-h2 { margin: 1.25rem 0 0.25rem; }
.mp-setup-chips { display: flex; flex-wrap: wrap; gap: 0.3rem; margin: 0.3rem 0; }
.mp-setup-chip { display: inline-flex; align-items: center; gap: 0.3rem; background: var(--mp-bg);
    border: 1px solid var(--mp-border); border-radius: 999px; padding: 0.15rem 0.35rem 0.15rem 0.6rem; font-size: 0.85rem; }
/* The chip's remove button — quiet until hovered, then reads as destructive. */
.mp-chip-x { background: none; border: 0; color: var(--mp-muted); font-size: 1rem; line-height: 1;
    padding: 0 0.15rem; cursor: pointer; border-radius: 999px; }
.mp-chip-x:hover { color: #fff; background: var(--mp-nolift); }

/* ---- Sticky save bar (SetupSaveBar.razor visuals; EditForm shell stays on ManageMeet.razor) ----
   Fixed to the viewport bottom per the mock; .mp-setup-scope reserves bottom padding (see responsive tiers below)
   so it never covers the last section's controls. */
.mp-savebar {
    position: fixed; z-index: 60; left: 50%; bottom: 1.1rem; transform: translateX(-50%);
    width: min(1768px, calc(100% - 3.5rem)); display: flex; align-items: center; justify-content: space-between;
    gap: 0.75rem; padding: 0.65rem 0.75rem 0.65rem 1rem;
    background: color-mix(in srgb, var(--mp-surface) 94%, transparent); backdrop-filter: blur(14px);
    border: 1px solid var(--mp-control-border); border-radius: 11px;
    box-shadow: 0 20px 50px rgba(0,0,0,0.45);
}
.mp-savebar-note { visibility: hidden; display: flex; align-items: center; gap: 0.5rem; margin-right: auto; font-size: 0.8rem; font-weight: 650; }
.mp-savebar-note.show { visibility: visible; color: #d3b673; }
.mp-savebar-note.show::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: var(--mp-accent); flex: 0 0 auto; }
/* Custom unsaved-changes dialog. */
.mp-dirty-dialog { background: var(--mp-surface); color: var(--mp-text); border: 1px solid var(--mp-border);
    border-radius: 12px; padding: 1.25rem 1.4rem; max-width: 26rem; }
.mp-dirty-dialog::backdrop { background: rgba(0, 0, 0, 0.55); }

/* ---- Responsive tiers (fable-spec §6.5, row layout re-work per §4) ----
   >=2400: the shell/page already stretch (no max-width cap on .mp-container) — no extra rule needed.
   1180-2399: the explicit pair/trio rows above render at full width — two/three equal-height cards per row.
   768-1179: every row collapses to one column, in DOM order (no cramped 50%/33% cards); sub-grids (catalogue,
     toggle-grid, plates, the Schedule card's own days/platforms container-query pair) stay multi-up where they fit.
   <768: one column, 44px touch targets, no page-level horizontal scroll. */
.mp-setup-scope { padding-bottom: 5.5rem; }
/* >=2400px (fable-spec §6.5) used to cap this column at 2100px so single-line text fields wouldn't stretch to a
   fraction of a 3840px viewport. meets-ui fable-spec §6.1 supersedes that: no page-level surface cap is allowed
   anywhere, including here, so the setup column now stretches full-width with .mp-container (which itself has
   no max-width) at every viewport, including 4K. */
.mp-setup-scope { width: 100%; max-width: none; }
/* The old 1100-1599px "c8/c4 both collapse to span 12" tier is retired along with the shell it patched — the
   explicit .mp-setup-row--pair/--trio rows above already collapse cleanly in one place (max-width:1179px), so this
   tier's entire job (working around c4 cards never landing next to each other in DOM order) no longer exists. */
@media (max-width: 1099px) {
    .mp-setup-pagehead { grid-template-columns: 1fr; gap: 0.9rem; }
    .mp-setup-stats { width: 100%; }
}
@media (max-width: 767px) {
    .mp-setup-pagehead { padding: 1rem; }
    .mp-setup-stats { grid-template-columns: repeat(2, 1fr); }
    .mp-setup-stats div:nth-child(odd) { border-left: 0; }
    .mp-setup-stats div:nth-child(n+3) { border-top: 1px solid var(--mp-border); }
    .mp-setup-toggle-grid { grid-template-columns: 1fr; }
    .mp-setup-plates { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .mp-setup-scope .form-control,
    .mp-setup-scope .mp-btn,
    .mp-setup-scope input[type="checkbox"]:not(.mp-setup-toggle input),
    .mp-setup-scope .mp-setup-plate-row { min-height: 44px; }
    .mp-savebar { width: calc(100% - 1.5rem); flex-wrap: wrap; }
}

.mp-muted { color: var(--mp-muted); }
.mp-hero { padding: 3rem 0 2rem; }
.mp-hero h1 { font-size: 2.5rem; font-weight: 800; letter-spacing: -0.03em; }
.mp-hero p { color: var(--mp-muted); font-size: 1.15rem; max-width: 640px; }

/* display:inline-flex + width:max-content (rather than plain inline-block) plus an explicit white-space:nowrap
   (meets-ui fable-spec §5.6) guarantees .mp-badge.live can never break into two lines inside a narrow composite
   header track, without resorting to an oversized fixed width. */
.mp-badge {
    display: inline-flex; align-items: center; width: max-content; max-width: 100%; white-space: nowrap;
    padding: 0.15rem 0.6rem; border-radius: 999px;
    font-size: 0.75rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em;
    background: var(--mp-surface-2); color: var(--mp-muted); border: 1px solid var(--mp-border);
}
.mp-badge.good { color: var(--mp-good); border-color: var(--mp-good); }
.mp-badge.nolift { color: var(--mp-nolift); border-color: var(--mp-nolift); }
.mp-badge.live { color: var(--mp-accent); border-color: var(--mp-accent); }

.mp-btn {
    display: inline-block; padding: 0.55rem 1.1rem; border-radius: 8px; font-weight: 700;
    background: var(--mp-accent); color: #1a1300; text-decoration: none; border: none; cursor: pointer;
}
.mp-btn.secondary { background: var(--mp-surface-2); color: var(--mp-text); border: 1px solid var(--mp-border); }
.mp-btn.danger { background: var(--mp-surface-2); color: var(--mp-nolift); border: 1px solid var(--mp-border); font-weight: 800; }
.mp-btn.danger:hover { background: var(--mp-nolift); color: #fff; border-color: var(--mp-nolift); }
.mp-btn.ghost { background: transparent; color: var(--mp-text); border: 1px solid transparent; font-weight: 600; }
.mp-btn.ghost:hover { border-color: var(--mp-border); }
.mp-btn:disabled { opacity: 0.45; cursor: default; }

table.mp-table { width: 100%; border-collapse: collapse; }
.mp-table th, .mp-table td { padding: 0.6rem 0.8rem; text-align: left; border-bottom: 1px solid var(--mp-border); }
.mp-table th { color: var(--mp-muted); font-size: 0.8rem; text-transform: uppercase; letter-spacing: 0.04em; }

/* Referee light pips */
.mp-lights { display: inline-flex; gap: 0.4rem; }
.mp-light { width: 22px; height: 22px; border-radius: 50%; border: 2px solid #000; }
.mp-light.white { background: #f5f5f5; }
.mp-light.red { background: var(--mp-nolift); }
.mp-light.yellow { background: #f5c518; }
.mp-light.blue { background: #2563eb; }
.mp-light.off { background: #2a2a2a; }

/* Referee-light picker buttons (colour the button when its light is selected). */
.mp-light-btn {
    border: 1px solid var(--mp-border); border-radius: 6px; padding: 0.3rem 0.55rem; cursor: pointer;
    font-weight: 700; font-size: 0.8rem; background: var(--mp-surface-2); color: var(--mp-text);
}
.mp-light-btn.selected[data-light="White"] { background: #f5f5f5; color: #111; border-color: #f5f5f5; }
.mp-light-btn.selected[data-light="Red"] { background: var(--mp-nolift); color: #fff; border-color: var(--mp-nolift); }
.mp-light-btn.selected[data-light="Yellow"] { background: #f5c518; color: #111; border-color: #f5c518; }
.mp-light-btn.selected[data-light="Blue"] { background: #2563eb; color: #fff; border-color: #2563eb; }

/* Theme tab — live board previews (scoreboard / run board / overlay) rendered in scaled-down iframes. */
.mp-theme-previews {
    display: grid; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); gap: 1rem; margin-top: 0.5rem;
}
.mp-theme-preview-label { color: var(--mp-muted); font-size: 0.8rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em; margin-bottom: 0.35rem; }
.mp-theme-preview {
    position: relative; border: 1px solid var(--mp-border); border-radius: 10px; overflow: hidden;
    aspect-ratio: 16 / 9; background: #000;
}
.mp-theme-preview iframe {
    position: absolute; top: 0; left: 0; width: 400%; height: 400%; border: 0;
    transform: scale(0.25); transform-origin: 0 0; pointer-events: none;
}

/* Column-resize grips on grid headers. */
.mp-table thead th { position: relative; }
/* Border-box so a pinned column width is exact (no padding/border drift → no jump on first resize). */
.mp-table th, .mp-table td { box-sizing: border-box; }
.mp-col-grip { position: absolute; top: 0; right: 0; width: 7px; height: 100%; cursor: col-resize; user-select: none; touch-action: none; }
.mp-col-grip:hover { background: var(--mp-accent); opacity: 0.6; }
body.mp-col-resizing { cursor: col-resize; user-select: none; }

/* Big display screens */
.mp-screen { background: #000; color: #fff; min-height: 100vh; padding: 2rem; }
.mp-screen .current-lifter { font-size: 4rem; font-weight: 800; }
.mp-screen .attempt-weight { font-size: 6rem; font-weight: 900; color: var(--mp-accent); }

/* Livestream overlay: transparent background for OBS browser source */
.mp-overlay { background: transparent; color: #fff; padding: 1rem 1.5rem; }
.mp-overlay .lower-third {
    display: inline-block; background: rgba(0,0,0,0.75); border-left: 5px solid var(--mp-accent);
    padding: 0.75rem 1.25rem; border-radius: 6px;
}

/* ==== Director UI redesign (docs/specs/director-ui-spec.md) ====
   Shared primitives (visually-hidden text, an overflow disclosure, a status-dot) used by both the dashboard and
   the manage-console Overview, plus the two screens' own layout classes. Reuses --mp-* tokens and the existing
   .mp-card/.mp-btn/.mp-badge/.mp-linkbtn system throughout — no second styling framework (§4). */
.mp-sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden;
    clip: rect(0,0,0,0); white-space: nowrap; border: 0; }
/* Alias used by the profile/equipment components (WP6 BLOCK-2: the name previously existed only as scoped CSS
   inside ProfileImageUpload, so legends/live-regions elsewhere rendered visibly). Keep both names global. */
.mp-visually-hidden { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden;
    clip: rect(0,0,0,0); white-space: nowrap; border: 0; }

.mp-eyebrow { color: var(--mp-accent); text-transform: uppercase; letter-spacing: 0.1em; font-size: 0.72rem; font-weight: 800; }

/* Generic <details>/<summary> disclosure for "quiet" secondary actions (Export, More actions, card overflow) —
   keyboard-operable natively, no JS required to open/close (§4.3). */
.mp-overflow { position: relative; display: inline-block; }
.mp-overflow summary { list-style: none; cursor: pointer; }
.mp-overflow summary::-webkit-details-marker { display: none; }
.mp-overflow-menu { position: absolute; right: 0; top: calc(100% + 4px); z-index: 30; min-width: 12rem;
    display: flex; flex-direction: column; background: var(--mp-surface); border: 1px solid var(--mp-border-strong, var(--mp-border));
    border-radius: 8px; padding: 0.35rem; box-shadow: 0 10px 28px rgba(0,0,0,0.4); }
.mp-overflow-menu a, .mp-overflow-menu .mp-linkbtn { display: block; width: 100%; text-align: left; padding: 0.4rem 0.55rem;
    border-radius: 6px; color: var(--mp-text); text-decoration: none; font-size: 0.85rem; font-weight: 600; }
.mp-overflow-menu a:hover, .mp-overflow-menu .mp-linkbtn:hover { background: var(--mp-surface-2); }
.mp-overflow-menu form, .mp-overflow-menu .mp-linkbtn { margin: 0; }
.mp-danger-text.mp-linkbtn { color: var(--mp-nolift); }
.mp-icon-btn { width: 2.3rem; padding: 0 !important; }

/* ---- Meet Director dashboard (§5) ----
   meets-ui fable-spec §6.1: .mp-page-header/.mp-dash-toolbar/.mp-dash-empty/.mp-dash-noresults/.mp-dash-grid no
   longer carry a max-width:1760px page-level cap — they stretch to .mp-container's own edges (width:100%) at
   every viewport, including 4K, leaving no dead gutter. Intentional readability caps (page-header p's 46rem
   measure, the search control's own max-width) are unaffected. */
.mp-page-header { display: flex; align-items: flex-end; justify-content: space-between; gap: 1.25rem;
    flex-wrap: wrap; width: 100%; max-width: none; margin: 0 0 1.25rem; }
.mp-page-header h1 { margin: 0.2rem 0 0.35rem; font-size: clamp(1.7rem, 2.6vw, 2.4rem); letter-spacing: -0.02em; }
.mp-page-header p { max-width: 46rem; }
.mp-dash-actions { display: flex; gap: 0.5rem; flex-wrap: wrap; }

.mp-dash-toolbar { width: 100%; max-width: none; margin: 0 0 1rem; display: flex; align-items: center; gap: 0.6rem; flex-wrap: wrap; }
.mp-dash-search { flex: 1 1 240px; max-width: 30rem; }
.mp-dash-search input { width: 100%; height: 2.4rem; border-radius: 8px; border: 1px solid var(--mp-border);
    background: var(--mp-bg); color: var(--mp-text); padding: 0 0.75rem; }
/* Segmented control: supports plain <button> (dashboard, JS-toggled) and plain <a> (public meets, real
   navigation — meets-ui fable-spec §4.3, no JS owned by this work package) with identical visuals. */
.mp-segmented { display: flex; align-items: center; padding: 3px; background: var(--mp-bg); border: 1px solid var(--mp-border); border-radius: 9px; }
.mp-segmented button, .mp-segmented a { display: inline-flex; align-items: center; height: 1.9rem; padding: 0 0.7rem;
    color: var(--mp-muted); background: transparent; border: 0; text-decoration: none;
    border-radius: 6px; font-size: 0.78rem; font-weight: 750; cursor: pointer; white-space: nowrap; }
.mp-segmented button.active, .mp-segmented a.active { background: var(--mp-surface-2); color: var(--mp-text); }
.mp-dash-sort { width: 11rem; height: 2.4rem; border-radius: 8px; border: 1px solid var(--mp-border); background: var(--mp-bg); color: var(--mp-text); padding: 0 0.6rem; }

.mp-dash-empty, .mp-dash-noresults { width: 100%; max-width: none; margin: 0 0 1rem; text-align: center; padding: 2.5rem 1.5rem; }
.mp-dash-empty-icon { width: 3rem; height: 3rem; margin: 0 auto 0.75rem; border: 1px solid var(--mp-border); border-radius: 12px;
    display: grid; place-items: center; background: var(--mp-surface-2); font-size: 1.4rem; font-weight: 800; color: var(--mp-accent); }

/* auto-fill + minmax(min(100%,360px),1fr) + grid-auto-rows:1fr (meets-ui fable-spec §5.7) makes every card/tile
   in a row share the same computed row height, so Create-another-meet stretches to match its row siblings
   without a fixed min-height. */
.mp-dash-grid { width: 100%; max-width: none; margin: 0; display: grid; gap: 1rem;
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 360px), 1fr)); grid-auto-rows: 1fr; align-items: stretch; }
.mp-dash-card, .mp-dash-create-tile { background: var(--mp-surface); border: 1px solid var(--mp-border); border-radius: 13px; overflow: hidden; }
/* Six explicit row tracks (meets-ui fable-spec §5.7): top, meta, kpis, progress, a flexible spacer (.mp-dash-spacer,
   an explicit empty row so it — not the footer — absorbs the leftover height), then the footer pinned to the
   card's bottom edge regardless of how much content the other rows carry. */
.mp-dash-card { display: grid; grid-template-rows: auto auto auto auto 1fr auto; height: 100%; min-height: 374px; }

/* Composite header (meets-ui fable-spec §5.4): the title link reserves an explicit fixed-height 25px badge track
   + 10px gap + 2.56em two-line title track — regardless of whether the name naturally wraps to one or two lines —
   so `.mp-dash-card-meta` (now this row's sibling, not its child; see §5.2) always begins at the same
   parent-relative offset. The 40px second column reserves the overflow control's slot even when a given card
   renders no overflow menu, so every card's title column starts/ends at the same x-offset too. */
.mp-dash-card-top { display: grid; grid-template-columns: minmax(0, 1fr) 40px; align-items: start; column-gap: 12px;
    padding: 1.1rem 1.1rem 0; }
.mp-dash-card-link { display: grid; grid-template-rows: 25px 2.56em; row-gap: 10px; min-width: 0;
    text-decoration: none; color: inherit; border-radius: 6px; }
.mp-dash-card-link:focus-visible { outline: 2px solid var(--mp-accent); outline-offset: 3px; }
.mp-dash-card-title {
    display: -webkit-box; overflow: hidden; -webkit-box-orient: vertical; -webkit-line-clamp: 2;
    line-height: 1.28;
    /* 2 × 1.28 line-height: explicit block-size (not just min/max-block-size) forces the track to reserve two
       lines even when the rendered title only occupies one — a browser may otherwise size the row from the
       single rendered line despite a min-block-size alone. */
    block-size: 2.56em; min-block-size: 2.56em; max-block-size: 2.56em;
    margin: 0; font-size: 1.12rem; font-weight: 800; letter-spacing: -0.015em; color: var(--mp-text);
}
/* Sibling of .mp-dash-card-top (§5.2), not nested inside it — metadata no longer competes with the title/overflow
   row for horizontal space, and its top offset is now purely a function of the title-link's fixed track sizes
   above, identical for a one-line and a naturally two-line title. */
.mp-dash-card-meta { display: flex; flex-wrap: wrap; gap: 0.25rem 0.85rem; font-size: 0.75rem; padding: 0.55rem 1.1rem 0; }
.mp-dash-kpis { display: grid; grid-template-columns: repeat(3, 1fr); margin: 0.6rem 1.1rem 0.9rem; border: 1px solid var(--mp-border); border-radius: 10px; overflow: hidden; }
.mp-dash-kpis > div { padding: 0.6rem 0.65rem; background: rgba(0,0,0,0.12); border-right: 1px solid var(--mp-border); }
.mp-dash-kpis > div:last-child { border-right: 0; }
.mp-dash-kpis strong { display: block; overflow: hidden; font-size: 0.95rem; letter-spacing: -0.01em; text-overflow: ellipsis; white-space: nowrap; }
.mp-dash-kpis span { display: block; color: var(--mp-muted); font-size: 0.62rem; text-transform: uppercase; letter-spacing: 0.06em; font-weight: 750; }
.mp-dash-progress { margin: 0 1.1rem 0.9rem; }
.mp-dash-progress-label { display: flex; justify-content: space-between; color: var(--mp-muted); font-size: 0.7rem; margin-bottom: 0.4rem; }
.mp-dash-progress-bar { height: 6px; border-radius: 999px; background: var(--mp-bg); overflow: hidden; }
.mp-dash-progress-bar i { display: block; height: 100%; border-radius: inherit; background: linear-gradient(90deg, var(--mp-accent), #ffd76a); }
/* Explicit empty grid row (the 5th `1fr` track above) — grows/shrinks so .mp-dash-foot always lands on the
   card's last (auto) row instead of being stretched itself. */
.mp-dash-spacer { min-height: 0; }
.mp-dash-foot { display: flex; align-items: center; justify-content: space-between; gap: 0.6rem; padding: 0.75rem 1.1rem; border-top: 1px solid var(--mp-border); background: rgba(0,0,0,0.12); flex-wrap: wrap; }
.mp-dash-quick { display: flex; gap: 0.85rem; flex-wrap: wrap; }
.mp-dash-quick a { color: var(--mp-muted); text-decoration: none; font-size: 0.75rem; font-weight: 700; }
.mp-dash-quick a:hover { color: var(--mp-text); }
/* Create-another-meet tile (§5.8): one anchor, same border-radius/surface/min-height/height:100% contract as
   .mp-dash-card, so it stretches to the same computed row height under .mp-dash-grid's grid-auto-rows:1fr — the
   old fixed min-height:14rem sizing mechanism is gone. Centered via its own 5-row grid (spacer/icon/title/copy/
   spacer), matching the reference mock's .create-card. */
.mp-dash-create-tile { display: grid; grid-template-rows: 1fr auto auto auto 1fr; align-items: center; justify-items: center;
    height: 100%; min-height: 374px; text-align: center; padding: 1.5rem; text-decoration: none; color: var(--mp-text); border-style: dashed; }
.mp-dash-create-tile:hover { border-color: var(--mp-accent); }
.mp-dash-create-tile .mp-dash-empty-icon { grid-row: 2; margin: 0 0 0.4rem; }
.mp-dash-create-tile h3 { grid-row: 3; margin: 0; font-size: 1.05rem; letter-spacing: -0.01em; }
.mp-dash-create-tile .mp-muted { grid-row: 4; max-width: 15rem; margin: 0.4rem 0 0; }
[data-dashboard-card][hidden] { display: none; }

@media (max-width: 899px) {
    /* flex-wrap:nowrap must ride along with the column switch (here and on .mp-public-toolbar below): in a
       column container that still allows WRAPPING, each flex line is as wide as its widest item's intrinsic
       width — and .mp-segmented is a scroll strip whose intrinsic width ignores its own overflow-x, so once
       its status counts reach three digits ("All · 300") it is intrinsically wider than a phone viewport and
       align-items:stretch widens every sibling past the page edge with it. A single-line column instead
       clamps stretched children to the container and lets the strip scroll within itself. */
    .mp-page-header, .mp-dash-toolbar { flex-direction: column; align-items: stretch; flex-wrap: nowrap; }
    .mp-dash-actions .mp-btn { flex: 1; }
    .mp-dash-search { max-width: none; flex: 0 0 auto; }
    .mp-dash-grid { grid-template-columns: 1fr; }
}

/* ---- Public meets (meets-ui fable-spec §4) ----
   Dedicated .mp-public-* selectors (spec §7) instead of overloading the generic .mp-grid/.mp-card classes other
   unrelated pages still use. Reuses --mp-* tokens and the existing .mp-btn/.mp-badge/.mp-segmented/.mp-overflow
   system throughout — no second styling framework. .mp-public-meet-grid deliberately mirrors .mp-dash-grid's
   auto-fill/minmax(min(100%,360px),1fr)/grid-auto-rows:1fr recipe (§5.7) for the same equal-row-height guarantee. */
.mp-public-page { width: 100%; }

.mp-public-toolbar { display: flex; flex-wrap: wrap; align-items: center; gap: 0.6rem; width: 100%; margin: 0 0 1rem; }
/* position:relative lives on the FORM (not the inner .mp-public-search span) because the submit button is the
   form's last child, a sibling of the span — not nested inside it. */
.mp-public-search-form { position: relative; flex: 1 1 240px; max-width: 30rem; min-width: 0; }
.mp-public-search { display: block; }
.mp-public-search input[type="search"] { width: 100%; height: 2.6rem; border-radius: 9px; border: 1px solid var(--mp-border);
    background: var(--mp-bg); color: var(--mp-text); padding: 0 2.5rem 0 0.85rem; }
.mp-public-search-submit { position: absolute; right: 0.3rem; top: 50%; transform: translateY(-50%);
    width: 2rem; height: 2rem; display: grid; place-items: center; background: transparent; border: 0;
    border-radius: 6px; color: var(--mp-muted); cursor: pointer; }
.mp-public-search-submit:hover { color: var(--mp-text); background: var(--mp-surface-2); }
.mp-public-search-submit svg { width: 16px; height: 16px; }
.mp-public-sort-form { flex: 0 0 auto; }

.mp-public-result-row { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 1rem;
    margin: 0.25rem 0.15rem 0.85rem; color: var(--mp-muted); font-size: 0.78rem; }
.mp-public-result-row strong { color: var(--mp-text); }

.mp-public-meet-grid { width: 100%; display: grid; gap: clamp(14px, 1vw, 20px);
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 360px), 1fr)); grid-auto-rows: 1fr; align-items: stretch; }

.mp-public-meet-card { display: grid; grid-template-rows: auto minmax(92px, 1fr) auto; height: 100%; min-height: 340px;
    min-width: 0; padding: 1.15rem; border: 1px solid var(--mp-border); border-radius: 13px; background: var(--mp-surface); }

/* Composite header (meets-ui fable-spec §5.4, the same fixed-track contract applied to director cards): a fixed
   25px status track + a fixed 15px gap + a fixed 2.56em two-line title track, so `.mp-public-meet-meta` always
   begins at the same offset from the top of its own parent card, whether the meet name naturally occupies one
   line ("Canterbury Raw Open") or wraps to two. */
.mp-public-meet-head { display: grid; grid-template-rows: 25px 2.56em; row-gap: 15px; min-width: 0; }
.mp-public-meet-status { display: flex; align-items: center; justify-content: space-between; gap: 0.6rem; min-width: 0; }
.mp-public-meet-time { overflow: hidden; color: var(--mp-muted); font-size: 0.72rem; font-weight: 750; text-overflow: ellipsis; white-space: nowrap; }
.mp-public-meet-title {
    display: -webkit-box; overflow: hidden; -webkit-box-orient: vertical; -webkit-line-clamp: 2;
    line-height: 1.28;
    block-size: 2.56em; min-block-size: 2.56em; max-block-size: 2.56em;
    margin: 0; font-size: 1.15rem; font-weight: 850; letter-spacing: -0.02em; color: var(--mp-text); text-decoration: none;
}
.mp-public-meet-title:hover { text-decoration: underline; }
.mp-public-meet-title:focus-visible { outline: 2px solid var(--mp-accent); outline-offset: 3px; border-radius: 4px; }

/* The flexible `minmax(92px,1fr)` row on .mp-public-meet-card lives HERE (not as a separate spacer element) —
   align-content:start pins the detail rows to the top of that row while its own leftover height absorbs the
   difference between cards, pushing every card's footer to the same bottom edge (§4.4). */
.mp-public-meet-meta { display: grid; align-content: start; gap: 0.55rem; min-width: 0; padding-block: 0.95rem 0; }
.mp-public-meet-detail { display: grid; grid-template-columns: 18px minmax(0, 1fr); align-items: center; gap: 0.5rem;
    min-width: 0; color: var(--mp-muted); font-size: 0.78rem; line-height: 1.35; }
.mp-public-meet-detail svg { width: 15px; height: 15px; color: var(--mp-muted); flex: 0 0 auto; }
.mp-public-meet-detail span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Action footer (§4.5): equal-width two-column grid; a lone action or the 3rd action (when Livestream + Live
   scoreboard are both present) spans both columns. Every rendered control shares the same min-height. */
.mp-public-meet-actions { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0.5rem;
    min-width: 0; padding-block-start: 0.95rem; border-top: 1px solid var(--mp-border); }
.mp-public-meet-actions .mp-btn { width: 100%; min-width: 0; min-height: 44px; padding-inline: 0.65rem; }
.mp-public-meet-actions .mp-overflow { display: block; width: 100%; min-width: 0; }
.mp-public-meet-actions > *:first-child:last-child { grid-column: 1 / -1; }
.mp-public-meet-actions > *:nth-child(3) { grid-column: 1 / -1; }

.mp-btn.stream { display: inline-flex; align-items: center; justify-content: center; gap: 0.4rem;
    background: color-mix(in srgb, var(--mp-nolift) 16%, var(--mp-surface-2));
    border: 1px solid color-mix(in srgb, var(--mp-nolift) 45%, var(--mp-border)); color: #ffb5b9; }
.mp-btn.stream:hover { border-color: var(--mp-nolift); background: color-mix(in srgb, var(--mp-nolift) 24%, var(--mp-surface-2)); }
.mp-btn.stream svg { width: 14px; height: 14px; flex: 0 0 auto; }

/* ================================================================================================================
   Public meet page (PublicMeet.razor) — the .mp-pm-* family.

   ONE scoped class family over the existing --mp-* tokens; no second design system and no CSS dependency. It
   replaces the page's former three-equal-cards layout (and the .mp-watch-actions / .mp-meet-detail-* selectors
   that supported it, which had no other consumer).

   Responsive/accessibility rules baked in here rather than left to the markup:
     * every length is relative (rem / clamp / fr / minmax), so 200% browser zoom simply reflows — the two-column
       body collapses at the same 899px breakpoint the rest of this file uses, and again inside the hero;
     * min-width: 0 on both grid columns, because a grid item's default min-width:auto is what lets a long venue
       name or URL push a whole column past the viewport and give the PAGE a horizontal scrollbar at 320px;
     * :focus-visible outlines on every interactive element the page introduces (the shared .mp-btn already has
       its own), and 44px minimum touch targets on the ones that are not buttons;
     * prefers-reduced-motion drops the only transition.                                                        */
.mp-pm { display: block; }

.mp-pm-crumbs { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem; margin-bottom: 0.9rem;
    color: var(--mp-muted); font-size: 0.85rem; }
.mp-pm-crumbs a { color: var(--mp-muted); text-decoration: none; padding: 0.2rem 0; }
.mp-pm-crumbs a:hover { color: var(--mp-text); text-decoration: underline; }
.mp-pm-crumbs a:focus-visible { outline: 2px solid var(--mp-accent); outline-offset: 2px; border-radius: 4px; }
.mp-pm-crumb-sep { color: var(--mp-border); }

.mp-pm-hero { position: relative; overflow: hidden; display: grid; gap: clamp(1.25rem, 3vw, 2.25rem);
    grid-template-columns: minmax(0, 1fr) auto; align-items: end;
    padding: clamp(1.35rem, 3.5vw, 2.75rem); border: 1px solid var(--mp-border); border-radius: 16px;
    background:
        linear-gradient(125deg, color-mix(in srgb, var(--mp-accent) 9%, transparent), transparent 45%),
        linear-gradient(180deg, var(--mp-surface-2), var(--mp-surface)); }
.mp-pm-hero-main { min-width: 0; }
.mp-pm-badges { display: flex; flex-wrap: wrap; align-items: center; gap: 0.4rem; margin: 0 0 0.75rem; }
.mp-pm-hero h1 { margin: 0 0 0.6rem; font-size: clamp(1.75rem, 5vw, 3rem); line-height: 1.1;
    letter-spacing: -0.02em; overflow-wrap: anywhere; }
.mp-pm-lede { max-width: 46rem; margin: 0; color: var(--mp-muted); font-size: clamp(0.95rem, 1.4vw, 1.05rem); }

.mp-pm-meta { display: flex; flex-wrap: wrap; gap: 0.6rem 1.5rem; margin: 1.35rem 0 0; padding: 0;
    list-style: none; color: var(--mp-muted); font-size: 0.9rem; }
.mp-pm-meta li { display: inline-flex; align-items: center; gap: 0.5rem; min-width: 0; overflow-wrap: anywhere; }
.mp-pm-meta svg { width: 1.05rem; height: 1.05rem; flex: 0 0 auto; color: var(--mp-text); }

.mp-pm-hero-actions { display: flex; flex-direction: column; gap: 0.6rem; min-width: 12rem; }
.mp-pm-hero-actions .mp-btn { justify-content: center; min-height: 2.75rem; }

.mp-pm-body { display: grid; gap: 1.1rem; margin-top: 1.1rem;
    grid-template-columns: minmax(0, 1.5fr) minmax(0, 1fr); align-items: start; }
.mp-pm-col { display: grid; gap: 1.1rem; min-width: 0; align-content: start; }
.mp-pm-card { min-width: 0; }
.mp-pm-card h2 { margin: 0 0 0.85rem; font-size: 1.1rem; letter-spacing: -0.01em; }
.mp-pm-card-sub { margin: -0.55rem 0 0.85rem; font-size: 0.82rem; }
.mp-pm-subhead { margin: 1.1rem 0 0.35rem; font-size: 0.92rem; }

.mp-pm-details { display: grid; gap: 1px; margin: 0; overflow: hidden;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    border: 1px solid var(--mp-border); border-radius: 12px; background: var(--mp-border); }
.mp-pm-details > div { min-width: 0; padding: 0.85rem 0.95rem; background: var(--mp-surface); }
.mp-pm-details dt { color: var(--mp-muted); font-size: 0.72rem; font-weight: 700; letter-spacing: 0.06em;
    text-transform: uppercase; }
.mp-pm-details dd { margin: 0.4rem 0 0; font-size: 0.94rem; overflow-wrap: anywhere; }

.mp-pm-timeline { display: grid; gap: 0; margin: 0; padding: 0; list-style: none; }
.mp-pm-timeline li { position: relative; display: grid; grid-template-columns: 1.75rem minmax(0, 1fr);
    gap: 0.8rem; padding-bottom: 1.1rem; }
.mp-pm-timeline li:last-child { padding-bottom: 0; }
/* The connector is drawn from the mark downwards; the last step has nothing below it to connect to. */
.mp-pm-timeline li::before { content: ""; position: absolute; left: 0.85rem; top: 1.95rem; bottom: 0;
    width: 1px; background: var(--mp-border); }
.mp-pm-timeline li:last-child::before { display: none; }
.mp-pm-step-mark { display: grid; place-items: center; width: 1.75rem; height: 1.75rem;
    border: 1px solid var(--mp-border); border-radius: 50%; background: var(--mp-surface-2);
    color: var(--mp-muted); font-size: 0.8rem; font-weight: 800; }
.mp-pm-timeline li.done .mp-pm-step-mark { border-color: color-mix(in srgb, var(--mp-good) 55%, var(--mp-border));
    color: var(--mp-good); }
.mp-pm-step-copy { min-width: 0; }
.mp-pm-step-copy strong { display: block; font-size: 0.92rem; }
.mp-pm-step-copy span { display: block; margin-top: 0.15rem; font-size: 0.82rem; }

.mp-pm-links { display: grid; gap: 0.5rem; }
.mp-pm-link { display: block; min-height: 2.75rem; padding: 0.65rem 0.8rem; border: 1px solid var(--mp-border);
    border-radius: 10px; background: var(--mp-surface-2); color: var(--mp-text); text-decoration: none;
    transition: border-color 0.15s ease, background 0.15s ease; }
.mp-pm-link:hover { border-color: var(--mp-accent); background: var(--mp-surface); }
.mp-pm-link:focus-visible { outline: 2px solid var(--mp-accent); outline-offset: 2px; }
.mp-pm-link strong { display: block; font-size: 0.9rem; }
.mp-pm-link span { display: block; margin-top: 0.1rem; font-size: 0.78rem; }
/* The multi-stream disclosure reuses .mp-overflow's menu; only the summary needs the link's own shape, and
   list-style:none stops Safari/Firefox drawing a marker triangle inside it. */
.mp-pm-streams { position: relative; }
.mp-pm-streams > summary { cursor: pointer; list-style: none; }
.mp-pm-streams > summary::-webkit-details-marker { display: none; }

.mp-pm-fee { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.5rem; margin: 0 0 0.85rem; }
.mp-pm-fee strong { font-size: 1.05rem; }
.mp-pm-entry-note, .mp-pm-policy { margin: 0; font-size: 0.86rem; overflow-wrap: anywhere; }

@media (max-width: 899px) {
    .mp-pm-hero { grid-template-columns: minmax(0, 1fr); align-items: stretch; }
    .mp-pm-hero-actions { flex-direction: row; flex-wrap: wrap; min-width: 0; }
    .mp-pm-hero-actions .mp-btn { flex: 1 1 12rem; }
    .mp-pm-body { grid-template-columns: minmax(0, 1fr); }
}

@media (max-width: 599px) {
    .mp-pm-hero-actions { flex-direction: column; }
    .mp-pm-hero-actions .mp-btn { flex: 0 0 auto; width: 100%; }
    .mp-pm-meta { display: grid; gap: 0.55rem; }
    .mp-pm-details { grid-template-columns: minmax(0, 1fr); }
}

@media (prefers-reduced-motion: reduce) {
    .mp-pm-link { transition: none; }
}

@media (max-width: 899px) {
    /* flex-wrap:nowrap for the same reason as .mp-dash-toolbar's column switch above: without it, the
       wrapped-column line takes .mp-segmented's intrinsic (unscrolled) width once its counts reach three
       digits, and every stretched sibling overflows the page with it. */
    .mp-public-toolbar { flex-direction: column; align-items: stretch; flex-wrap: nowrap; }
    .mp-public-search-form, .mp-public-sort-form { max-width: none; }
    .mp-public-sort-form select { width: 100%; }
    .mp-segmented { overflow-x: auto; }
}

@media (max-width: 480px) {
    .mp-public-meet-actions { grid-template-columns: 1fr; }
    .mp-public-meet-actions > *:nth-child(3) { grid-column: auto; }
    .mp-watch-actions .mp-btn { width: 100%; }
}

/* ---- Manage console: shared context header + tab strip (§6.1) ---- */
.mp-crumbs { color: var(--mp-muted); font-size: 0.78rem; }
.mp-crumbs span { margin: 0 0.4rem; }
.mp-meet-hero { display: flex; align-items: center; justify-content: space-between; gap: 1.25rem; flex-wrap: wrap; }
.mp-meet-hero h1 { margin: 0.2rem 0 0.3rem; font-size: clamp(1.5rem, 2.2vw, 1.9rem); letter-spacing: -0.02em; }
.mp-meet-hero-actions { display: flex; align-items: center; gap: 0.6rem; flex-wrap: wrap; }
.mp-meet-tabs { display: flex; align-items: center; gap: 2px; padding: 5px;
    background: var(--mp-surface); border: 1px solid var(--mp-border); border-radius: 10px; overflow-x: auto; }
.mp-meet-tabs a { flex: none; padding: 0.55rem 0.8rem; border-radius: 8px; font-size: 0.78rem; font-weight: 750;
    color: var(--mp-muted); text-decoration: none; white-space: nowrap; }
.mp-meet-tabs a.active { color: var(--mp-text); background: var(--mp-surface-3, var(--mp-surface-2)); }
@media (max-width: 899px) {
    .mp-meet-hero { flex-direction: column; align-items: flex-start; }
    .mp-meet-hero-actions { width: 100%; }
    .mp-meet-hero-actions .mp-btn { flex: 1; }
}

/* ---- Manage Overview (§6.2–§6.7) ---- */
.mp-overview-toolbar { display: flex; justify-content: flex-end; }
.mp-overview-grid { display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); gap: 1rem; align-items: stretch; }
.mp-overview-grid .mp-card { margin-bottom: 0; }
.mp-readiness-card { grid-column: span 8; padding: 1.4rem; display: grid; grid-template-columns: auto 1fr; gap: 1.4rem; align-items: center; }
.mp-ring { --p: 0%; width: 5.5rem; aspect-ratio: 1; border-radius: 50%; display: grid; place-items: center;
    background: conic-gradient(var(--mp-accent) var(--p), var(--mp-surface-2) 0); position: relative; }
.mp-ring::before { content: ""; width: 4.2rem; aspect-ratio: 1; border-radius: 50%; background: var(--mp-surface); position: absolute; }
.mp-ring strong { position: relative; font-size: 1.2rem; }
.mp-readiness-copy h2 { margin: 0 0 0.4rem; font-size: 1.25rem; }
.mp-readiness-copy p { max-width: 40rem; }
.mp-readiness-copy .mp-btn { margin-top: 0.75rem; }
.mp-lifecycle-card { grid-column: span 4; padding: 1.1rem 1.25rem; display: flex; flex-direction: column; justify-content: space-between; gap: 0.75rem; }
.mp-lifecycle-label { font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.05em; font-weight: 700; }
.mp-lifecycle-stage { margin-top: 0.4rem; }
.mp-timeline { display: grid; grid-template-columns: repeat(5, 1fr); gap: 5px; margin-top: 0.5rem; }
.mp-timeline span { display: block; height: 4px; border-radius: 99px; background: var(--mp-surface-2); }
.mp-timeline span.done { background: var(--mp-good); }
.mp-timeline span.current { background: var(--mp-accent); }
.mp-timeline-labels { display: flex; justify-content: space-between; font-size: 0.68rem; margin-top: 0.4rem; }
.mp-lifecycle-actions { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; }
.mp-stat-strip { grid-column: 1 / -1; display: grid; grid-template-columns: repeat(6, 1fr); overflow: hidden; padding: 0; }
.mp-stat-box { min-height: 5.6rem; padding: 0.95rem 1rem; border-right: 1px solid var(--mp-border); }
.mp-stat-box:last-child { border-right: 0; }
.mp-stat-box strong { display: block; font-size: 1.3rem; letter-spacing: -0.02em; }
.mp-stat-box span { color: var(--mp-muted); font-size: 0.68rem; }
.mp-stat-box.alert strong { color: var(--mp-nolift); }
.mp-tasks { grid-column: span 7; }
.mp-board { grid-column: span 5; }
.mp-card-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 1rem; padding-bottom: 0.6rem; border-bottom: 1px solid var(--mp-border); margin-bottom: 0.35rem; }
.mp-card-head h2 { margin: 0; font-size: 1.05rem; }
.mp-card-head p { margin-top: 0.25rem; font-size: 0.8rem; }

/* Readiness checklist rows. */
.mp-checklist-item { display: grid; grid-template-columns: 1.6rem minmax(0,1fr) auto; gap: 0.75rem; align-items: center; padding: 0.7rem 0; border-bottom: 1px solid var(--mp-border); }
.mp-checklist-item:last-child { border-bottom: 0; }
.mp-checklist-mark { width: 1.6rem; height: 1.6rem; border-radius: 7px; display: grid; place-items: center;
    background: var(--mp-surface-2); border: 1px solid var(--mp-border); color: var(--mp-muted); font-size: 0.72rem; font-weight: 800; }
.mp-checklist-mark.done { color: #08261a; background: var(--mp-good); border-color: var(--mp-good); }
.mp-checklist-mark.blocking { color: var(--mp-nolift); border-color: var(--mp-nolift); }
.mp-checklist-mark.recommended { color: var(--mp-accent); border-color: var(--mp-accent); }
.mp-checklist-body strong { display: block; font-size: 0.85rem; }
.mp-checklist-body p { color: var(--mp-muted); font-size: 0.72rem; margin-top: 0.15rem; }
.mp-checklist-item.done { opacity: 0.75; }
.mp-checklist-item a { color: var(--mp-accent-2, var(--mp-accent)); text-decoration: none; font-size: 0.78rem; font-weight: 800; white-space: nowrap; }
.mp-checklist-state { font-size: 0.75rem; white-space: nowrap; }

/* Boards & displays launcher. */
.mp-board-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 0.3rem; }
.mp-board-row { display: grid; grid-template-columns: 2.2rem minmax(0,1fr) auto auto; gap: 0.6rem; align-items: center; padding: 0.4rem 0.35rem; border-radius: 9px; }
.mp-board-row:hover { background: var(--mp-surface-2); }
.mp-board-icon { width: 2.2rem; height: 2.2rem; border-radius: 8px; display: grid; place-items: center; background: var(--mp-surface-2); color: var(--mp-accent); }
.mp-board-link { min-width: 0; text-decoration: none; color: var(--mp-text); }
.mp-board-link:focus-visible { outline: 2px solid var(--mp-accent); outline-offset: 2px; }
.mp-board-link strong { display: block; font-size: 0.85rem; }
.mp-board-link span { display: block; color: var(--mp-muted); font-size: 0.72rem; margin-top: 0.1rem; }
.mp-board-copy-status { font-size: 0.68rem; color: var(--mp-good); min-width: 0; }
.mp-board-copy { border: 0; background: transparent; color: var(--mp-muted); cursor: pointer; padding: 0.4rem; border-radius: 7px; }
.mp-board-copy:hover { background: var(--mp-surface-3, var(--mp-surface-2)); color: var(--mp-text); }
.mp-board-copy.mp-copied { color: var(--mp-good); }

@media (max-width: 1439px) {
    .mp-readiness-card, .mp-tasks { grid-column: span 7; }
    .mp-lifecycle-card, .mp-board { grid-column: span 5; }
}
@media (max-width: 899px) {
    .mp-overview-grid { grid-template-columns: 1fr; }
    .mp-overview-grid > * { grid-column: 1 / -1; }
    .mp-readiness-card { grid-template-columns: auto 1fr; }
    .mp-stat-strip { grid-template-columns: repeat(2, 1fr); }
    .mp-stat-box { border-right: 0; border-bottom: 1px solid var(--mp-border); }
}

/* ---- Phone-first pass: /my/meets/{id} (docs/ARCHITECTURE-GAP-PLAN.md §12 Phase 7) ---- */
/* Scoped to .mp-mymeet (the lifter's own meet-day page) rather than globally — the meet-day boards (run board,
   scoreboard) reuse the same .mp-btn/.form-control/.mp-grid classes at operator-console density and must not
   grow bigger tap targets on a scoring-table screen. */
.mp-mymeet { min-width: 0; }
.mp-mymeet .mp-card { min-width: 0; overflow-wrap: anywhere; }
/* Tables can be wider than a phone screen (4 attempt columns) — scroll INSIDE the card, never the page. */
.mp-mymeet table.mp-table { min-width: 22rem; }
.mp-mymeet div:has(> table.mp-table) { overflow-x: auto; -webkit-overflow-scrolling: touch; }
/* Attempt/rack-height inputs and every button get a real thumb-sized tap target (>=44px, per WCAG 2.5.5). */
.mp-mymeet input.form-control, .mp-mymeet select.form-control { min-height: 44px; font-size: 1rem; box-sizing: border-box; }
.mp-mymeet .mp-btn { min-height: 44px; padding: 0.65rem 1.2rem; font-size: 1rem; box-sizing: border-box; }
.mp-mymeet .mp-withdraw-card { padding: 0.75rem 1.4rem; }
.mp-mymeet .mp-withdraw-card .mp-btn { width: 100%; }
.mp-target-row { margin: 0.3rem 0; line-height: 1.5; }
.mp-target-row:first-child { margin-top: 0; }
.mp-target-row:last-child { margin-bottom: 0; }
@media (max-width: 480px) {
    /* Single column: the two-up "Declare attempt / Rack heights" grid stacks, and every full-bleed action button
       spans the full width so it's an easy thumb target instead of a half-width phone-unfriendly strip. */
    .mp-mymeet .mp-grid { grid-template-columns: 1fr; }
    .mp-mymeet .mp-btn { width: 100%; }
    .mp-mymeet h1 { font-size: 1.5rem; }
}

/* ---- Async page-state (PageLoadState.razor): spinner + shimmer skeleton ---- */
.mp-load { display: flex; align-items: center; gap: 0.5rem; margin: 0.75rem 0; }
.mp-load-spinner {
    width: 18px; height: 18px; border: 2px solid var(--mp-border); border-top-color: var(--mp-accent);
    border-radius: 50%; animation: mp-spin 0.8s linear infinite;
}
@keyframes mp-spin { to { transform: rotate(360deg); } }
.mp-skel { display: flex; flex-direction: column; gap: 0.55rem; margin-top: 0.75rem; }
.mp-skel-bar {
    height: 1.1rem; border-radius: 6px; width: 100%;
    background: linear-gradient(90deg, var(--mp-surface) 25%, color-mix(in srgb, var(--mp-text) 8%, var(--mp-surface)) 37%, var(--mp-surface) 63%);
    background-size: 400% 100%; animation: mp-shimmer 1.4s ease infinite;
}
@keyframes mp-shimmer { 0% { background-position: 100% 0; } 100% { background-position: 0 0; } }
.mp-skel-title { height: 1.6rem; width: 40%; }
.mp-load-error strong { color: var(--mp-nolift); display: block; margin-bottom: 0.25rem; }
.mp-load-error a { margin-top: 0.5rem; display: inline-flex; }

/* ---- Configurable entry form (WP3 §6.1): the Setup-tab editor and the public /enter form share these classes
   so the live preview and the real entrant-facing form read identically. ---- */
.mp-entry-editor .mp-setup-head { align-items: center; }
.mp-entry-warning {
    background: color-mix(in srgb, var(--mp-accent) 12%, var(--mp-surface)); border: 1px solid var(--mp-accent);
    border-radius: 8px; padding: 0.6rem 0.9rem; font-size: 0.85rem; margin: 0.5rem 0 0.75rem;
}
.mp-entry-table { margin-top: 0.5rem; }
.mp-entry-table td, .mp-entry-table th { vertical-align: top; }
.mp-entry-field { margin: 0 0 0.85rem; }
.mp-entry-field label { display: block; font-size: 0.8rem; margin-bottom: 0.2rem; }
.mp-entry-help { color: var(--mp-muted); font-size: 0.78rem; margin: -0.05rem 0 0.3rem; }
.mp-entry-checks { display: flex; flex-direction: column; gap: 0.25rem; margin: 0.2rem 0; }
.mp-entry-check { display: flex; align-items: center; gap: 0.4rem; font-size: 0.9rem; font-weight: 400; }
.mp-entry-none { margin-top: 0.35rem; color: var(--mp-muted); }
.mp-entry-error { color: var(--mp-nolift); font-size: 0.8rem; margin-top: 0.25rem; }
.mp-entry-preview {
    border: 1px dashed var(--mp-border); border-radius: 10px; padding: 0.85rem 1rem; margin-top: 0.4rem;
    background: color-mix(in srgb, var(--mp-bg) 60%, transparent);
}
.mp-entry-preview .mp-entry-field:last-child { margin-bottom: 0; }

/* ---- Federation membership verification (federation-membership WP5, visual reference mock-up). The builder's
   inspector (Setup tab) and the public /enter signup section share the .mp-membership- and .mp-locked-line
   vocabulary; state notices are a border-color variant over --mp-good/--mp-nolift/--mp-accent/--mp-info, matching
   the mock-up's four states (verified/mismatch/inactive/unavailable) without inventing new palette tokens.

   NOTE (WP6): the class-name prefixes here and in the WP3 block below are deliberately written WITHOUT a trailing
   wildcard, and every list of them is separated by " / " rather than "/". A star immediately followed by a slash
   CLOSES a CSS comment: ".mp-membership-" plus a wildcard plus "/.mp-locked-line" ended this comment four lines
   early and dumped the rest of the sentence into the stylesheet as garbage tokens. The parser's recovery from that
   swallowed real rules further down the file, which showed up as several completely unrelated pages losing their
   responsive layout (documentElement.scrollWidth ~2060px at a 390px viewport on /admin/users, the account
   capabilities card and the OpenPowerlifting submissions card). Never end a token with a star before a slash. ---- */
.mp-locked-line {
    display: flex; align-items: center; justify-content: space-between; gap: 0.75rem;
    border: 1px solid var(--mp-border); background: var(--mp-surface-2); border-radius: 8px;
    padding: 0.6rem 0.75rem; margin-top: 0.4rem;
}
.mp-membership-inspector { margin-top: 0.5rem; }
.mp-membership-inspector textarea.form-control { min-height: 4.5rem; }

.mp-membership-section { padding: 0.75rem 0 0; border-top: 1px solid var(--mp-border); margin-top: 0.75rem; }
.mp-membership-section h3 { margin: 0 0 0.3rem; }
.mp-section-kicker {
    color: var(--mp-accent); text-transform: uppercase; letter-spacing: 0.08em; font-size: 0.7rem; font-weight: 800;
    margin-bottom: 0.2rem;
}
/* Facts grid: 2 columns collapsing to 1 at 720px. */
.mp-membership-facts { display: grid; grid-template-columns: 1fr 1fr; gap: 0.6rem; margin: 0.75rem 0; }
.mp-membership-fact {
    border: 1px solid var(--mp-border); background: var(--mp-surface-2); border-radius: 8px; padding: 0.55rem 0.7rem;
}
.mp-membership-fact span { display: block; color: var(--mp-muted); font-size: 0.7rem; margin-bottom: 0.15rem; }
/* Input + Verify button row: collapses to a stacked, full-width layout at 720px. */
.mp-membership-input-row { display: grid; grid-template-columns: 1fr auto; gap: 0.55rem; align-items: end; }

.state-panel { margin-top: 0.75rem; }
.mp-membership-notice {
    display: flex; gap: 0.7rem; align-items: flex-start; border: 1px solid var(--mp-border); border-radius: 10px;
    padding: 0.7rem 0.85rem; background: var(--mp-surface-2);
}
.mp-membership-notice-icon {
    flex: 0 0 auto; width: 1.5rem; height: 1.5rem; border-radius: 50%; border: 1px solid currentColor;
    display: flex; align-items: center; justify-content: center; font-weight: 800; font-size: 0.8rem;
}
.mp-membership-notice p { margin: 0.15rem 0 0; }
.mp-membership-notice-good { border-color: var(--mp-good); }
.mp-membership-notice-good .mp-membership-notice-icon { color: var(--mp-good); }
.mp-membership-notice-bad { border-color: var(--mp-nolift); }
.mp-membership-notice-bad .mp-membership-notice-icon { color: var(--mp-nolift); }
.mp-membership-notice-warn { border-color: var(--mp-accent); }
.mp-membership-notice-warn .mp-membership-notice-icon { color: var(--mp-accent); }
.mp-membership-notice-info { border-color: var(--mp-info); }
.mp-membership-notice-info .mp-membership-notice-icon { color: var(--mp-info); }

@media (max-width: 720px) {
    .mp-membership-facts { grid-template-columns: 1fr; }
    .mp-membership-input-row { grid-template-columns: 1fr; }
    .mp-membership-input-row button { width: 100%; }
}

/* ---- nzpu-membership-entry WP2 (gate G2.2C / spec 5.1/5.3/5.5): shared entry-form header, progress, requirements
   summary, invitation banner and director invite-list additions. Reuses --mp-* tokens and the existing
   .mp-card / .mp-btn / .mp-badge / .mp-table / .mp-muted / .mp-membership- system throughout -- no second styling
   framework. ---- */
.mp-entry-header { margin: 0 0 0.75rem; }
.mp-entry-header h1 { margin: 0 0 0.3rem; }

.mp-entry-progress {
    display: grid; grid-template-columns: repeat(4, 1fr); gap: 0.5rem; list-style: none;
    margin: 0.75rem 0 1rem; padding: 0;
}
.mp-entry-progress-step { color: var(--mp-muted); font-size: 0.78rem; }
.mp-entry-progress-dot { display: block; height: 5px; border-radius: 999px; background: var(--mp-border); margin-bottom: 0.35rem; }
.mp-entry-progress-step[data-state="done"],
.mp-entry-progress-step[data-state="current"] { color: var(--mp-text); font-weight: 700; }
.mp-entry-progress-step[data-state="done"] .mp-entry-progress-dot,
.mp-entry-progress-step[data-state="current"] .mp-entry-progress-dot { background: var(--mp-accent); }

.mp-entry-layout { display: grid; grid-template-columns: minmax(0, 1fr) minmax(220px, 300px); gap: 1rem; align-items: start; }
.mp-entry-main { min-width: 0; }
.mp-entry-summary { position: sticky; top: 0.75rem; }
.mp-entry-summary-list { display: grid; gap: 0.55rem; margin: 0.5rem 0 0; }
.mp-entry-summary-row { display: flex; justify-content: space-between; gap: 0.75rem; padding-bottom: 0.5rem; border-bottom: 1px solid var(--mp-border); }
.mp-entry-summary-row:last-child { border-bottom: 0; padding-bottom: 0; }
.mp-entry-summary-row dt { color: var(--mp-muted); font-size: 0.78rem; }
.mp-entry-summary-row dd { margin: 0; font-weight: 700; font-size: 0.85rem; }

@media (max-width: 860px) {
    .mp-entry-layout { grid-template-columns: 1fr; }
    .mp-entry-summary { position: static; order: -1; }
}

/* Invitation access gate (/enter/{token}) -- EnterViaInvite.razor's own banner/prompt cards, kept in the same
   .mp-card vocabulary as everything else on this route. */
.mp-invite-banner { margin-bottom: 0.75rem; }
.mp-invite-banner p { margin-top: 0.3rem; }

/* Director "Invitations" list (EntriesPanel.razor invite section, spec 5.5). */
.mp-invite-link-once {
    display: flex; align-items: center; gap: 0.6rem; flex-wrap: wrap;
    border: 1px solid var(--mp-accent); background: color-mix(in srgb, var(--mp-accent) 10%, var(--mp-surface));
    border-radius: 8px; padding: 0.6rem 0.75rem; margin-top: 0.6rem;
}
.mp-invite-link-once code { overflow-wrap: anywhere; }

/* ---- OpenPowerlifting import (WP4 §7.3): Setup-tab "Import livestream data" panel. ---- */
.mp-opl-preflight { display: flex; gap: 1.25rem; flex-wrap: wrap; margin: 0.5rem 0; }
.mp-opl-stat { display: flex; flex-direction: column; align-items: flex-start; min-width: 5.5rem; }
.mp-opl-stat-n { font-size: 1.4rem; font-weight: 800; line-height: 1.1; }
.mp-opl-source-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 1.25rem; margin-top: 0.5rem; }
@media (max-width: 720px) { .mp-opl-source-grid { grid-template-columns: 1fr; } }
.mp-opl-jobhead { display: flex; align-items: center; gap: 0.6rem; flex-wrap: wrap; margin: 0.6rem 0; }
.mp-opl-processing { color: var(--mp-muted); }
.mp-opl-table td, .mp-opl-table th { vertical-align: top; }
.mp-opl-table select.form-control { min-width: 14rem; }
.mp-opl-attrib { margin-top: 1rem; font-size: 0.72rem; }

/* ==== WP4 (§7): Setup lower half — section index + entry-form builder + compact tool panels ==== */
.mp-badge.warn { color: var(--mp-accent); border-color: var(--mp-accent); }
.mp-form-ok { color: var(--mp-good); font-weight: 600; }
.mp-form-err { color: var(--mp-nolift); font-weight: 600; }

/* ---- §7.1 Section index: sticky rail on desktop, horizontal strip on mobile ---- */
.mp-setup-lower { display: grid; grid-template-columns: 232px minmax(0, 1fr); gap: 1rem; align-items: start; margin-top: 1rem; }
.mp-setup-tools { display: flex; flex-direction: column; gap: 1rem; min-width: 0; }
.mp-setup-tools .mp-card { margin-bottom: 0; }
/* min-width: 0 — without it this grid item's automatic minimum size is its min-content width, which on the mobile
   tier below is the whole un-collapsed row of index links (~617px) and floors the column, and so the page, wider
   than the viewport. The nav's own overflow-x makes it a scroll container, which zeroes the automatic minimum of a
   flex/grid ITEM — but the nav is a normal-flow block here, so it still reports that width as its min-content
   contribution up to this aside. Fixing it has to happen on the grid item (here) or the track (below). */
.mp-setup-index { position: sticky; top: 0.75rem; padding: 0.75rem; min-width: 0; }
.mp-setup-index-nav { display: flex; flex-direction: column; gap: 0.25rem; }
.mp-setup-index-nav a { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem;
    padding: 0.5rem 0.6rem; border-radius: 8px; color: var(--mp-text); text-decoration: none; border: 1px solid transparent; }
.mp-setup-index-nav a:hover { background: color-mix(in srgb, var(--mp-accent) 12%, var(--mp-surface)); border-color: var(--mp-border); }
.mp-setup-index-label { font-weight: 600; font-size: 0.9rem; }
.mp-setup-index-help { font-size: 0.75rem; margin: 0.6rem 0 0; }
@media (max-width: 900px) {
    /* minmax(0, 1fr), not 1fr: the single mobile column must never be floored by its items' min-content. */
    .mp-setup-lower { grid-template-columns: minmax(0, 1fr); }
    .mp-setup-index { position: static; }
    .mp-setup-index-nav { flex-direction: row; overflow-x: auto; -webkit-overflow-scrolling: touch; }
    .mp-setup-index-nav a { flex: 0 0 auto; flex-direction: column; align-items: flex-start; }
    .mp-setup-index-help { display: none; }
}

/* ---- §7.2 Builder header ---- */
.mp-builder-head { align-items: flex-start; }
.mp-builder-title { display: flex; align-items: center; gap: 0.6rem; flex-wrap: wrap; }
.mp-builder-title h3 { margin: 0; }
.mp-builder-sub { flex: 1 1 100%; font-size: 0.82rem; margin: 0.15rem 0 0; }
.mp-builder-actions { margin-left: auto; display: flex; gap: 0.5rem; flex-wrap: wrap; align-items: center; }

/* ---- §7.2/§7.5 Two-pane body: ordered field list + live preview ---- */
.mp-builder-body { display: grid; grid-template-columns: minmax(0, 1fr) minmax(300px, 400px); gap: 1.25rem; align-items: start; }
@media (max-width: 1080px) { .mp-builder-body { grid-template-columns: 1fr; } }
.mp-fields { min-width: 0; }
/* A flex-wrap row (not a rigid grid) so the field name never collapses to zero width when the pane is narrow —
   the source/requirement/entries/menu controls wrap under the name instead. */
.mp-field-row { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem 0.7rem;
    padding: 0.6rem 0.2rem; border-bottom: 1px solid var(--mp-border); }
.mp-field-reorder { flex: 0 0 auto; display: flex; flex-direction: column; gap: 0.15rem; }
.mp-field-reorder form { line-height: 0; }
.mp-icon-btn { background: var(--mp-surface-2); color: var(--mp-text); border: 1px solid var(--mp-border);
    border-radius: 6px; width: 1.7rem; height: 1.35rem; font-size: 0.7rem; cursor: pointer; padding: 0;
    display: inline-flex; align-items: center; justify-content: center; }
.mp-icon-btn:hover { border-color: var(--mp-accent); color: var(--mp-accent); }
.mp-field-name { flex: 1 1 12rem; min-width: 9rem; }
.mp-field-name strong { display: flex; align-items: center; gap: 0.4rem; font-size: 0.92rem; }
.mp-field-name .mp-badge { font-size: 0.6rem; padding: 0.05rem 0.35rem; }
.mp-field-meta { display: block; font-size: 0.75rem; }
.mp-field-source { flex: 0 0 auto; font-size: 0.8rem; min-width: 4.5rem; }
.mp-req-seg, .mp-field-entries { flex: 0 0 auto; }

/* Three-state requirement control (Hidden / Optional / Required) as an accessible segmented radio group. */
.mp-req-seg { display: inline-flex; border: 1px solid var(--mp-border); border-radius: 8px; overflow: hidden; }
.mp-req-input { position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none; }
.mp-req-label { padding: 0.28rem 0.55rem; font-size: 0.78rem; cursor: pointer; color: var(--mp-muted);
    border-left: 1px solid var(--mp-border); user-select: none; }
.mp-req-label:first-of-type { border-left: 0; }
.mp-req-input:checked + .mp-req-label { background: var(--mp-accent); color: #1a1300; font-weight: 700; }
.mp-req-input:focus-visible + .mp-req-label { outline: 2px solid var(--mp-accent); outline-offset: -2px; }
.mp-req-locked { padding: 0.28rem 0.55rem; font-size: 0.78rem; color: var(--mp-muted); }

/* "Show on Entries page" toggle line. */
.mp-toggle-line { display: inline-flex; align-items: center; gap: 0.4rem; font-size: 0.8rem; cursor: pointer;
    color: var(--mp-muted); }
.mp-toggle-line input { position: absolute; width: 1px; height: 1px; opacity: 0; }
.mp-toggle { width: 1.8rem; height: 1rem; border-radius: 999px; background: var(--mp-surface-2);
    border: 1px solid var(--mp-border); position: relative; flex: 0 0 auto; transition: background 0.12s; }
.mp-toggle::after { content: ""; position: absolute; top: 1px; left: 1px; width: 0.8rem; height: 0.8rem;
    border-radius: 50%; background: var(--mp-muted); transition: transform 0.12s, background 0.12s; }
.mp-toggle-line.on { color: var(--mp-text); }
.mp-toggle-line.on .mp-toggle { background: color-mix(in srgb, var(--mp-accent) 55%, var(--mp-surface)); border-color: var(--mp-accent); }
.mp-toggle-line.on .mp-toggle::after { transform: translateX(0.8rem); background: var(--mp-accent); }
.mp-field-entries input:focus-visible + .mp-toggle { outline: 2px solid var(--mp-accent); outline-offset: 1px; }

/* Advanced per-field settings (public label, help text, options, explicit None, remove). */
.mp-field-adv { flex: 0 0 auto; margin-left: auto; }
.mp-field-adv[open] { flex: 1 1 100%; margin-left: 0; }
.mp-field-adv > summary { list-style: none; }
.mp-field-adv > summary::-webkit-details-marker { display: none; }
.mp-field-adv-body { grid-column: 1 / -1; display: flex; flex-direction: column; gap: 0.35rem;
    margin: 0.5rem 0 0.2rem; padding: 0.7rem 0.85rem; background: var(--mp-bg); border: 1px solid var(--mp-border);
    border-radius: 8px; }
.mp-field-adv-body label.mp-muted { font-size: 0.75rem; }
.mp-field-adv-body .form-control { max-width: 26rem; }
.mp-field-adv-body form { margin-top: 0.2rem; }

/* Builder footer: add-field / form-options panels + save-draft. */
.mp-builder-foot { display: flex; flex-wrap: wrap; gap: 0.5rem; align-items: flex-start; margin-top: 0.85rem; }
.mp-tool-panel { border: 1px solid var(--mp-border); border-radius: 8px; }
.mp-tool-panel[open] { flex: 1 1 100%; padding: 0.2rem 0.85rem 0.85rem; }
.mp-tool-panel > summary { display: inline-block; list-style: none; margin: 0; }
.mp-tool-panel > summary::-webkit-details-marker { display: none; }
.mp-tool-panel:not([open]) { border: 0; }
.mp-builder-save { margin-left: auto; display: flex; align-items: center; gap: 0.6rem; }
.mp-builder-savenote { font-size: 0.78rem; }
.mp-form-options { display: flex; flex-direction: column; gap: 0.6rem; max-width: 32rem; }
.mp-form-dep { background: color-mix(in srgb, var(--mp-accent) 8%, var(--mp-surface));
    border: 1px solid var(--mp-border); border-radius: 8px; padding: 0.5rem 0.7rem; }
.mp-form-dep-note { font-size: 0.82rem; }
/* Custom-field options input appears only for select types (pure-CSS :has, no interactivity). */
.mp-cf-options { display: none; }
.mp-cf-panel:has(.mp-cf-type option[value="SingleSelect"]:checked) .mp-cf-options,
.mp-cf-panel:has(.mp-cf-type option[value="MultiSelect"]:checked) .mp-cf-options { display: block; }

/* ---- §7.5 Live preview pane ---- */
.mp-preview { position: sticky; top: 0.75rem; border: 1px solid var(--mp-border); border-radius: 12px; padding: 0.85rem; background: var(--mp-surface); }
@media (max-width: 1080px) { .mp-preview { position: static; } }
.mp-vis-hidden { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
.mp-preview-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 0.5rem; margin-bottom: 0.6rem; }
.mp-preview-head h4 { margin: 0; }
.mp-preview-mode { font-size: 0.75rem; }
.mp-seg { display: inline-flex; border: 1px solid var(--mp-border); border-radius: 8px; overflow: hidden; }
.mp-seg label { padding: 0.28rem 0.6rem; font-size: 0.78rem; cursor: pointer; color: var(--mp-muted); border-left: 1px solid var(--mp-border); }
.mp-seg label:first-of-type { border-left: 0; }
#mp-pw-desktop:checked ~ .mp-preview-head .mp-seg label[for="mp-pw-desktop"],
#mp-pw-mobile:checked ~ .mp-preview-head .mp-seg label[for="mp-pw-mobile"] { background: var(--mp-accent); color: #1a1300; font-weight: 700; }
#mp-pw-desktop:focus-visible ~ .mp-preview-head .mp-seg label[for="mp-pw-desktop"],
#mp-pw-mobile:focus-visible ~ .mp-preview-head .mp-seg label[for="mp-pw-mobile"] { outline: 2px solid var(--mp-accent); outline-offset: -2px; }
.mp-preview-window { transition: max-width 0.15s ease; }
#mp-pw-mobile:checked ~ .mp-preview-window { max-width: 390px; margin-inline: auto; }
.mp-preview-mode::after { content: " · desktop width"; }
#mp-pw-mobile:checked ~ .mp-preview-head .mp-preview-mode::after { content: " · mobile width"; }
.mp-preview-title { display: flex; flex-direction: column; margin-bottom: 0.6rem; }
.mp-preview-title span { font-size: 0.75rem; }

/* ---- §7.6 Compact "at rest" tool panels (livestream import, record book) ---- */
.mp-tool-disclosure > summary { list-style: none; cursor: pointer; }
.mp-tool-disclosure > summary::-webkit-details-marker { display: none; }
.mp-compact-row { display: flex; align-items: flex-start; gap: 0.85rem; padding: 0.15rem 0; }
.mp-compact-icon { flex: 0 0 auto; width: 2.2rem; height: 2.2rem; border-radius: 8px; display: flex; align-items: center;
    justify-content: center; background: var(--mp-surface-2); border: 1px solid var(--mp-border); font-size: 1.1rem; }
.mp-compact-main { flex: 1 1 auto; min-width: 0; }
.mp-compact-main h3 { margin: 0; }
.mp-compact-main p { margin: 0.15rem 0 0.4rem; font-size: 0.82rem; }
.mp-compact-meta { display: flex; align-items: center; gap: 0.6rem; flex-wrap: wrap; font-size: 0.8rem; }
.mp-compact-cue { flex: 0 0 auto; align-self: center; }
.mp-tool-disclosure[open] .mp-compact-cue { display: none; }
.mp-tool-disclosure[open] .mp-compact-row { border-bottom: 1px solid var(--mp-border); padding-bottom: 0.7rem; margin-bottom: 0.2rem; }
.mp-tool-detail { padding-top: 0.4rem; }

/* ---- Entries tab (director-ui-spec §8) — reuses the shared .mp-* tokens and the WP2 .mp-data-grid/.mp-dg-*
   foundation as-is; only Entries-specific chrome (counts, payment banner, chips, column chooser, row menu, edit
   drawer) is defined here. Rows hidden by the global search / status chips use !important so they win over the
   inline display data-grid.js sets for its own per-column filters (the two compose). */
.mp-e-filtered-out { display: none !important; }

.mp-e-flash { padding: 0.5rem 0.8rem; }
.mp-e-header { display: flex; justify-content: flex-end; margin-bottom: 0.75rem; }
.mp-e-header-actions { display: flex; gap: 0.5rem; flex-wrap: wrap; align-items: center; }

/* Payment banner (§8.2) — a compact <details> whose summary is the status line. */
.mp-e-pay-banner { padding: 0; margin-bottom: 0.9rem; overflow: hidden; }
.mp-e-pay-banner > summary { list-style: none; cursor: pointer; display: flex; align-items: center; gap: 0.7rem; padding: 0.7rem 0.9rem; }
.mp-e-pay-banner > summary::-webkit-details-marker { display: none; }
.mp-e-pay-banner.is-ok { border-color: color-mix(in srgb, var(--mp-good) 45%, var(--mp-border)); }
.mp-e-pay-banner.is-warn { border-color: color-mix(in srgb, var(--mp-accent) 55%, var(--mp-border)); }
.mp-e-pay-icon { flex: 0 0 auto; width: 1.5rem; height: 1.5rem; border-radius: 50%; display: grid; place-items: center;
    font-weight: 900; color: #08261a; background: var(--mp-good); }
.mp-e-pay-banner.is-warn .mp-e-pay-icon { background: var(--mp-accent); color: #241a00; }
.mp-e-pay-text { display: flex; flex-direction: column; }
.mp-e-pay-text .mp-muted { font-size: 0.8rem; }
.mp-e-pay-manage { margin-left: auto; white-space: nowrap; }
.mp-e-pay-body { padding: 0 0.9rem 0.9rem; border-top: 1px solid var(--mp-border); }

/* Counts strip (§8.1). */
.mp-e-counts { display: flex; align-items: stretch; padding: 0; overflow-x: auto; margin-bottom: 0.9rem; }
.mp-e-count { min-width: 118px; flex: 1; padding: 0.7rem 0.9rem; border-right: 1px solid var(--mp-border); white-space: nowrap; }
.mp-e-count:last-child { border-right: 0; }
.mp-e-count strong { font-size: 1.2rem; margin-right: 0.35rem; }
.mp-e-count span { color: var(--mp-muted); font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.05em; }

/* Toolbar: search + status chips + column chooser (§8.3/§8.8). */
.mp-e-toolbar { display: flex; align-items: center; gap: 0.55rem; margin-bottom: 0.6rem; flex-wrap: wrap; }
.mp-e-search { flex: 1 1 220px; max-width: 22rem; }
.mp-e-search input { width: 100%; height: 2.3rem; border-radius: 8px; border: 1px solid var(--mp-border);
    background: var(--mp-bg); color: var(--mp-text); padding: 0 0.7rem; }
.mp-e-search input:focus { outline: none; border-color: var(--mp-accent); }
.mp-e-chips { display: flex; align-items: center; gap: 0.3rem; flex-wrap: wrap; }
.mp-e-chip { height: 2.1rem; padding: 0 0.7rem; background: transparent; border: 1px solid var(--mp-border);
    border-radius: 8px; color: var(--mp-muted); cursor: pointer; font-size: 0.75rem; font-weight: 700; }
.mp-e-chip:hover { color: var(--mp-text); }
.mp-e-chip.is-active { color: var(--mp-text); background: var(--mp-surface-2); border-color: var(--mp-accent); }
.mp-e-toolbar-spacer { flex: 1 1 auto; }

/* Column chooser popover (§8.6) — reuses .mp-overflow/.mp-overflow-menu; widened for the grouped list. */
.mp-e-columns .mp-overflow-menu { min-width: 19rem; padding: 0; }
.mp-e-columns-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 0.5rem;
    padding: 0.7rem 0.8rem; border-bottom: 1px solid var(--mp-border); }
.mp-e-columns-body { max-height: 22rem; overflow: auto; padding: 0.35rem; }
.mp-e-columns-section { padding: 0.5rem 0.5rem 0.25rem; color: var(--mp-muted); text-transform: uppercase;
    letter-spacing: 0.07em; font-size: 0.62rem; font-weight: 800; }
.mp-e-column-option { display: flex; align-items: center; gap: 0.6rem; min-height: 2.2rem; padding: 0.3rem 0.5rem; border-radius: 6px; }
.mp-e-column-option:hover { background: var(--mp-surface-2); }
.mp-e-column-option.is-locked { opacity: 0.75; }
.mp-e-column-label { flex: 1; font-size: 0.82rem; }
.mp-e-column-option small { color: var(--mp-muted); font-size: 0.68rem; white-space: nowrap; }
.mp-e-lock { color: var(--mp-accent); font-size: 0.7rem; }
/* Toggle switch (a submit button that immediately persists the choice). */
.mp-e-switch { flex: 0 0 auto; width: 2rem; height: 1.15rem; border-radius: 999px; border: 1px solid var(--mp-border);
    background: var(--mp-bg); cursor: pointer; position: relative; padding: 0; }
.mp-e-switch::after { content: ""; position: absolute; top: 1px; left: 1px; width: 0.9rem; height: 0.9rem;
    border-radius: 50%; background: var(--mp-muted); transition: transform 0.12s ease, background 0.12s ease; }
.mp-e-switch.on { background: color-mix(in srgb, var(--mp-accent) 35%, var(--mp-bg)); border-color: var(--mp-accent); }
.mp-e-switch.on::after { transform: translateX(0.85rem); background: var(--mp-accent); }
.mp-e-switch:focus-visible { outline: 2px solid var(--mp-accent); outline-offset: 2px; }

/* Grid cell rendering. */
.mp-entries-grid .mp-e-col-lifter { min-width: 15rem; }
.mp-entries-grid .mp-e-muted { color: var(--mp-muted); }
.mp-e-person { display: flex; align-items: center; gap: 0.55rem; }
.mp-e-avatar { flex: 0 0 auto; width: 1.7rem; height: 1.7rem; border-radius: 50%; display: grid; place-items: center;
    font-size: 0.62rem; font-weight: 800; color: #fff; background: linear-gradient(135deg, #4e5d73, #232b39); }
.mp-e-person-name { font-weight: 700; }
.mp-e-sub { color: var(--mp-muted); font-size: 0.7rem; margin-top: 0.15rem; }
.mp-e-status { display: inline-flex; align-items: center; gap: 0.4rem; font-weight: 700; white-space: nowrap; }
.mp-e-status i { flex: 0 0 auto; width: 0.5rem; height: 0.5rem; border-radius: 50%; background: var(--mp-muted); }
.mp-e-status.confirmed i, .mp-e-status.paid i { background: var(--mp-good); }
.mp-e-status.pending i { background: var(--mp-accent); }
.mp-e-status.wait i { background: var(--mp-info); }

/* Row actions + overflow menu. */
.mp-e-actions-cell { white-space: nowrap; }
.mp-e-row-actions { display: flex; align-items: center; gap: 0.3rem; }
.mp-e-mini { height: 1.9rem; padding: 0 0.55rem; font-size: 0.72rem; }
.mp-e-mini.primary { background: var(--mp-accent); color: #1a1300; border-color: var(--mp-accent); font-weight: 800; }
.mp-e-more { font-weight: 800; letter-spacing: 0.05em; }
.mp-e-row-menu .mp-overflow-menu { min-width: 9rem; }

/* Grid footer. */
.mp-e-gridfoot { display: flex; align-items: center; justify-content: space-between; gap: 1rem; flex-wrap: wrap;
    font-size: 0.72rem; padding: 0.5rem 0.2rem 0; }

/* Edit drawer (§8.9). */
.mp-e-drawer-scrim { position: fixed; inset: 0; z-index: 60; background: rgba(0,0,0,0.5); display: flex; justify-content: flex-end; }
.mp-e-drawer { width: min(40rem, 100%); height: 100%; overflow-y: auto; background: var(--mp-surface);
    border-left: 1px solid var(--mp-border); padding: 1.1rem 1.2rem; box-shadow: -14px 0 40px rgba(0,0,0,0.45); }
.mp-e-drawer-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 0.5rem; }
.mp-e-drawer-head h3 { margin: 0.15rem 0 0; }
.mp-e-drawer-body { display: grid; grid-template-columns: 1fr 1fr; gap: 1.1rem; margin-top: 0.6rem; }
.mp-e-original, .mp-e-correction { min-width: 0; }
.mp-e-original h4, .mp-e-correction h4 { margin: 0 0 0.5rem; }
.mp-e-original { background: var(--mp-bg); border: 1px solid var(--mp-border); border-radius: 10px; padding: 0.75rem 0.85rem; }
.mp-e-fieldlist { display: grid; grid-template-columns: auto 1fr; gap: 0.3rem 0.7rem; margin: 0; font-size: 0.82rem; }
.mp-e-fieldlist dt { color: var(--mp-muted); }
.mp-e-fieldlist dd { margin: 0; word-break: break-word; }
/* Email notifications WP4 (spec §4.6) — last-notification pill inside the edit drawer's "Original at entry" panel. */
.mp-e-notify-pill { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; font-size: 0.8rem; }

@media (max-width: 720px) {
    .mp-e-drawer-body { grid-template-columns: 1fr; }
    .mp-e-drawer { width: 100%; }
    .mp-e-toolbar { align-items: stretch; }
    .mp-e-search { max-width: none; }
}

/* ==== Scoreboard/Livestream WP4: Setup-tab "Livestreams" panel (spec §5.2) ====
   Session-grouped card list; one row per active platform. Renders inside .mp-setup-scope, so the dark
   .form-control/select/input tokens defined near the top of this file already apply — only this panel's own
   layout (grid rows, compact fields, advanced disclosure) is defined here. */
.mp-ls-session {
    border: 1px solid var(--mp-border); border-radius: 12px; background: var(--mp-nested-surface, var(--mp-surface-2));
    margin-bottom: 0.85rem; overflow: hidden;
}
.mp-ls-session:last-child { margin-bottom: 0; }
.mp-ls-session-head {
    display: flex; align-items: flex-start; justify-content: space-between; gap: 0.6rem;
    padding: 0.7rem 0.85rem; border-bottom: 1px solid var(--mp-border);
}
.mp-ls-session-head h4 { margin: 0; font-size: 0.92rem; }
.mp-ls-session-head p { margin: 0.2rem 0 0; font-size: 0.75rem; }
.mp-ls-row {
    display: grid; grid-template-columns: 7rem minmax(0,1.6fr) minmax(200px,1.3fr) 7.5rem 10rem auto;
    gap: 0.6rem; align-items: end; padding: 0.75rem 0.85rem;
    border-bottom: 1px solid color-mix(in srgb, var(--mp-border) 70%, transparent);
}
.mp-ls-row:last-of-type { border-bottom: 0; }
.mp-ls-field label { display: block; font-size: 0.66rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em; margin: 0 0 0.25rem; }
.mp-ls-static { min-height: 2.2rem; display: flex; align-items: center; font-weight: 650; font-size: 0.85rem; }
/* Video start's plain-text dd/mm/yyyy hh:mm am input (no browser-native widget to size it) — width:100% already
   comes from .mp-setup-scope .form-control, but a grid item's default min-width:auto still sizes to the input's
   own min-content, which can push the row wider than its 1fr track at the narrow single-column breakpoint below. */
.mp-ls-field input.form-control { min-width: 0; }
.mp-ls-actions { display: flex; gap: 0.35rem; flex-wrap: wrap; align-items: center; grid-column: 1 / -1; margin-top: 0.15rem; }
.mp-ls-actions .mp-btn, .mp-ls-actions a.mp-btn, .mp-ls-actions span.mp-btn { white-space: nowrap; }
.mp-ls-advanced { grid-column: 1 / -1; margin-top: 0.35rem; }
.mp-ls-advanced > summary { cursor: pointer; font-size: 0.72rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em; list-style: none; color: var(--mp-muted); }
.mp-ls-advanced > summary::-webkit-details-marker { display: none; }
.mp-ls-advanced label { display: inline-block; margin: 0.4rem 0.5rem 0.4rem 0; font-size: 0.78rem; }

/* Video start's D-6 advisory (workflow-repair ADR) — role="status", never role="alert" (that stays the existing
   inline-styled .mp-ls-field-error above), so it must read as neither an error nor a success. Amber, same family as
   .mp-badge.warn/.mp-oplx-notice.warn, but its own small pill rather than a bare colored line so it is visually
   distinct from the red field-error text sitting right above it in the same field. Never disables anything below it. */
.mp-ls-field-warning {
    display: block; margin-top: 0.3rem; padding: 0.3rem 0.5rem; border-radius: 6px;
    border: 1px solid color-mix(in srgb, var(--mp-accent) 45%, transparent);
    background: color-mix(in srgb, var(--mp-accent) 10%, transparent);
    color: var(--mp-accent); font-size: 0.72rem; font-weight: 650;
}
@media (max-width: 1099px) { .mp-ls-row { grid-template-columns: 1fr 1fr; } }
@media (max-width: 640px) { .mp-ls-row { grid-template-columns: 1fr; } }

/* Playback timing summary cell (light-sync spec §5.8) — occupies the row grid's spare `auto` track above, so no
   .mp-ls-row column change was needed. Reuses .mp-badge good/warn, same as every other status pill in this file. */
.mp-lsync-summary { display: flex; align-items: center; gap: 0.4rem; min-height: 2.2rem; font-weight: 650; font-size: 0.85rem; flex-wrap: wrap; }
.mp-lsync-using { display: block; font-size: 0.7rem; margin-top: 0.15rem; }

/* ==== Light-sync WP (Sonnet slice): LivestreamSyncLauncher's guided synchronization dialog ====
   Native <dialog> chrome, same shape/reasoning as .mp-capability-dialog/.mp-undo-dialog/.mp-refmode-dialog
   elsewhere in this file (WP0 §2 rule 6 — no new dialog chrome framework). Reuses --mp-* tokens, .mp-btn/.mp-badge/
   .mp-light throughout; only this dialog's own layout (step bar, two-column body, seek panel, candidate list,
   calculation card) is new. Full-screen below 720px per the mock-up's own breakpoint. */
.mp-lsync-dialog {
    width: min(64rem, calc(100vw - 2rem)); max-width: 64rem; max-height: calc(100vh - 3rem);
    padding: 0; margin: auto; overflow: hidden;
    border: 1px solid var(--mp-border); border-radius: 16px; background: var(--mp-bg, #0d1117); color: var(--mp-text);
    box-shadow: 0 24px 70px rgba(0, 0, 0, 0.5);
}
/* CRITICAL: display must stay the UA default (none when closed) so an author rule never re-shows a closed native
   <dialog> in normal document flow. This component's row lives inside .mp-ls-actions alongside the panel's own
   Preview/Save/Clear buttons — an always-flex dialog silently overlaid and intercepted every click on them (caught
   by LivestreamSetupUiTests's pointer-interception failures). Flex layout only turns on once showModal() sets
   [open]; .mp-capability-dialog/.mp-undo-dialog elsewhere in this file avoid the bug by never setting `display` at
   all — this one needs an explicit flex column for its head/steps/body/footer stack, so it is scoped to [open]. */
.mp-lsync-dialog[open] { display: flex; flex-direction: column; }
.mp-lsync-dialog::backdrop { background: rgba(2, 4, 7, 0.78); }
.mp-lsync-head {
    display: flex; align-items: flex-start; gap: 0.9rem; padding: 1rem 1.1rem;
    border-bottom: 1px solid var(--mp-border); background: var(--mp-surface); flex: 0 0 auto;
}
.mp-lsync-head-title h2 { margin: 0; font-size: 1.15rem; }
.mp-lsync-head-title p { margin: 0.2rem 0 0; color: var(--mp-muted); font-size: 0.78rem; }
.mp-lsync-head .mp-badge { margin-left: auto; white-space: normal; text-align: right; }
/* light-sync spec §6: >=44 CSS px pointer targets. */
.mp-lsync-icon-btn {
    width: 2.75rem; height: 2.75rem; flex: 0 0 auto; border-radius: 8px; border: 1px solid var(--mp-border);
    background: var(--mp-surface-2); color: var(--mp-text); cursor: pointer; font-size: 1.2rem; line-height: 1;
}
.mp-lsync-icon-btn:disabled { opacity: 0.45; cursor: default; }

.mp-lsync-steps {
    display: grid; grid-template-columns: repeat(3, 1fr); gap: 0.6rem;
    padding: 0.7rem 1.1rem; border-bottom: 1px solid var(--mp-border); background: var(--mp-bg, #0d1117); flex: 0 0 auto;
}
.mp-lsync-step { display: flex; align-items: center; gap: 0.5rem; min-width: 0; color: var(--mp-muted); font-size: 0.78rem; font-weight: 750; }
.mp-lsync-step-num {
    width: 1.5rem; height: 1.5rem; flex: 0 0 1.5rem; border-radius: 50%; display: grid; place-items: center;
    border: 1px solid var(--mp-border); background: var(--mp-surface);
}
.mp-lsync-step.active { color: var(--mp-text); }
.mp-lsync-step.active .mp-lsync-step-num { background: var(--mp-accent); color: #1a1300; border-color: var(--mp-accent); }
.mp-lsync-step.done { color: var(--mp-good); }
.mp-lsync-step.done .mp-lsync-step-num { background: color-mix(in srgb, var(--mp-good) 18%, transparent); border-color: var(--mp-good); color: var(--mp-good); }

.mp-lsync-banner.error { margin: 0.8rem 1.1rem 0; padding: 0.6rem 0.8rem; border-radius: 8px; color: var(--mp-nolift); background: color-mix(in srgb, var(--mp-nolift) 12%, transparent); border: 1px solid color-mix(in srgb, var(--mp-nolift) 40%, transparent); font-size: 0.82rem; font-weight: 650; }
.mp-lsync-loading, .mp-lsync-empty { margin: 1rem 1.1rem; color: var(--mp-muted); font-size: 0.85rem; }
.mp-lsync-empty { padding: 0.9rem; border: 1px dashed var(--mp-border); border-radius: 10px; }

.mp-lsync-body { overflow: auto; padding: 1rem 1.1rem; display: grid; grid-template-columns: minmax(0, 1.3fr) minmax(19rem, 0.9fr); gap: 1rem; flex: 1 1 auto; }
.mp-lsync-player-card, .mp-lsync-reference-card, .mp-lsync-candidates-card, .mp-lsync-calc-card {
    border: 1px solid var(--mp-border); border-radius: 12px; background: var(--mp-surface); overflow: hidden;
}
.mp-lsync-right-col { display: flex; flex-direction: column; gap: 0.85rem; min-width: 0; }
.mp-lsync-section-head { display: flex; align-items: center; gap: 0.6rem; padding: 0.65rem 0.8rem; border-bottom: 1px solid var(--mp-border); }
.mp-lsync-section-head h3 { margin: 0; font-size: 0.85rem; }
.mp-lsync-help { margin-left: auto; color: var(--mp-muted); font-size: 0.7rem; }
.mp-lsync-field-label { display: block; color: var(--mp-muted); font-size: 0.66rem; text-transform: uppercase; letter-spacing: 0.06em; font-weight: 800; margin-bottom: 0.3rem; }

.mp-lsync-video { position: relative; aspect-ratio: 16 / 9; background: #000; }
.mp-lsync-video [data-lsync-player-host] { position: absolute; inset: 0; width: 100%; height: 100%; }
/* android-handler-lift-player-crash WP1: the JS-owned mount div (and the real <iframe> the IFrame API replaces it
   with) must fill the Blazor-owned host above — the host itself is never given directly to YT.Player any more. */
.mp-lsync-video [data-lsync-player-host] > .mp-lsync-player-mount,
.mp-lsync-video [data-lsync-player-host] > iframe { width: 100%; height: 100%; border: 0; display: block; }
.mp-lsync-player-error { margin: 0; padding: 0.6rem 0.8rem; color: var(--mp-nolift); font-size: 0.78rem; background: color-mix(in srgb, var(--mp-nolift) 10%, transparent); }
.mp-lsync-hint { margin: 0; padding: 0.55rem 0.8rem; color: var(--mp-muted); font-size: 0.75rem; border-top: 1px solid var(--mp-border); }

.mp-lsync-seek-panel { padding: 0.75rem 0.8rem; border-top: 1px solid var(--mp-border); display: flex; align-items: center; gap: 0.8rem; flex-wrap: wrap; }
.mp-lsync-seek-group { display: flex; gap: 0.35rem; flex-wrap: wrap; }
.mp-lsync-seek-btn {
    min-width: 2.75rem; min-height: 2.75rem; border-radius: 8px; border: 1px solid var(--mp-border);
    background: var(--mp-surface-2); color: var(--mp-text); cursor: pointer; font-size: 0.75rem; font-weight: 800;
}
.mp-lsync-seek-btn:disabled { opacity: 0.45; cursor: default; }
.mp-lsync-seek-btn:hover:not(:disabled) { border-color: var(--mp-accent); }
.mp-lsync-time-readout { margin-left: auto; text-align: right; }
.mp-lsync-time-readout strong { font-variant-numeric: tabular-nums; font-size: 1.05rem; }

.mp-lsync-capture-strip { padding: 0.75rem 0.8rem; border-top: 1px solid var(--mp-border); display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 0.8rem; align-items: center; background: color-mix(in srgb, var(--mp-info) 6%, transparent); }
.mp-lsync-capture-strip p { margin: 0; color: var(--mp-muted); font-size: 0.75rem; }

.mp-lsync-reference-body { padding: 0.8rem; }
.mp-lsync-selected-lift { display: flex; align-items: center; gap: 0.7rem; }
.mp-lsync-lights { display: inline-flex; gap: 0.3rem; flex: 0 0 auto; }
/* A Run Board reference's result badge stands in for the three light circles (workflow-repair ADR D-4/D-7) — sized
   up from the base .mp-badge so it reads as the headline evidence, same visual weight the lights would have had. */
.mp-lsync-decision-badge { font-size: 0.85rem; padding: 0.3rem 0.75rem; flex: 0 0 auto; }
.mp-lsync-kind-note { margin: 0.5rem 0 0; color: var(--mp-muted); font-size: 0.72rem; font-style: italic; }
.mp-lsync-meta-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 0.6rem; margin-top: 0.75rem; }
.mp-lsync-meta-cell { background: var(--mp-bg, #0d1117); border: 1px solid var(--mp-border); border-radius: 9px; padding: 0.5rem 0.6rem; }
.mp-lsync-meta-cell span { display: block; color: var(--mp-muted); font-size: 0.62rem; text-transform: uppercase; letter-spacing: 0.05em; font-weight: 800; }
.mp-lsync-meta-cell strong { display: block; margin-top: 0.15rem; font-size: 0.82rem; font-variant-numeric: tabular-nums; }

.mp-lsync-candidates { max-height: 13rem; overflow: auto; }
.mp-lsync-candidate {
    display: grid; grid-template-columns: auto minmax(0, 1fr) auto; gap: 0.6rem; align-items: center;
    padding: 0.55rem 0.8rem; border-bottom: 1px solid color-mix(in srgb, var(--mp-border) 70%, transparent);
    cursor: pointer; min-height: 2.75rem;
}
.mp-lsync-candidate:last-child { border-bottom: 0; }
.mp-lsync-candidate:hover { background: color-mix(in srgb, var(--mp-accent) 6%, transparent); }
.mp-lsync-candidate.selected { background: color-mix(in srgb, var(--mp-info) 14%, transparent); box-shadow: inset 3px 0 0 var(--mp-info); }
.mp-lsync-candidate input[type="radio"] { width: 1.15rem; height: 1.15rem; margin: 0; accent-color: var(--mp-info); }
.mp-lsync-candidate-copy strong { display: block; font-size: 0.78rem; }
.mp-lsync-candidate-copy span { display: flex; align-items: center; gap: 0.35rem; flex-wrap: wrap; color: var(--mp-muted); font-size: 0.72rem; margin-top: 0.2rem; }
.mp-lsync-candidate-time { color: var(--mp-muted); font-size: 0.72rem; font-variant-numeric: tabular-nums; }

/* Per-candidate source badge (workflow-repair ADR D-7) — a shrunk .mp-badge so it sits inline with the weight/result
   text instead of dominating the compact candidate row; .blue for Run Board matches this file's existing
   .mp-badge.blue accent, distinguishing "recorded on the desk" from the two physical-light kinds at a glance. */
.mp-badge.small { font-size: 0.6rem; padding: 0.08rem 0.4rem; letter-spacing: 0.03em; }

.mp-lsync-calc-body { padding: 0.8rem; }
.mp-lsync-calc-row { display: flex; justify-content: space-between; gap: 0.7rem; color: var(--mp-muted); font-size: 0.78rem; padding: 0.25rem 0; }
.mp-lsync-calc-row strong { color: var(--mp-text); font-variant-numeric: tabular-nums; }
.mp-lsync-calc-divider { height: 1px; background: var(--mp-border); margin: 0.5rem 0; }
.mp-lsync-calc-row.result { font-size: 0.85rem; align-items: center; }
.mp-lsync-calc-row.result strong { color: var(--mp-accent); font-size: 1.05rem; }
.mp-lsync-impact { margin-top: 0.65rem; padding: 0.55rem 0.65rem; border-radius: 9px; border: 1px solid color-mix(in srgb, var(--mp-good) 40%, transparent); color: var(--mp-good); background: color-mix(in srgb, var(--mp-good) 10%, transparent); font-size: 0.72rem; }

.mp-lsync-manual { margin-top: 0.65rem; border-top: 1px solid var(--mp-border); padding-top: 0.65rem; }
.mp-lsync-manual summary { color: var(--mp-muted); font-size: 0.72rem; cursor: pointer; list-style: none; }
.mp-lsync-manual summary::-webkit-details-marker { display: none; }
.mp-lsync-manual-row { display: flex; gap: 0.5rem; margin-top: 0.55rem; }
.mp-lsync-manual-row input { flex: 1 1 auto; min-height: 2.5rem; font-variant-numeric: tabular-nums; }
.mp-lsync-manual-error { margin: 0.4rem 0 0; color: var(--mp-nolift); font-size: 0.72rem; }

.mp-lsync-footer {
    border-top: 1px solid var(--mp-border); min-height: 4.4rem; padding: 0.8rem 1.1rem; background: var(--mp-surface);
    display: flex; align-items: center; gap: 0.9rem; flex: 0 0 auto;
}
.mp-lsync-footer-status { color: var(--mp-muted); font-size: 0.75rem; min-width: 0; }
.mp-lsync-footer-status strong { color: var(--mp-text); display: block; margin-bottom: 0.15rem; }
.mp-lsync-footer-actions { margin-left: auto; display: flex; gap: 0.55rem; flex: 0 0 auto; }
.mp-lsync-footer-actions .mp-btn { min-width: 8rem; min-height: 2.75rem; }

@media (max-width: 900px) {
    .mp-lsync-body { grid-template-columns: minmax(0, 1fr); }
}
@media (max-width: 720px) {
    .mp-lsync-dialog { width: 100%; max-width: 100%; height: 100%; max-height: 100%; margin: 0; border: 0; border-radius: 0; }
    .mp-lsync-head { padding: 0.85rem 0.9rem; }
    .mp-lsync-steps { padding: 0.55rem 0.9rem; }
    .mp-lsync-step { font-size: 0; gap: 0.35rem; }
    .mp-lsync-step-num { font-size: 0.78rem; }
    .mp-lsync-step::after { content: attr(data-short); font-size: 0.68rem; }
    .mp-lsync-body { padding: 0.8rem; }
    .mp-lsync-capture-strip { grid-template-columns: 1fr; }
    .mp-lsync-capture-strip .mp-btn { width: 100%; }
    .mp-lsync-time-readout { width: 100%; margin-left: 0; text-align: left; }
    .mp-lsync-footer { flex-direction: column; align-items: stretch; }
    .mp-lsync-footer-actions { margin-left: 0; }
    .mp-lsync-footer-actions .mp-btn { flex: 1; }
}

/* ==== Scoreboard/Livestream WP4: web lift player (spec §3.3/§4.3) — /meets/{id}/lifts/{attemptId} ==== */
.mp-lift-player { max-width: 40rem; margin: 0 auto; padding: 1rem 0 3rem; }
.mp-lp-back { display: inline-block; margin-bottom: 0.75rem; }
.mp-lp-frame {
    position: relative; aspect-ratio: 16 / 9; border-radius: 14px; overflow: hidden;
    background: linear-gradient(155deg, #151a25, #030405); border: 1px solid var(--mp-border);
    display: grid; place-items: center;
}
.mp-lp-iframe { width: 100%; height: 100%; border: 0; }
.mp-lp-play {
    width: 4.5rem; height: 4.5rem; min-width: 44px; min-height: 44px; border-radius: 50%;
    border: 1px solid rgba(255,255,255,0.33); background: rgba(9,11,13,0.85); color: #fff; font-size: 1.6rem;
    padding-left: 0.3rem; cursor: pointer; box-shadow: 0 10px 30px rgba(0,0,0,0.6);
}
.mp-lp-cliptag { position: absolute; bottom: 0.7rem; left: 0.7rem; border-radius: 7px; background: rgba(0,0,0,0.7); padding: 0.3rem 0.5rem; font-size: 0.72rem; color: #fff; }
.mp-lp-frame-empty { padding: 1.5rem; text-align: center; }
/* Missing-Bars-Loaded fallback timing: a restrained amber note, never a control — the per-viewer snippet
   adjustment lives in the mobile player's overflow menu, not permanently beside the web player. */
.mp-lp-fallbacktag { position: absolute; bottom: 0.7rem; right: 0.7rem; border-radius: 7px; background: rgba(87,57,0,0.85); border: 1px solid rgba(255,200,87,0.32); color: #ffe7ad; padding: 0.3rem 0.5rem; font-size: 0.68rem; font-weight: 700; }
.mp-lp-missing { color: var(--mp-warn, #ffc857); }
.mp-lp-fallbacknote { margin: 0.55rem 0 0; font-size: 0.76rem; }
.mp-lp-fallback { display: inline-block; margin-top: 0.5rem; font-size: 0.78rem; }
.mp-lp-title { display: flex; justify-content: space-between; align-items: flex-start; gap: 0.75rem; margin-top: 1rem; }
.mp-lp-title h2 { margin: 0 0 0.2rem; }
.mp-lp-result { font-weight: 800; font-size: 0.85rem; white-space: nowrap; }
.mp-lp-result.good { color: var(--mp-good); }
.mp-lp-result.bad { color: var(--mp-nolift); }
.mp-lp-metarow { display: grid; grid-template-columns: repeat(3, 1fr); gap: 0.6rem; margin-top: 0.85rem; }
.mp-lp-metarow div { background: var(--mp-surface-2); border: 1px solid var(--mp-border); border-radius: 10px; padding: 0.55rem 0.7rem; }
.mp-lp-metarow small { display: block; color: var(--mp-muted); font-size: 0.68rem; text-transform: uppercase; letter-spacing: 0.04em; }
.mp-lp-metarow b { font-size: 0.92rem; }
.mp-lp-nav { display: flex; justify-content: space-between; gap: 0.6rem; margin-top: 1rem; }
.mp-lp-nav .mp-btn { min-height: 44px; display: inline-flex; align-items: center; }
.mp-lp-others { margin-top: 1.25rem; }
.mp-lp-others h3 { margin: 0 0 0.5rem; font-size: 0.85rem; }
.mp-lp-others-strip { display: flex; gap: 0.6rem; overflow-x: auto; padding-bottom: 0.3rem; }
.mp-lp-mini {
    min-width: 8.5rem; border: 1px solid var(--mp-border); border-radius: 10px; background: var(--mp-surface-2);
    padding: 0.6rem 0.7rem; text-decoration: none; color: var(--mp-text); flex: 0 0 auto; display: block;
}
.mp-lp-mini.active { border-color: var(--mp-accent); background: color-mix(in srgb, var(--mp-accent) 12%, var(--mp-surface-2)); }
.mp-lp-mini b { display: block; font-size: 0.78rem; font-weight: 700; }
.mp-lp-mini small { display: block; color: var(--mp-muted); font-size: 0.68rem; margin-top: 0.25rem; }
@media (max-width: 500px) {
    .mp-lift-player { padding: 0.5rem 0.75rem 3rem; }
    .mp-lp-metarow { grid-template-columns: 1fr 1fr; }
}

/* ==== Completion WP1b+WP2: home, auth, onboarding, account & security (docs/specs/completion) ====
   New surfaces only — reuses --mp-* tokens and the existing .mp-card/.mp-btn/.mp-badge/.mp-muted system
   throughout (WP0 §2 rule 5). Dark form-control treatment mirrors the Setup redesign's .mp-setup-scope rules
   (same --mp-control-* tokens, same states) but scoped under .mp-auth-scope so Login/Register/Onboarding/
   Devices get properly themed inputs without touching any other page. Also reused as-is (WP8 completion fix,
   spec §5.1) on the director's manual-entry form (ManualEntryPage.razor) and the public results filter bar
   (Results.razor) — same harsh-white-input problem, same fix, no new CSS needed. */

.mp-auth-scope .form-control,
.mp-auth-scope .mp-multiselect > summary.msd-control {
    display: block; width: 100%; min-height: 2.6rem; padding: 0 0.75rem; color: var(--mp-text);
    background: var(--mp-control-bg); border: 1px solid var(--mp-control-border); border-radius: 8px;
    box-shadow: inset 0 1px 1px rgba(0,0,0,0.2); outline: none;
    transition: border-color .14s ease, background-color .14s ease, box-shadow .14s ease;
}
.mp-auth-scope .form-control::placeholder { color: var(--mp-control-placeholder); opacity: 1; }
.mp-auth-scope .form-control:hover:not(:disabled):not([readonly]) { background: var(--mp-control-bg-hover); border-color: #435164; }
.mp-auth-scope .form-control:focus-visible, .mp-auth-scope .form-control:focus {
    border-color: var(--mp-control-border-focus); background: #19212b;
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--mp-control-border-focus) 22%, transparent), inset 0 1px 1px rgba(0,0,0,0.2);
}
.mp-auth-scope .form-control:disabled { opacity: 0.55; cursor: not-allowed; }
.mp-auth-scope .form-control.invalid, .mp-auth-scope .form-control[aria-invalid="true"] {
    border-color: var(--mp-nolift);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--mp-nolift) 18%, transparent), inset 0 1px 1px rgba(0,0,0,0.2);
}
.mp-auth-scope select.form-control {
    appearance: none; -webkit-appearance: none;
    background-image: linear-gradient(45deg, transparent 50%, #7d8999 50%), linear-gradient(135deg, #7d8999 50%, transparent 50%);
    background-position: calc(100% - 15px) 52%, calc(100% - 10px) 52%; background-size: 4px 4px, 4px 4px; background-repeat: no-repeat;
    padding-right: 1.7rem;
}
.mp-auth-scope .validation-message, .mp-auth-scope .mp-field-error {
    display: block; margin-top: 0.3rem; color: var(--mp-nolift); font-size: 0.78rem; font-weight: 700;
}
.mp-auth-scope label.mp-muted { display: block; margin: 0.75rem 0 0.3rem; font-size: 0.78rem; font-weight: 650; }
.mp-auth-scope label.mp-muted:first-child { margin-top: 0; }

.mp-badge.blue { color: var(--mp-info); border-color: var(--mp-info); }

/* ---- Shared inline status panels (errors/notices) — aria-live region content, no card-jump (spec §5.4/§10) ---- */
.mp-auth-error {
    border: 1px solid var(--mp-nolift); background: color-mix(in srgb, var(--mp-nolift) 12%, var(--mp-surface));
    border-radius: 10px; padding: 0.75rem 0.9rem; margin-bottom: 1rem;
}
.mp-auth-error strong { color: var(--mp-nolift); display: block; font-size: 0.85rem; }
.mp-auth-error p { margin: 0.25rem 0 0; color: var(--mp-muted); font-size: 0.8rem; }
.mp-auth-notice {
    border: 1px solid var(--mp-good); background: color-mix(in srgb, var(--mp-good) 12%, var(--mp-surface));
    border-radius: 10px; padding: 0.75rem 0.9rem; margin-bottom: 1rem;
}
.mp-auth-notice strong { color: var(--mp-good); display: block; font-size: 0.85rem; }
.mp-auth-notice p { margin: 0.25rem 0 0; color: var(--mp-muted); font-size: 0.8rem; }
/* Self-service account capabilities WP2: StatusMessage.razor's one-shot banner (the mp-auth-notice reused on
   every page via MainLayout) renders arbitrary caller text inline as a flex:1 child — an unbroken string with no
   natural break points (a long organisation name with no spaces, e.g. "{OrgName} is ready...") forces the whole
   flex row past the viewport at narrow widths without these two rules. min-width:0 lets the flex child actually
   shrink; overflow-wrap:anywhere then lets its own text wrap instead of overflowing. */
[data-status-message] strong { min-width: 0; overflow-wrap: anywhere; }

/* ---- §5.4 Sign-in / create account ---- */
.mp-auth-wrap { max-width: 1180px; margin: 0 auto; }
.mp-auth-layout { display: grid; grid-template-columns: minmax(0, 1.1fr) 460px; gap: 1.75rem; align-items: stretch; margin-top: 1.25rem; }
.mp-auth-story {
    padding: 2.25rem; border-radius: 14px; border: 1px solid var(--mp-border);
    background: linear-gradient(140deg, color-mix(in srgb, var(--mp-accent) 11%, transparent), transparent 45%), var(--mp-surface);
    display: flex; flex-direction: column; justify-content: space-between; gap: 1.5rem;
}
.mp-auth-story h1 { font-size: clamp(1.7rem, 3vw, 2.6rem); line-height: 1.05; letter-spacing: -0.02em; margin: 0.5rem 0 0.75rem; }
.mp-auth-story-top > p { color: #b8c0ca; font-size: 0.98rem; line-height: 1.6; max-width: 34rem; }
.mp-session-preview { display: grid; gap: 0.6rem; margin-top: 0.5rem; }
.mp-session-row {
    display: grid; grid-template-columns: 42px minmax(0, 1fr) auto; gap: 0.75rem; align-items: center;
    padding: 0.7rem; border-radius: 10px; background: rgba(11,14,19,0.45); border: 1px solid var(--mp-border);
}
.mp-device-icon { width: 42px; height: 42px; border-radius: 9px; background: var(--mp-surface-2); display: grid; place-items: center; color: var(--mp-accent-2, var(--mp-accent)); font-size: 1.1rem; }
.mp-session-row strong { display: block; font-size: 0.8rem; }
.mp-session-row span { display: block; color: var(--mp-muted); font-size: 0.7rem; margin-top: 2px; }

.mp-auth-card { padding: 1.6rem; border-radius: 14px; background: var(--mp-surface); border: 1px solid var(--mp-border); align-self: center; }
.mp-auth-card h2 { font-size: 1.5rem; margin: 0 0 0.4rem; }
.mp-auth-card > p.mp-muted { font-size: 0.82rem; margin-bottom: 0; }

.mp-provider-list { display: grid; gap: 0.6rem; margin: 1.2rem 0; }
.mp-provider-btn {
    min-height: 48px; display: grid; grid-template-columns: 28px 1fr 20px; align-items: center; gap: 0.6rem;
    border: 1px solid var(--mp-border); border-radius: 9px; background: var(--mp-surface-2); color: var(--mp-text);
    font-weight: 700; text-decoration: none; padding: 0 0.9rem;
}
.mp-provider-btn:hover, .mp-provider-btn:focus-visible { border-color: var(--mp-accent); }
.mp-provider-icon { width: 24px; height: 24px; border-radius: 6px; background: #fff; color: #151515; display: grid; place-items: center; font-weight: 900; font-size: 0.75rem; justify-self: start; }
.mp-provider-btn.instagram .mp-provider-icon { background: linear-gradient(135deg,#7c3aed,#f43f5e,#f59e0b); color: #fff; }
.mp-provider-arrow { justify-self: end; color: var(--mp-muted); }

.mp-divider { display: flex; align-items: center; gap: 0.6rem; color: var(--mp-muted); font-size: 0.72rem; margin: 0.9rem 0; }
.mp-divider::before, .mp-divider::after { content: ""; height: 1px; flex: 1; background: var(--mp-border); }

.mp-remember-row { display: flex; align-items: center; justify-content: space-between; gap: 0.75rem; margin-top: 0.7rem; font-size: 0.8rem; color: var(--mp-muted); flex-wrap: wrap; }
.mp-remember-row label { display: flex; align-items: center; gap: 0.5rem; }
.mp-remember-row input[type="checkbox"] { accent-color: var(--mp-accent); width: 15px; height: 15px; }

.mp-auth-foot { margin-top: 1.1rem; color: var(--mp-muted); font-size: 0.78rem; text-align: center; line-height: 1.6; }

@media (max-width: 900px) {
    .mp-auth-layout { grid-template-columns: 1fr; }
    .mp-auth-story { display: none; }
    .mp-auth-card { max-width: 520px; margin: 0 auto; width: 100%; }
}

/* ---- §5.5 First-run onboarding ---- */
.mp-onboard-layout { display: grid; grid-template-columns: 250px minmax(0, 1fr) 330px; gap: 1rem; align-items: start; margin-top: 1rem; }
.mp-onboard-steps { padding: 0.8rem; position: sticky; top: 0.75rem; }
.mp-ostep { display: grid; grid-template-columns: 27px 1fr; gap: 0.6rem; align-items: center; min-height: 50px; padding: 0.45rem 0.5rem; border-radius: 9px; color: var(--mp-muted); font-size: 0.82rem; font-weight: 700; }
.mp-ostep.active { color: var(--mp-text); background: var(--mp-surface-2); }
.mp-ostep-n { width: 27px; height: 27px; border-radius: 50%; border: 1px solid var(--mp-border); display: grid; place-items: center; font-size: 0.68rem; font-weight: 900; }
.mp-ostep.done .mp-ostep-n { background: var(--mp-good); border-color: var(--mp-good); color: #08261a; }
.mp-ostep.active .mp-ostep-n { border-color: var(--mp-accent); color: var(--mp-accent); }

.mp-choice-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0.75rem; margin: 1.1rem 0; }
.mp-choice {
    position: relative; min-height: 160px; padding: 1.1rem; border: 1px solid var(--mp-border); border-radius: 11px;
    background: var(--mp-surface-2); cursor: pointer; display: block;
}
.mp-choice input { position: absolute; width: 1px; height: 1px; opacity: 0; top: 0.9rem; left: 0.9rem; }
.mp-choice:has(input:focus-visible) { outline: 2px solid var(--mp-accent); outline-offset: 2px; }
.mp-choice.selected {
    border-color: var(--mp-accent); box-shadow: inset 0 0 0 1px var(--mp-accent);
    background: linear-gradient(135deg, color-mix(in srgb, var(--mp-accent) 14%, transparent), transparent 55%), var(--mp-surface-2);
}
.mp-choice-icon { width: 40px; height: 40px; border-radius: 10px; background: var(--mp-surface-3, var(--mp-surface)); display: grid; place-items: center; color: var(--mp-accent-2, var(--mp-accent)); margin-bottom: 0.9rem; font-weight: 900; }
.mp-choice p { color: var(--mp-muted); font-size: 0.78rem; line-height: 1.5; margin-top: 0.4rem; }
.mp-choice-check { position: absolute; top: 0.9rem; right: 0.9rem; width: 22px; height: 22px; border-radius: 6px; border: 1px solid var(--mp-border-strong, var(--mp-border)); display: grid; place-items: center; font-size: 0.7rem; font-weight: 900; color: transparent; }
.mp-choice.selected .mp-choice-check { background: var(--mp-good); border-color: var(--mp-good); color: #08261a; }

.mp-onboard-summary { padding: 1.1rem; position: sticky; top: 0.75rem; }
.mp-summary-line { display: flex; justify-content: space-between; gap: 0.75rem; padding-bottom: 0.6rem; margin-bottom: 0.6rem; border-bottom: 1px solid var(--mp-border); font-size: 0.78rem; }
.mp-summary-line span { color: var(--mp-muted); }
.mp-summary-line:last-of-type { border-bottom: 0; margin-bottom: 0; padding-bottom: 0; }

.mp-onboard-actions { display: flex; justify-content: space-between; gap: 0.6rem; margin-top: 1.4rem; flex-wrap: wrap; }

@media (max-width: 1180px) {
    .mp-onboard-layout { grid-template-columns: 210px minmax(0, 1fr); }
    .mp-onboard-summary { grid-column: 1 / -1; position: static; }
}
@media (max-width: 860px) {
    .mp-onboard-layout { grid-template-columns: 1fr; }
    .mp-onboard-steps { position: static; display: flex; gap: 0.4rem; overflow-x: auto; -webkit-overflow-scrolling: touch; }
    .mp-ostep { flex: 0 0 auto; min-width: 9rem; }
}
@media (max-width: 560px) {
    .mp-choice-grid { grid-template-columns: 1fr; }
}

/* ---- §5.3 Public home ---- */
.mp-home-hero { display: grid; grid-template-columns: minmax(0, 7fr) minmax(340px, 5fr); gap: 2.5rem; align-items: center; min-height: 560px; padding: 2rem 0 2.5rem; }
.mp-home-hero h1 { font-size: clamp(2.2rem, 5vw, 4.2rem); line-height: 0.98; letter-spacing: -0.03em; margin: 0.5rem 0 0.9rem; }
.mp-home-hero h1 span { color: var(--mp-accent); }
.mp-home-copy p { max-width: 38rem; color: #b5bfcc; font-size: 1.05rem; line-height: 1.6; }
.mp-home-actions { display: flex; gap: 0.75rem; margin-top: 1.4rem; flex-wrap: wrap; }
.mp-proof-row { display: flex; flex-wrap: wrap; gap: 1.1rem; margin-top: 1.5rem; color: var(--mp-muted); font-size: 0.72rem; font-weight: 700; }
.mp-proof-row span::before { content: "\2713"; color: var(--mp-good); margin-right: 0.35rem; }

.mp-preview-card { padding: 1rem; border-radius: 14px; background: linear-gradient(150deg, color-mix(in srgb, var(--mp-accent) 9%, transparent), transparent 42%), var(--mp-surface); border: 1px solid var(--mp-border); box-shadow: 0 18px 44px rgba(0,0,0,0.35); }
/* flex-wrap matters: .mp-badge is white-space:nowrap, so without it the badge fixes this row's min-content
   at title+badge width (~281px), which propagates up through .mp-preview-card into the hero's 1fr track and
   forces page-level horizontal overflow at viewports ≤ ~347px. */
.mp-preview-top { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: center; margin-bottom: 0.8rem; gap: 0.5rem; }
.mp-preview-current { padding: 0.9rem; border-radius: 10px; background: var(--mp-bg); border-left: 4px solid var(--mp-accent); }
.mp-preview-name { display: flex; justify-content: space-between; gap: 0.75rem; align-items: flex-start; }
.mp-preview-name strong { font-size: 1.35rem; letter-spacing: -0.02em; }
.mp-preview-kg { color: var(--mp-accent); font-size: 1.35rem; font-weight: 900; }
.mp-preview-meta { display: flex; gap: 0.4rem; flex-wrap: wrap; color: var(--mp-muted); font-size: 0.72rem; margin-top: 0.4rem; }
.mp-preview-table { margin-top: 0.8rem; border: 1px solid var(--mp-border); border-radius: 10px; overflow: hidden; }
.mp-preview-row { display: grid; grid-template-columns: 28px minmax(0,1fr) repeat(3, 3.4rem); min-height: 42px; align-items: center; padding: 0 0.65rem; border-bottom: 1px solid var(--mp-border); font-size: 0.72rem; gap: 0.3rem; }
.mp-preview-row:last-child { border-bottom: 0; }
.mp-preview-row.head { color: var(--mp-muted); background: var(--mp-surface-2); font-size: 0.6rem; text-transform: uppercase; font-weight: 800; }
.mp-preview-row.current { background: color-mix(in srgb, var(--mp-accent) 12%, transparent); }
.mp-preview-good { color: var(--mp-good); font-weight: 800; }

.mp-feature-band { border-top: 1px solid var(--mp-border); border-bottom: 1px solid var(--mp-border); margin-top: 1rem; background: rgba(22,27,34,0.5); }
.mp-feature-grid { max-width: 1560px; margin: 0 auto; padding: 2.5rem 0; display: grid; grid-template-columns: repeat(4, 1fr); gap: 1rem; }
.mp-feature-icon { width: 40px; height: 40px; border-radius: 10px; background: var(--mp-surface-2); color: var(--mp-accent); display: grid; place-items: center; margin-bottom: 1rem; font-weight: 900; }
.mp-feature-grid .mp-card p { color: var(--mp-muted); font-size: 0.8rem; line-height: 1.55; margin-top: 0.45rem; }

@media (max-width: 1100px) {
    /* minmax(0, 1fr), not bare 1fr: 1fr means minmax(auto, 1fr), so any grid item's min-content (e.g. a
       nowrap badge inside the preview card) could widen the track past the container and overflow the page. */
    .mp-home-hero { grid-template-columns: minmax(0, 1fr); min-height: auto; }
    .mp-home-hero .mp-preview-wrap { order: 2; }
    .mp-home-hero .mp-home-copy { order: 1; }
    .mp-feature-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 560px) {
    .mp-feature-grid { grid-template-columns: 1fr; }
    .mp-preview-row > :nth-child(n+5) { display: none; }
    .mp-preview-row { grid-template-columns: 24px minmax(0,1fr) 3.4rem; }
}
@media (max-width: 480px) {
    .mp-home-actions { flex-direction: column; }
    .mp-home-actions .mp-btn { width: 100%; text-align: center; }
}

/* ---- §3.4 Account & security / trusted devices ---- */
.mp-device-list { display: grid; gap: 0.75rem; }
.mp-device-card { display: flex; align-items: center; gap: 1rem; padding: 0.9rem 1rem; border: 1px solid var(--mp-border); border-radius: 11px; background: var(--mp-surface-2); flex-wrap: wrap; }
.mp-device-card.current { border-color: var(--mp-accent); }
.mp-device-card-info { flex: 1 1 14rem; min-width: 0; }
.mp-device-card-info strong { display: block; font-size: 0.92rem; }
.mp-device-meta { display: flex; flex-wrap: wrap; gap: 0.5rem 0.9rem; margin-top: 0.35rem; color: var(--mp-muted); font-size: 0.75rem; }
.mp-device-card-actions { display: flex; gap: 0.5rem; flex-wrap: wrap; align-items: center; }

.mp-conn-list { display: grid; }
.mp-conn-row { display: flex; align-items: center; justify-content: space-between; gap: 0.75rem; padding: 0.75rem 0; border-bottom: 1px solid var(--mp-border); flex-wrap: wrap; }
.mp-conn-row:last-child { border-bottom: 0; }
.mp-conn-name { display: flex; align-items: center; gap: 0.6rem; font-weight: 700; }

@media (max-width: 560px) {
    .mp-device-card { flex-direction: column; align-items: flex-start; }
    .mp-device-card-actions { width: 100%; }
}

/* ==== Profile/equipment WP3: /profile professional layout ====
   docs/specs/profile-equipment/{WP0-architecture-and-parity.md, fable-profile-equipment-architecture-spec.md,
   profile-redesign-ui-mockup.html}. ADDITIVE ONLY — nothing above this comment is touched. `.mp-profile-scope`
   clones the Setup redesign's `.mp-setup-scope` control treatment (rest/hover/focus-visible ring/readonly dashed/
   disabled/invalid/placeholder/select-arrow/color-scheme, WP0 finding 15) rather than duplicating hard-coded
   colours, plus this page's own layout/media-rail/set-card/rack-card/autocomplete chrome. Only --mp-* tokens are
   used, matching every value already used elsewhere in this file (WP0 §2 rule 5/finding 15). */

.mp-profile-scope { width: 100%; max-width: none; padding-bottom: 6.5rem; }

/* ---- Dark control base (identical states to .mp-setup-scope; see that block's own comments for the Chromium
   file-input caveat, which this page doesn't use, so it isn't repeated here). ---- */
.mp-profile-scope .form-control {
    display: block; width: 100%; min-height: 2.35rem; padding: 0 0.65rem; color: var(--mp-text);
    background: var(--mp-control-bg); border: 1px solid var(--mp-control-border); border-radius: 7px;
    box-shadow: inset 0 1px 1px rgba(0,0,0,0.2); outline: none;
    transition: border-color .14s ease, background-color .14s ease, box-shadow .14s ease;
}
.mp-profile-scope textarea.form-control { min-height: 6.5rem; resize: vertical; padding: 0.55rem 0.65rem; }
.mp-profile-scope .form-control::placeholder { color: var(--mp-control-placeholder); opacity: 1; }
.mp-profile-scope .form-control:hover:not(:disabled):not([readonly]) { background: var(--mp-control-bg-hover); border-color: #435164; }
.mp-profile-scope .form-control:focus-visible, .mp-profile-scope .form-control:focus {
    border-color: var(--mp-control-border-focus); background: #19212b;
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--mp-control-border-focus) 22%, transparent), inset 0 1px 1px rgba(0,0,0,0.2);
}
.mp-profile-scope .form-control:disabled, .mp-profile-scope .form-control[disabled] {
    opacity: 0.55; cursor: not-allowed; background: color-mix(in srgb, var(--mp-control-bg) 65%, var(--mp-bg));
}
.mp-profile-scope .form-control[readonly] { background: transparent; border-style: dashed; color: var(--mp-muted); }
.mp-profile-scope .form-control.invalid, .mp-profile-scope .form-control[aria-invalid="true"],
.mp-profile-scope .validation-message {
    border-color: var(--mp-nolift);
}
.mp-profile-scope .form-control.invalid, .mp-profile-scope .form-control[aria-invalid="true"] {
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--mp-nolift) 18%, transparent), inset 0 1px 1px rgba(0,0,0,0.2);
}
.mp-profile-scope .validation-message { display: block; margin-top: 0.3rem; color: var(--mp-nolift); font-size: 0.78rem; font-weight: 700; border: 0; }
.mp-profile-scope select.form-control {
    appearance: none; -webkit-appearance: none;
    background-image: linear-gradient(45deg, transparent 50%, #7d8999 50%), linear-gradient(135deg, #7d8999 50%, transparent 50%);
    background-position: calc(100% - 15px) 52%, calc(100% - 10px) 52%; background-size: 4px 4px, 4px 4px; background-repeat: no-repeat;
    padding-right: 1.7rem;
}
.mp-profile-scope label { display: block; margin-bottom: 0.35rem; color: var(--mp-muted); font-size: 0.78rem; font-weight: 700; }
.mp-profile-scope label .optional { color: var(--mp-faint, var(--mp-muted)); font-weight: 550; }

/* ---- WP5 polish: card elevation + icon chips (mock ".card"/".card-icon") ----
   The shared global `.mp-card` (platform.css line ~776) is deliberately left untouched — it is reused by Setup and
   other pages that were never designed with a drop shadow. Scoping the mock's `--shadow`/13px radius under
   `.mp-profile-scope` only brings this page to visual parity with the mock without touching any other surface. */
.mp-profile-scope .mp-card { border-radius: 13px; box-shadow: 0 14px 35px rgba(0, 0, 0, 0.22); }
.mp-profile-card-title { display: flex; align-items: flex-start; gap: 0.7rem; min-width: 0; }
.mp-profile-card-icon {
    flex: 0 0 auto; width: 2.15rem; height: 2.15rem; display: grid; place-items: center;
    border: 1px solid color-mix(in srgb, var(--mp-accent) 28%, transparent); border-radius: 9px;
    background: color-mix(in srgb, var(--mp-accent) 12%, transparent); color: var(--mp-accent);
}
.mp-profile-card-icon svg { width: 17px; height: 17px; }

/* ---- Header (ProfileHeader.razor, mock ".page-header") ---- */
.mp-profile-header {
    display: flex; align-items: flex-end; justify-content: space-between; gap: 1.25rem; flex-wrap: wrap;
    margin: 0 0 1.1rem; padding: 0.25rem 0.1rem;
}
.mp-profile-eyebrow {
    margin: 0 0 0.35rem; color: var(--mp-accent); font-size: 0.68rem; font-weight: 850;
    text-transform: uppercase; letter-spacing: 0.1em;
}
.mp-profile-header h1 { margin: 0; font-size: clamp(1.7rem, 2.4vw, 2.4rem); line-height: 1.05; letter-spacing: -0.03em; }
/* Self-service account capabilities WP2: a flex child needs min-width:0 to actually shrink below its content's
   intrinsic width, and the signed-in email (an unbroken string with no natural break points) needs
   overflow-wrap:anywhere to wrap at all — otherwise a long registration email forces this whole flex row past the
   viewport at narrow widths. Pre-existing gap only ever exercised by a short email until this WP2's long-email
   overflow requirement. */
.mp-profile-header > div:first-child { min-width: 0; }
.mp-profile-subtitle { margin: 0.5rem 0 0; color: var(--mp-muted); overflow-wrap: anywhere; }
.mp-profile-role-badges { display: flex; flex-wrap: wrap; gap: 0.4rem; }
.mp-profile-role-badge {
    display: inline-flex; align-items: center; gap: 6px; min-height: 26px; width: max-content; white-space: nowrap;
    padding: 4px 10px; border: 1px solid #425064; border-radius: 999px; background: #1a222c; color: #dce4ee;
    font-size: 0.75rem; font-weight: 750;
}
.mp-profile-role-badge::before { content: ""; width: 7px; height: 7px; border-radius: 50%; background: var(--mp-accent); box-shadow: 0 0 0 3px color-mix(in srgb, var(--mp-accent) 20%, transparent); }

/* ---- Alerts / notices (error summary + success/review banner — spec §12.4 focus management) ---- */
.mp-profile-alert {
    border: 1px solid var(--mp-nolift); background: color-mix(in srgb, var(--mp-nolift) 12%, var(--mp-surface));
    border-radius: 10px; padding: 0.8rem 0.95rem; margin-bottom: 1rem;
}
.mp-profile-alert:focus-visible, .mp-profile-alert:focus { outline: 2px solid var(--mp-nolift); outline-offset: 2px; }
.mp-profile-alert strong { color: var(--mp-nolift); display: block; font-size: 0.85rem; margin-bottom: 0.2rem; }
.mp-profile-notice {
    border: 1px solid var(--mp-good); background: color-mix(in srgb, var(--mp-good) 12%, var(--mp-surface));
    border-radius: 10px; padding: 0.8rem 0.95rem; margin-bottom: 1rem;
}
.mp-profile-notice strong { color: var(--mp-good); display: block; font-size: 0.85rem; }
.mp-profile-notice p { margin: 0.35rem 0 0; color: var(--mp-muted); font-size: 0.8rem; }

/* ---- Two-column workspace (fable-spec §4.1/§4.2, mock ".profile-layout") ---- */
.mp-profile-layout { display: grid; grid-template-columns: minmax(290px, 350px) minmax(0, 1fr); gap: 1.1rem; align-items: start; }
.mp-profile-side { position: sticky; top: 1.1rem; }
.mp-profile-main { display: flex; flex-direction: column; gap: 1.1rem; min-width: 0; }

.mp-profile-card { padding: 0; }
.mp-profile-card-head {
    display: flex; align-items: flex-start; justify-content: space-between; gap: 1rem;
    padding: 1.1rem 1.25rem 0.85rem; border-bottom: 1px solid var(--mp-border);
}
.mp-profile-card-head h2 { margin: 0; font-size: 1rem; letter-spacing: -0.015em; }
.mp-profile-card-desc { margin: 0.2rem 0 0; color: var(--mp-muted); font-size: 0.78rem; }
.mp-profile-card-body { padding: 1.1rem 1.25rem 1.25rem; }
.mp-profile-section-label {
    margin: 0 0 0.75rem; color: #cfd7e2; font-size: 0.72rem; font-weight: 850;
    text-transform: uppercase; letter-spacing: 0.07em;
}
.mp-profile-divider { height: 1px; background: var(--mp-border); margin: 1.1rem 0; }
.mp-profile-help { margin: 0.4rem 0 0; color: var(--mp-muted); font-size: 0.72rem; }
.mp-profile-help a { color: var(--mp-accent); }
.mp-profile-fieldset { border: 0; padding: 0; margin: 0; min-width: 0; }

/* ---- Personal-details/public-profile field grid (mock ".field-grid") ---- */
.mp-profile-field-grid { display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); gap: 0.85rem; }
.mp-profile-field { grid-column: span 4; min-width: 0; }
.mp-profile-field.span-6 { grid-column: span 6; }
.mp-profile-field.span-8 { grid-column: span 8; }
.mp-profile-field.span-12 { grid-column: 1 / -1; }

/* ---- Best-lift set cards (BestLiftsEditor.razor, mock ".equipment-set") ---- */
.mp-profile-equipment-defaults { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0.75rem; }
.mp-profile-set { position: relative; padding: 0.9rem; border: 1px solid var(--mp-border); border-radius: 10px; background: var(--mp-nested-surface); }
.mp-profile-set.is-default { border-color: color-mix(in srgb, var(--mp-accent) 48%, var(--mp-border)); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--mp-accent) 9%, transparent); }
.mp-profile-set-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 0.6rem; margin-bottom: 0.75rem; }
.mp-profile-set-name { display: flex; align-items: center; gap: 0.5rem; font-weight: 850; }
.mp-profile-default-badge { font-size: 0.6rem; padding: 0.1rem 0.45rem; }
.mp-profile-default-choice {
    display: inline-flex; align-items: center; gap: 0.4rem; min-height: 1.6rem; padding: 0.1rem 0.2rem;
    color: var(--mp-muted); cursor: pointer; font-size: 0.68rem; font-weight: 750;
}
.mp-profile-default-choice input[type="radio"] { accent-color: var(--mp-accent); width: 15px; height: 15px; margin: 0; }
.mp-profile-default-choice:focus-within { outline: 2px solid var(--mp-control-border-focus); outline-offset: 2px; border-radius: 4px; }
.mp-profile-set.is-default .mp-profile-default-choice { color: var(--mp-accent); }
.mp-profile-lift-fields { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 0.6rem; }
.mp-profile-lift-field label { margin-bottom: 0.3rem; font-size: 0.68rem; }
.mp-profile-input-wrap { position: relative; }
.mp-profile-input-wrap .form-control { padding-right: 2.2rem; }
.mp-profile-input-suffix {
    position: absolute; right: 0.65rem; top: 50%; transform: translateY(-50%);
    color: var(--mp-muted); font-size: 0.7rem; font-weight: 750; pointer-events: none;
}
.mp-profile-set-note { margin: 0.6rem 0 0; color: var(--mp-muted); font-size: 0.66rem; line-height: 1.4; }

/* ---- Rack defaults island (RackDefaultsEditor.razor, mock ".rack-default") ---- */
.mp-profile-immediate-note { margin: 0 0 0.9rem; color: var(--mp-muted); font-size: 0.76rem; font-style: italic; }
.mp-profile-rack-search-row { display: grid; grid-template-columns: minmax(240px, 32rem) auto; align-items: end; gap: 0.65rem; margin-bottom: 0.5rem; }
.mp-profile-rack-search-row .mp-btn { min-height: 2.35rem; }
.mp-profile-rack-fields-pad { margin: 0 1.1rem 0.6rem; }
.mp-profile-rack-list { display: flex; flex-direction: column; gap: 0.7rem; margin-top: 0.9rem; }
.mp-profile-rack-card { border: 1px solid var(--mp-border); border-radius: 10px; background: var(--mp-nested-surface); overflow: hidden; }
.mp-profile-rack-head { display: flex; align-items: center; justify-content: space-between; gap: 1rem; padding: 0.75rem 0.85rem; border-bottom: 1px solid var(--mp-border); }
.mp-profile-rack-name { display: flex; align-items: center; gap: 0.6rem; min-width: 0; }
.mp-profile-rack-glyph {
    flex: 0 0 auto; width: 1.9rem; height: 1.9rem; display: grid; place-items: center; border-radius: 8px;
    background: #202a36; color: var(--mp-accent); font-weight: 900; text-transform: uppercase;
}
.mp-profile-rack-name strong { display: block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.mp-profile-rack-meta { display: flex; align-items: center; gap: 0.4rem; color: var(--mp-muted); font-size: 0.66rem; }
.mp-profile-unavailable-badge { color: var(--mp-nolift); border-color: color-mix(in srgb, var(--mp-nolift) 45%, var(--mp-border)); }
.mp-profile-confirm-remove { display: flex; align-items: center; gap: 0.5rem; font-size: 0.72rem; color: var(--mp-muted); flex-wrap: wrap; }
.mp-profile-rack-fields { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 0.7rem; padding: 0.85rem 0.85rem 0.9rem; }
.mp-profile-segmented {
    display: grid; grid-template-columns: 1fr 1fr; gap: 4px; min-height: 2.35rem; padding: 4px;
    border: 1px solid var(--mp-control-border); border-radius: 8px; background: var(--mp-control-bg);
}
.mp-profile-segmented label {
    display: flex; align-items: center; justify-content: center; margin: 0; border-radius: 5px;
    color: var(--mp-muted); cursor: pointer; font-size: 0.7rem; font-weight: 750;
}
.mp-profile-segmented label.active { background: #2a3542; color: var(--mp-text); box-shadow: inset 0 0 0 1px #48576a; }
.mp-profile-segmented input[type="radio"] {
    position: absolute; width: 1px; height: 1px; margin: -1px; overflow: hidden; clip-path: inset(50%);
}
.mp-profile-segmented label:focus-within { outline: 2px solid var(--mp-control-border-focus); outline-offset: 2px; }
.mp-profile-rack-save-row { display: flex; align-items: center; gap: 0.75rem; padding: 0 0.85rem 0.85rem; flex-wrap: wrap; }
.mp-profile-save-state { color: var(--mp-muted); font-size: 0.75rem; }
.mp-profile-rack-error { color: var(--mp-nolift); font-weight: 700; }

/* ---- Shared rack-equipment autocomplete (RackEquipmentAutocomplete.razor, mock ".search-box"/".suggestions").
   Not nested under .mp-profile-scope: WP4 reuses this same component under .mp-setup-scope, so its chrome is
   scoped to its own class names instead of duplicated per host page. z-index follows the documented chain — the
   savebar is z-60 (below), so the open dropdown clears it at 190 (WP0 finding 15/§ "z-chain"). ---- */
.mp-rea { position: relative; min-width: 0; }
.mp-rea-box { position: relative; }
.mp-rea-input { padding-right: 0.65rem; }
.suggestions {
    position: absolute; left: 0; right: 0; top: calc(100% + 5px); z-index: 190; overflow: hidden;
    border: 1px solid #445165; border-radius: 9px; background: #141b24; box-shadow: 0 18px 40px rgba(0,0,0,.42);
    max-height: 18rem; overflow-y: auto;
}
.suggestion {
    width: 100%; display: flex; align-items: center; justify-content: space-between; gap: 0.75rem;
    padding: 0.6rem 0.75rem; border: 0; border-bottom: 1px solid #29323e; background: transparent;
    color: var(--mp-text); text-align: left; cursor: pointer; font: inherit;
}
.suggestion:last-child { border-bottom: 0; }
.suggestion:hover, .suggestion.active { background: #1d2631; }
.suggestion:focus-visible { outline: 2px solid var(--mp-control-border-focus); outline-offset: -2px; }
.suggestion[aria-disabled="true"] { cursor: default; color: var(--mp-muted); }
.suggestion strong { display: block; font-size: 0.75rem; }
.suggestion span span { display: block; color: var(--mp-muted); font-size: 0.62rem; }
.suggestion .type { flex: 0 0 auto; color: var(--mp-accent); font-size: 0.68rem; }
.suggestion.create { color: var(--mp-accent); font-weight: 800; }

/* ---- Sticky savebar clearance (reuses the existing global .mp-savebar; see the shared rule far above) ---- */
.mp-profile-scope .mp-save-state { display: flex; align-items: center; gap: 0.55rem; color: var(--mp-muted); font-size: 0.8rem; }
.mp-profile-scope .mp-save-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--mp-good); box-shadow: 0 0 0 4px color-mix(in srgb, var(--mp-good) 12%, transparent); flex: 0 0 auto; }
.mp-profile-scope .mp-save-actions { display: flex; align-items: center; gap: 0.6rem; }

/* ---- Responsive tiers (fable-spec §4.1/§4.2/§10, mock breakpoints) ----
   >=1180: two-column workspace as authored above.
   860-1179: media rail narrows slightly, fields still 12-col but span-8 collapses to full width.
   <860: media rail stacks above the form; media uploaders sit two-up (own ProfileImageUpload.razor.css handles
     stacking one-up under 720px, matched here for consistency at the same page-level tier).
   <640: single column throughout, 44px touch targets, no page-level horizontal scroll (spec §4.2). ---- */
@media (max-width: 1180px) {
    .mp-profile-layout { grid-template-columns: minmax(260px, 310px) minmax(0, 1fr); }
    .mp-profile-field { grid-column: span 6; }
    .mp-profile-field.span-8 { grid-column: span 12; }
    .mp-profile-rack-fields { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 860px) {
    .mp-profile-layout { grid-template-columns: minmax(0, 1fr); }
    .mp-profile-side { position: static; }
    .mp-profile-media-card .mp-profile-card-body { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1rem; }
    .mp-profile-media-card .mp-media-block + .mp-media-block { margin: 0; padding: 0; border: 0; }
    .mp-profile-equipment-defaults { grid-template-columns: minmax(0, 1fr); }
    .mp-profile-rack-search-row { grid-template-columns: minmax(0, 1fr); }
}
@media (max-width: 640px) {
    .mp-profile-header { align-items: flex-start; flex-direction: column; gap: 0.6rem; }
    .mp-profile-card-head, .mp-profile-card-body { padding-left: 1rem; padding-right: 1rem; }
    .mp-profile-field, .mp-profile-field.span-6, .mp-profile-field.span-8 { grid-column: 1 / -1; }
    .mp-profile-media-card .mp-profile-card-body { grid-template-columns: minmax(0, 1fr); }
    .mp-profile-lift-fields { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .mp-profile-rack-fields { grid-template-columns: minmax(0, 1fr); }
    .mp-profile-rack-search-row .mp-btn { width: 100%; }
    .mp-profile-scope .form-control, .mp-profile-scope .mp-btn, .mp-profile-scope .mp-media-icon-btn,
    .mp-profile-segmented label, .mp-profile-scope input[type="checkbox"] { min-height: 44px; }
    .mp-savebar { width: calc(100% - 1.5rem); flex-wrap: wrap; }
}
@media (max-width: 390px) {
    .mp-profile-scope { padding-left: 0; padding-right: 0; }
}

/* ==== Federation defaults WP2: /admin/users "Users and roles" (docs/specs/federation-defaults §7.5 +
   strength-meet-federation-create-mockup.html #page-roles) ====
   ADDITIVE ONLY — nothing above this comment is touched. Reuses --mp-* tokens and the existing
   .mp-card/.mp-btn/.mp-badge/.mp-table/.mp-auth-notice system; the dark control treatment is the same
   --mp-control-* recipe already used by .mp-setup-scope/.mp-auth-scope/.mp-profile-scope, scoped here so the
   admin filters get muted dark fields instead of harsh white ones without touching any other surface. */

.mp-adminroles-scope { width: 100%; }

.mp-adminroles-scope .form-control {
    display: block; width: 100%; min-height: 2.5rem; padding: 0 0.7rem; color: var(--mp-text);
    background: var(--mp-control-bg); border: 1px solid var(--mp-control-border); border-radius: 8px;
    box-shadow: inset 0 1px 1px rgba(0,0,0,0.2); outline: none;
    transition: border-color .14s ease, background-color .14s ease, box-shadow .14s ease;
}
.mp-adminroles-scope .form-control::placeholder { color: var(--mp-control-placeholder); opacity: 1; }
.mp-adminroles-scope .form-control:hover:not(:disabled) { background: var(--mp-control-bg-hover); border-color: #435164; }
.mp-adminroles-scope .form-control:focus-visible, .mp-adminroles-scope .form-control:focus {
    border-color: var(--mp-control-border-focus); background: #19212b;
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--mp-control-border-focus) 22%, transparent), inset 0 1px 1px rgba(0,0,0,0.2);
}
.mp-adminroles-scope select.form-control {
    appearance: none; -webkit-appearance: none;
    background-image: linear-gradient(45deg, transparent 50%, #7d8999 50%), linear-gradient(135deg, #7d8999 50%, transparent 50%);
    background-position: calc(100% - 15px) 52%, calc(100% - 10px) 52%; background-size: 4px 4px, 4px 4px; background-repeat: no-repeat;
    padding-right: 1.7rem;
}

.mp-adminroles-head { margin-bottom: 1rem; }
.mp-adminroles-head h1 { margin: 0 0 0.4rem; }
.mp-adminroles-eyebrow {
    margin: 0 0 0.35rem; color: var(--mp-accent); font-size: 0.68rem; font-weight: 850;
    text-transform: uppercase; letter-spacing: 0.1em;
}

.mp-adminroles-notice {
    border: 1px solid var(--mp-accent); border-radius: 10px; margin-bottom: 1rem; padding: 0.75rem 0.9rem;
    background: color-mix(in srgb, var(--mp-accent) 10%, var(--mp-surface));
}
.mp-adminroles-notice strong { display: block; font-size: 0.85rem; }
.mp-adminroles-notice p { margin: 0.25rem 0 0; color: var(--mp-muted); font-size: 0.8rem; }

/* Filters: a wrapping flex row so 320px stacks instead of forcing document-level horizontal overflow. */
.mp-adminroles-filters { display: flex; flex-wrap: wrap; gap: 0.6rem; align-items: flex-end; margin-bottom: 0.85rem; }
.mp-adminroles-field { flex: 1 1 11rem; min-width: 0; }
.mp-adminroles-field.search { flex: 2 1 16rem; }
.mp-adminroles-field label { display: block; margin-bottom: 0.3rem; color: var(--mp-muted); font-size: 0.78rem; font-weight: 700; }
.mp-adminroles-filters .mp-btn { flex: 0 0 auto; min-height: 2.5rem; }

/* The table is wide by nature (five columns incl. two action stacks); it scrolls inside its own card so the
   page body never does — same containment rule as .mp-mymeet's table wrapper. */
.mp-adminroles-tablewrap { padding: 0; overflow-x: auto; -webkit-overflow-scrolling: touch; max-width: 100%; }
.mp-adminroles-table { min-width: 62rem; }
.mp-adminroles-table td { vertical-align: top; }
.mp-adminroles-name { font-weight: 750; }
.mp-adminroles-sub { color: var(--mp-muted); font-size: 0.75rem; margin-top: 2px; word-break: break-word; }
.mp-adminroles-badges { display: flex; flex-wrap: wrap; gap: 0.35rem; }

/* Federation access state: the switch pip. For a SystemAdmin row (and while a row's confirm panel is open) it's
   rendered decoratively (aria-hidden) next to real text so the state is never colour-only; for every other row
   it IS the control — a real <button type="submit"> (loading-admin-federation spec §5.1/brief D3) — so the rule
   below resets the button's UA chrome (padding/font/appearance) without touching the plain-span usage. */
.mp-adminroles-state { display: inline-flex; align-items: center; gap: 0.5rem; font-size: 0.82rem; }
.mp-adminroles-switch {
    flex: 0 0 auto; width: 30px; height: 17px; border-radius: 999px; position: relative;
    background: var(--mp-surface-2); border: 1px solid var(--mp-border);
    padding: 0; margin: 0; appearance: none; -webkit-appearance: none; font: inherit; cursor: pointer;
}
.mp-adminroles-switch::after {
    content: ""; position: absolute; top: 2px; left: 2px; width: 11px; height: 11px; border-radius: 50%;
    background: var(--mp-muted); transition: left .14s ease, background-color .14s ease;
}
.mp-adminroles-switch.on { background: color-mix(in srgb, var(--mp-good) 30%, transparent); border-color: var(--mp-good); }
.mp-adminroles-switch.on::after { left: 15px; background: var(--mp-good); }
.mp-adminroles-switch.locked { opacity: 0.75; cursor: default; }
.mp-adminroles-switch:focus-visible { outline: 2px solid var(--mp-accent); outline-offset: 2px; }

.mp-adminroles-rolebtn { display: inline-block; margin-top: 0.5rem; font-size: 0.8rem; padding: 0.4rem 0.75rem; }
.mp-adminroles-confirm {
    margin-top: 0.5rem; padding: 0.6rem 0.7rem; border-radius: 9px;
    border: 1px solid var(--mp-accent); background: color-mix(in srgb, var(--mp-accent) 9%, var(--mp-surface-2));
    max-width: 22rem;
}
.mp-adminroles-confirm p { margin: 0 0 0.5rem; color: var(--mp-muted); font-size: 0.78rem; line-height: 1.5; }
.mp-adminroles-actions { display: flex; flex-wrap: wrap; gap: 0.4rem; align-items: center; }
.mp-adminroles-actions .mp-btn { font-size: 0.8rem; padding: 0.4rem 0.75rem; }

.mp-adminroles-cellstack { display: flex; flex-direction: column; gap: 0.35rem; min-width: 13.5rem; }
.mp-adminroles-hint { color: var(--mp-muted); font-size: 0.7rem; }
.mp-adminroles-lockrow { display: flex; gap: 0.35rem; }
.mp-adminroles-lockrow .form-control { min-width: 0; }

.mp-adminroles-foot { margin-top: 0.85rem; font-size: 0.78rem; }

@media (max-width: 640px) {
    .mp-adminroles-filters .mp-btn { width: 100%; }
    /* 44px touch targets on the role controls, matching the Setup/profile rules above. */
    .mp-adminroles-scope .form-control, .mp-adminroles-scope .mp-btn { min-height: 44px; }
}

/* ===== federation management (.mp-fed-*) =====
   Federation defaults WP3 (docs/specs/federation-defaults §7.1/§7.3/§7.4 + strength-meet-federation-create-
   mockup.html #page-federations / #page-editor). ADDITIVE ONLY — nothing above this comment is touched.
   Reuses --mp-* tokens and the existing .mp-card/.mp-btn/.mp-badge/.mp-table/.mp-notice/.mp-auth-notice/.mp-muted
   primitives; the muted dark field recipe is the SAME --mp-control-* tokens already used by .mp-setup-scope/
   .mp-adminroles-scope, scoped here under .mp-fed-scope so no other page is affected. 12px card radius comes
   from the shared .mp-card rule; every control below is 38px (2.375rem) minimum height on desktop and steps up
   to 44px under the touch media query, matching the Setup/admin-roles precedent. Usable at 320px: every wide
   table sits in its own horizontally-scrolling .mp-fed-tablewrap so the document itself never overflows. */

.mp-fed-scope { width: 100%; }

.mp-fed-scope .form-control {
    display: block; width: 100%; min-height: 2.375rem; padding: 0 0.7rem; color: var(--mp-text);
    background: var(--mp-control-bg); border: 1px solid var(--mp-control-border); border-radius: 7px;
    box-shadow: inset 0 1px 1px rgba(0,0,0,0.2); outline: none;
    transition: border-color .14s ease, background-color .14s ease, box-shadow .14s ease;
}
.mp-fed-scope textarea.form-control { min-height: 4.5rem; padding-top: 0.5rem; resize: vertical; }
.mp-fed-scope .form-control::placeholder { color: var(--mp-control-placeholder); opacity: 1; }
.mp-fed-scope .form-control:hover:not(:disabled) { background: var(--mp-control-bg-hover); border-color: #435164; }
.mp-fed-scope .form-control:focus-visible, .mp-fed-scope .form-control:focus {
    border-color: var(--mp-control-border-focus); background: #19212b;
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--mp-control-border-focus) 22%, transparent), inset 0 1px 1px rgba(0,0,0,0.2);
}
.mp-fed-scope .form-control:disabled { opacity: 0.6; cursor: not-allowed; }
.mp-fed-scope select.form-control {
    appearance: none; -webkit-appearance: none;
    background-image: linear-gradient(45deg, transparent 50%, #7d8999 50%), linear-gradient(135deg, #7d8999 50%, transparent 50%);
    background-position: calc(100% - 15px) 52%, calc(100% - 10px) 52%; background-size: 4px 4px, 4px 4px; background-repeat: no-repeat;
    padding-right: 1.7rem;
}

/* ---- page heading / metrics / filters (list + editor share these) ---- */
.mp-fed-head { display: flex; align-items: flex-end; justify-content: space-between; gap: 1rem; margin-bottom: 1rem; flex-wrap: wrap; }
.mp-fed-head h1 { margin: 0 0 0.3rem; }
.mp-fed-head p { max-width: 48rem; }
.mp-fed-eyebrow { margin: 0 0 0.25rem; color: var(--mp-accent); font-size: 0.68rem; font-weight: 800; text-transform: uppercase; letter-spacing: 0.09em; }
.mp-fed-heading-actions { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; }

.mp-fed-metric-grid { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 0.6rem; margin-bottom: 0.9rem; }
.mp-fed-metric { padding: 0.7rem 0.75rem; border: 1px solid var(--mp-border); border-radius: 9px; background: var(--mp-surface); }
.mp-fed-metric strong { display: block; margin-bottom: 0.1rem; font-size: 1.25rem; line-height: 1; }
.mp-fed-metric span { color: var(--mp-muted); font-size: 0.65rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em; }

.mp-fed-filters { display: grid; grid-template-columns: minmax(220px, 1.4fr) minmax(140px, 1fr) minmax(140px, 1fr) auto; gap: 0.6rem; align-items: end; margin-bottom: 0.85rem; }
.mp-fed-field { min-width: 0; }
.mp-fed-field label { display: block; margin-bottom: 0.3rem; color: var(--mp-muted); font-size: 0.78rem; font-weight: 700; }
.mp-fed-filters .mp-btn { min-height: 2.375rem; }

/* ---- list table ---- */
.mp-fed-tablewrap { padding: 0; overflow-x: auto; -webkit-overflow-scrolling: touch; max-width: 100%; }
.mp-fed-table { min-width: 52rem; }
.mp-fed-table td { vertical-align: top; }
.mp-fed-identity { display: flex; align-items: center; gap: 0.6rem; }
.mp-fed-logo-tile {
    width: 2.2rem; height: 2.2rem; flex: 0 0 auto; display: grid; place-items: center;
    border: 1px solid var(--mp-border); border-radius: 8px; color: var(--mp-accent); background: var(--mp-control-bg);
    font-weight: 800; font-size: 0.72rem;
}
.mp-fed-row-title { font-weight: 750; color: var(--mp-text); overflow-wrap: anywhere; }
/* overflow-wrap: anywhere so a long unbreakable email/token wraps inside the card instead of forcing it wider
   than a narrow viewport (federation + admin rows reuse this class). */
.mp-fed-row-sub { margin-top: 2px; color: var(--mp-muted); font-size: 0.72rem; overflow-wrap: anywhere; }
.mp-fed-attention { color: var(--mp-accent); }
.mp-fed-badges { display: flex; flex-wrap: wrap; gap: 0.35rem; }
.mp-fed-scope .mp-badge.draft { color: var(--mp-info); border-color: var(--mp-info); }
.mp-fed-dot { display: inline-block; width: 6px; height: 6px; border-radius: 50%; background: var(--mp-good); margin-right: 2px; }

.mp-fed-row-actions { display: flex; align-items: center; justify-content: flex-end; gap: 0.35rem; flex-wrap: wrap; }
.mp-fed-scope .mp-fed-btn-sm { min-height: 1.9rem; padding: 0 0.65rem; font-size: 0.78rem; }

.mp-fed-confirm {
    margin-top: 0.4rem; padding: 0.6rem 0.7rem; border: 1px solid var(--mp-border); border-radius: 8px;
    background: var(--mp-control-bg); min-width: 14rem;
}
.mp-fed-confirm p { margin: 0 0 0.5rem; color: var(--mp-muted); font-size: 0.78rem; line-height: 1.45; }

.mp-fed-archive-notice { margin-top: 0.9rem; }

/* ---- federation access page (Manage access, federation-ownership D4.9) ---- */
.mp-fed-access-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0.9rem; align-items: start; }
.mp-fed-access-person {
    display: flex; align-items: center; justify-content: space-between; gap: 0.6rem;
    padding: 0.55rem 0; border-bottom: 1px solid var(--mp-border);
}
.mp-fed-access-person:last-of-type { border-bottom: 0; }
.mp-fed-access-addform { display: flex; gap: 0.5rem; align-items: end; margin-top: 0.75rem; flex-wrap: wrap; }
.mp-fed-access-addform .mp-fed-field { flex: 1 1 auto; min-width: 0; }

/* admin-access WP4: SystemAdmin user-search results (federation access + meet access panels) and the combined-grant checkbox row. */
.mp-fed-search-results { display: flex; flex-wrap: wrap; gap: 0.35rem; margin: 0.5rem 0; }
.mp-fed-check-row { display: flex; align-items: flex-start; gap: 0.5rem; font-size: 0.8rem; color: var(--mp-text); margin: 0.5rem 0; }

/* ---- shared form grid (new-federation form + editor sections) ---- */
.mp-fed-form-grid { display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); gap: 0.8rem; }
.mp-fed-f12 { grid-column: span 12; }
.mp-fed-f8 { grid-column: span 8; }
.mp-fed-f6 { grid-column: span 6; }
.mp-fed-f4 { grid-column: span 4; }
.mp-fed-f3 { grid-column: span 3; }
.mp-fed-form-grid label { display: block; margin-bottom: 0.3rem; color: var(--mp-muted); font-size: 0.75rem; font-weight: 700; }

/* ---- ruleset editor shell ---- */
.mp-fed-editor-shell { display: grid; grid-template-columns: 15.5rem minmax(0, 1fr); gap: 0.9rem; align-items: start; }
.mp-fed-editor-nav { position: sticky; top: 5rem; padding: 0.4rem; display: flex; flex-direction: column; gap: 0.15rem; }
.mp-fed-editor-nav a {
    display: flex; align-items: center; justify-content: space-between; gap: 0.5rem;
    padding: 0.55rem 0.6rem; border-radius: 7px; color: var(--mp-muted); text-decoration: none; font-size: 0.78rem; font-weight: 700;
}
.mp-fed-editor-nav a:hover, .mp-fed-editor-nav a:focus-visible { color: var(--mp-text); background: var(--mp-control-bg); outline: none; }
.mp-fed-editor-nav a em { min-width: 1.3rem; padding: 0.05rem 0.3rem; border: 1px solid var(--mp-border); border-radius: 999px; color: var(--mp-muted); font-size: 0.62rem; font-style: normal; text-align: center; }
.mp-fed-editor-body { min-width: 0; display: flex; flex-direction: column; gap: 0.9rem; }
.mp-fed-sec { scroll-margin-top: 5rem; }
.mp-fed-sec-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 0.75rem; margin-bottom: 0.6rem; }
.mp-fed-sec h2 { margin: 0 0 0.2rem; font-size: 1.02rem; }

.mp-fed-draft-banner {
    display: flex; align-items: center; justify-content: space-between; gap: 0.9rem; flex-wrap: wrap;
    margin-bottom: 0.9rem; padding: 0.65rem 0.75rem; border: 1px solid var(--mp-info); border-radius: 9px;
    background: color-mix(in srgb, var(--mp-info) 8%, transparent);
}
.mp-fed-draft-banner p { margin: 0.15rem 0 0; }
.mp-fed-readonly-notice { margin-bottom: 0.9rem; }

/* ---- overall matrix generator ---- */
.mp-fed-matrix-toolbar { display: flex; align-items: center; justify-content: space-between; gap: 0.75rem; flex-wrap: wrap; margin-bottom: 0.6rem; }
.mp-fed-matrix-actions { display: flex; gap: 0.5rem; flex-wrap: wrap; margin-top: 0.7rem; }
.mp-fed-matrix-count {
    margin-top: 0.7rem; align-items: flex-start;
}
.mp-fed-matrix-count span { font-weight: 800; color: var(--mp-accent); }

/* ---- review section ---- */
.mp-fed-review-list { display: grid; gap: 0; }
.mp-fed-review-row { display: flex; align-items: baseline; justify-content: space-between; gap: 0.75rem; padding: 0.5rem 0; border-bottom: 1px solid var(--mp-border); }
.mp-fed-review-row:last-child { border-bottom: 0; }
.mp-fed-review-row span { color: var(--mp-muted); font-size: 0.78rem; }
.mp-fed-status-good { color: var(--mp-good); }
.mp-fed-status-warn { color: var(--mp-accent); }
.mp-fed-status-bad { color: var(--mp-nolift); }
.mp-fed-issue-list { margin: 0.7rem 0 0; padding-left: 1.1rem; font-size: 0.8rem; line-height: 1.6; }
.mp-fed-publish-row { display: flex; align-items: center; gap: 0.6rem; flex-wrap: wrap; margin-top: 0.8rem; }

.mp-fed-savebar {
    position: sticky; bottom: 0.8rem; z-index: 5; display: flex; justify-content: flex-end;
    padding: 0.6rem; border: 1px solid var(--mp-border); border-radius: 10px; background: var(--mp-surface);
    box-shadow: 0 10px 30px rgba(0,0,0,0.3);
}

@media (max-width: 1040px) {
    .mp-fed-editor-shell { grid-template-columns: 1fr; }
    .mp-fed-editor-nav { position: static; display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 0.3rem; }
    .mp-fed-editor-nav a { flex-direction: column; text-align: center; gap: 0.2rem; }
}
@media (max-width: 760px) {
    .mp-fed-metric-grid { grid-template-columns: repeat(3, 1fr); }
    .mp-fed-filters { grid-template-columns: 1fr 1fr; }
    .mp-fed-filters .search { grid-column: 1 / -1; }
    .mp-fed-f8, .mp-fed-f6, .mp-fed-f4, .mp-fed-f3 { grid-column: span 12; }
    .mp-fed-editor-nav { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .mp-fed-head { align-items: flex-start; flex-direction: column; }
    .mp-fed-heading-actions { width: 100%; }
    .mp-fed-heading-actions .mp-btn { flex: 1; }
    /* minmax(0,1fr), not 1fr: a bare 1fr track keeps an `auto` (min-content) minimum, so a long unbreakable
       email in a row-sub would force the card past the viewport at narrow widths. */
    .mp-fed-access-grid { grid-template-columns: minmax(0, 1fr); }
    .mp-fed-access-addform { flex-direction: column; align-items: stretch; }
}
@media (max-width: 480px) {
    .mp-fed-metric-grid { grid-template-columns: repeat(2, 1fr); }
    .mp-fed-filters { grid-template-columns: 1fr; }
}
@media (max-width: 640px) {
    /* 44px touch targets, matching the Setup/admin-roles precedent. */
    .mp-fed-scope .form-control, .mp-fed-scope .mp-btn, .mp-fed-scope input[type="checkbox"] { min-height: 44px; }
    .mp-fed-scope .mp-fed-btn-sm { min-height: 2.4rem; }
    .mp-fed-savebar .mp-btn { width: 100%; }
}

/* ---- federation membership connection page (federation-membership WP3, /federations/{id}/membership) ----
   ADDITIVE ONLY. Reuses the existing --mp-* tokens and the .mp-card/.mp-card-head/.mp-btn/.mp-badge/.mp-muted/
   .mp-auth-notice / .mp-fed-confirm / .mp-fed-form-grid / .mp-fed-f… / .mp-fed-row-sub / .mp-fed-review-row / .mp-fed-btn-sm /
   `field` + `.form-control[disabled]` system throughout — no second styling framework and no new read-only field
   recipe (a disabled .form-control IS the read-only display, matching FederationAccessPage's "Current owner"
   field). The two new classes below are genuinely new layout needs: a two-column card/aside split at desktop
   width (unlike .mp-fed-access-grid's even 50/50 split, the aside here is a fixed narrower capabilities rail) and
   a left-aligned action-button row (unlike .mp-fed-row-actions, which is a table row's flex-end cluster). */
.mp-fed-conn-layout { display: grid; grid-template-columns: minmax(0, 1fr) 20rem; gap: 0.9rem; align-items: start; }
.mp-fed-conn-actions { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; margin-top: 0.9rem; }
.mp-fed-conn-credential { margin: 0; font-weight: 700; color: var(--mp-text); }
@media (max-width: 760px) {
    .mp-fed-conn-layout { grid-template-columns: minmax(0, 1fr); }
}
@media (max-width: 640px) {
    .mp-fed-conn-actions .mp-btn { min-height: 44px; }
}

/* ===== admin account detail (.mp-admin-*) =====
   admin-access WP2 (docs/specs/admin-access §4.2/§6.6): /admin/users/{userId}. ADDITIVE ONLY. The page wraps its
   content in BOTH .mp-fed-scope (reused verbatim for the muted dark form-control/select recipe and the 44px
   touch-target media query already defined above) and this .mp-admin-scope block, which only adds the
   admin-detail-specific layout: the subtab strip, the security summary grid, session/section rows and the
   set-password/reset-link confirm forms. Confirm boxes, notices, cards, badges and buttons are the existing
   shared .mp-card/.mp-btn/.mp-badge/.mp-notice/.mp-auth-notice/.mp-auth-error/.mp-fed-confirm primitives —
   nothing new is invented for those. */

.mp-admin-scope { width: 100%; }

.mp-admin-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 1rem; margin-bottom: 0.9rem; flex-wrap: wrap; }
.mp-admin-head h1 { margin: 0 0 0.3rem; }
.mp-admin-eyebrow { margin: 0 0 0.25rem; color: var(--mp-accent); font-size: 0.68rem; font-weight: 800; text-transform: uppercase; letter-spacing: 0.09em; }
.mp-admin-identity { display: flex; align-items: center; gap: 0.6rem; flex-wrap: wrap; }

/* Wraps instead of horizontally scrolling (unlike .mp-fed-scope's screen-tab strips): a handful of subtab links
   wrapping onto a second line is simpler and avoids any risk of a scroll-container's own content leaking into the
   document's scrollWidth at narrow viewports (WP0 §6.6 "no document-level horizontal overflow at 320px"). */
.mp-admin-subtabs { display: flex; flex-wrap: wrap; gap: 0.4rem; padding: 0 0 1rem; max-width: 100%; }
.mp-admin-subtab {
    display: inline-flex; align-items: center; gap: 0.35rem; white-space: nowrap; min-height: 2.25rem;
    padding: 0.4rem 0.7rem; border: 1px solid var(--mp-border); border-radius: 8px; color: var(--mp-muted);
    background: var(--mp-surface); font-size: 0.8rem; font-weight: 700;
}
.mp-admin-subtab.active { border-color: var(--mp-accent); color: var(--mp-text); background: color-mix(in srgb, var(--mp-accent) 12%, var(--mp-surface)); }
.mp-admin-subtab em { min-width: 1.2rem; padding: 0.05rem 0.3rem; border: 1px solid var(--mp-border); border-radius: 999px; font-size: 0.62rem; font-style: normal; text-align: center; }

.mp-admin-stack { display: flex; flex-direction: column; gap: 0.9rem; }

/* Security-state summary: two columns on desktop, one under 760px. */
.mp-admin-security-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0.6rem; }
.mp-admin-security-row {
    display: flex; align-items: center; justify-content: space-between; gap: 0.5rem 0.75rem; flex-wrap: wrap;
    padding: 0.55rem 0; border-bottom: 1px solid var(--mp-border);
}
.mp-admin-security-row:last-child { border-bottom: 0; }
.mp-admin-security-row span:first-child { color: var(--mp-muted); font-size: 0.8rem; }
/* A value cell holding a long, unbroken token (a long email address has no spaces to wrap at) must still be
   allowed to break — otherwise a single row can force the whole grid, and the document, wider than the viewport. */
.mp-admin-security-row > * { min-width: 0; overflow-wrap: anywhere; }

.mp-admin-session-row {
    display: flex; align-items: center; justify-content: space-between; gap: 0.75rem; flex-wrap: wrap;
    padding: 0.6rem 0; border-bottom: 1px solid var(--mp-border);
}
.mp-admin-session-row:last-child { border-bottom: 0; }
.mp-admin-session-row p { margin: 0.2rem 0 0; color: var(--mp-muted); font-size: 0.75rem; }

.mp-admin-list-row {
    display: flex; align-items: center; justify-content: space-between; gap: 0.75rem; flex-wrap: wrap;
    padding: 0.55rem 0; border-bottom: 1px solid var(--mp-border);
}
.mp-admin-list-row:last-child { border-bottom: 0; }
.mp-admin-list-row .mp-fed-row-sub { margin-top: 2px; }

.mp-admin-security-option {
    padding: 0.9rem; border: 1px solid var(--mp-border); border-radius: 10px; background: var(--mp-surface);
}
.mp-admin-security-option.recommended { border-color: color-mix(in srgb, var(--mp-accent) 55%, var(--mp-border)); }
.mp-admin-security-option h3 { margin: 0.4rem 0 0.35rem; font-size: 0.95rem; }
.mp-admin-security-option p { margin: 0 0 0.7rem; color: var(--mp-muted); font-size: 0.8rem; line-height: 1.5; }
.mp-admin-security-options { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0.7rem; }

/* Set-password / reset-link confirm forms: reuse .mp-fed-confirm's box, add a simple stacked field grid. */
.mp-admin-scope .mp-fed-confirm { max-width: 32rem; }
.mp-admin-form-grid { display: grid; gap: 0.65rem; margin: 0.6rem 0; }
.mp-admin-form-grid label { display: block; margin-bottom: 0.3rem; color: var(--mp-muted); font-size: 0.78rem; font-weight: 700; }
.mp-admin-policy-line { margin: -0.35rem 0 0; color: var(--mp-muted); font-size: 0.72rem; }
.mp-admin-check-row { display: flex; align-items: flex-start; gap: 0.5rem; font-size: 0.8rem; color: var(--mp-text); }
.mp-admin-locked-note { display: flex; gap: 0.5rem; align-items: flex-start; color: var(--mp-muted); font-size: 0.78rem; line-height: 1.45; }

.mp-admin-notfound { max-width: 34rem; }

@media (max-width: 760px) {
    /* minmax(0, 1fr), not a bare 1fr: a bare track's min size is content-based, so a long unbroken value (e.g. a
       lockout timestamp) would still force the grid — and the document — wider than the viewport. */
    .mp-admin-security-grid, .mp-admin-security-options { grid-template-columns: minmax(0, 1fr); }
    .mp-admin-head { flex-direction: column; align-items: flex-start; }
}
@media (max-width: 640px) {
    /* 44px touch targets, matching every other admin surface. */
    .mp-admin-scope .mp-btn, .mp-admin-scope input[type="text"], .mp-admin-scope input[type="password"],
    .mp-admin-scope input[type="checkbox"], .mp-admin-scope select, .mp-admin-subtab { min-height: 44px; }
}

/* ===== meet access & team workspace (.mp-meetaccess-*) =====
   Admin-access WP4 (spec §4.4): the /meets/{id}/manage?tab=access panel (MeetAccessPanel.razor). Follows the
   .mp-fed-* access-page structure verbatim (same field/confirm/badge/row-sub primitives, reused directly rather
   than duplicated) and adds only the layout this panel needs beyond that. */
.mp-meetaccess-scope { width: 100%; }
.mp-meetaccess-notice {
    display: flex; flex-direction: column; gap: 0.15rem; padding: 0.6rem 0.75rem; margin-bottom: 0.75rem;
    border: 1px solid var(--mp-border); border-radius: 9px; background: var(--mp-surface); font-size: 0.8rem;
}
.mp-meetaccess-notice p { margin: 0; color: var(--mp-muted); }

.mp-meetaccess-addcard { margin-bottom: 0.9rem; }
.mp-meetaccess-addform { margin-top: 0.5rem; }
.mp-meetaccess-add-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 0.6rem; align-items: end; }

.mp-meetaccess-row {
    display: flex; flex-direction: column; gap: 0.35rem;
    padding: 0.65rem 0; border-bottom: 1px solid var(--mp-border);
}
.mp-meetaccess-row:last-child { border-bottom: 0; }
.mp-meetaccess-row-top { display: flex; align-items: flex-start; justify-content: space-between; gap: 0.75rem; flex-wrap: wrap; }
.mp-meetaccess-identity { min-width: 0; }
.mp-meetaccess-roles { display: flex; flex-wrap: wrap; gap: 0.35rem; align-items: center; }
.mp-meetaccess-actions { display: flex; flex-wrap: wrap; gap: 0.4rem; align-items: center; }
.mp-meetaccess-editroles { margin-top: 0.4rem; padding: 0.65rem 0.75rem; border: 1px solid var(--mp-border); border-radius: 9px; background: var(--mp-control-bg); }
.mp-meetaccess-role-checks { display: grid; gap: 0.4rem; }

@media (max-width: 760px) {
    .mp-meetaccess-add-grid { grid-template-columns: 1fr; }
    .mp-meetaccess-row-top { flex-direction: column; align-items: flex-start; }
}
@media (max-width: 640px) {
    /* 44px touch targets, matching every other admin/access surface. */
    .mp-meetaccess-scope .mp-btn, .mp-meetaccess-scope .form-control,
    .mp-meetaccess-scope input[type="checkbox"], .mp-meetaccess-scope select { min-height: 44px; }
}

/* ===== meet handlers workspace (.mp-handlers-*) =====
   Admin-access WP5b (spec §4.5): the SystemAdmin-only /meets/{id}/manage?tab=handlers panel
   (MeetHandlersPanel.razor). Follows the .mp-meetaccess- and .mp-fed- structure verbatim (same field/confirm/badge/
   row-sub primitives, reused directly rather than duplicated) and adds only the layout this panel needs beyond
   that. */
.mp-handlers-scope { width: 100%; }
.mp-handlers-notice {
    display: flex; flex-direction: column; gap: 0.15rem; padding: 0.6rem 0.75rem; margin-bottom: 0.75rem;
    border: 1px solid var(--mp-border); border-radius: 9px; background: var(--mp-surface); font-size: 0.8rem;
}
.mp-handlers-notice p { margin: 0; color: var(--mp-muted); }

.mp-handlers-assigncard { margin-bottom: 0.9rem; }
.mp-handlers-assignform { margin-top: 0.5rem; }
.mp-handlers-assign-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0.6rem; align-items: start; }
.mp-handlers-selected-handler { margin: 0.3rem 0 0; font-size: 0.85rem; }
.mp-handlers-scope-checks { display: grid; gap: 0.4rem; margin: 0.6rem 0; }

.mp-handlers-row {
    display: flex; flex-direction: column; gap: 0.3rem;
    padding: 0.7rem 0; border-bottom: 1px solid var(--mp-border);
}
.mp-handlers-row:last-child { border-bottom: 0; }
.mp-handlers-row-top { display: flex; align-items: flex-start; justify-content: space-between; gap: 0.75rem; flex-wrap: wrap; }
.mp-handlers-identity { min-width: 0; }
.mp-handlers-badges { display: flex; flex-wrap: wrap; gap: 0.35rem; align-items: center; }
.mp-handlers-actions { display: flex; flex-wrap: wrap; gap: 0.4rem; align-items: center; margin-top: 0.15rem; }

@media (max-width: 760px) {
    .mp-handlers-assign-grid { grid-template-columns: 1fr; }
    .mp-handlers-row-top { flex-direction: column; align-items: flex-start; }
}
@media (max-width: 640px) {
    /* 44px touch targets, matching every other admin/access surface. */
    .mp-handlers-scope .mp-btn, .mp-handlers-scope .form-control,
    .mp-handlers-scope input[type="checkbox"], .mp-handlers-scope select { min-height: 44px; }
}

/* ===== meet creation (.mp-create-*) =====
   Federation defaults WP4 (docs/specs/federation-defaults §7.1/§7.2; visual reference
   strength-meet-federation-create-mockup.html "Create meet"). Appended block, every class prefixed .mp-create-, every
   colour a --mp-* token. Deliberately NO max-width anywhere: the page sits directly inside .mp-container and honours
   the global wide/narrow toggle (spec §7.1 "remove the page-local max-width:860px").

   The control styling mirrors the Setup tab's muted-field family (.mp-setup-scope) rather than reusing that class, so
   /meets/create picks up the same dark field surface, 38px minimum height, 7px radius and accent focus ring without
   inheriting the Setup shell's savebar padding or grid. */
.mp-create-scope .form-control {
    display: block; width: 100%; min-height: 38px; padding: 0 0.65rem; color: var(--mp-text);
    background: var(--mp-control-bg); border: 1px solid var(--mp-control-border); border-radius: 7px;
    box-shadow: inset 0 1px 1px rgba(0,0,0,0.2); outline: none;
    transition: border-color .14s ease, background-color .14s ease, box-shadow .14s ease;
}
.mp-create-scope .form-control::placeholder { color: var(--mp-control-placeholder); opacity: 1; }
.mp-create-scope .form-control:hover:not(:disabled):not([readonly]) { background: var(--mp-control-bg-hover); border-color: #435164; }
.mp-create-scope .form-control:focus, .mp-create-scope .form-control:focus-visible {
    border-color: var(--mp-control-border-focus); background: #19212b;
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--mp-control-border-focus) 22%, transparent), inset 0 1px 1px rgba(0,0,0,0.2);
}
.mp-create-scope .form-control[readonly] { color: var(--mp-muted); background: color-mix(in srgb, var(--mp-control-bg) 70%, var(--mp-bg)); border-style: dashed; }
.mp-create-scope .form-control.invalid, .mp-create-scope .form-control[aria-invalid="true"] {
    border-color: var(--mp-nolift);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--mp-nolift) 18%, transparent), inset 0 1px 1px rgba(0,0,0,0.2);
}
.mp-create-scope select.form-control {
    appearance: none; -webkit-appearance: none;
    background-image: linear-gradient(45deg, transparent 50%, #7d8999 50%), linear-gradient(135deg, #7d8999 50%, transparent 50%);
    background-position: calc(100% - 15px) 52%, calc(100% - 10px) 52%; background-size: 4px 4px, 4px 4px; background-repeat: no-repeat;
    padding-right: 1.7rem;
}
.mp-create-scope input[type="checkbox"] { accent-color: var(--mp-accent); width: 15px; height: 15px; }
.mp-create-scope .validation-message { display: block; margin-top: 0.3rem; color: var(--mp-nolift); font-size: 0.78rem; font-weight: 700; }

/* ---- layout: ~70/30 with a sticky summary, one column below 1040px (spec §7.2) ---- */
.mp-create-layout {
    display: grid; grid-template-columns: minmax(0, 1.75fr) minmax(290px, 0.68fr);
    gap: 1rem; align-items: start; width: 100%;
}
.mp-create-main { min-width: 0; }
.mp-create-aside { min-width: 0; }
.mp-create-sticky { position: sticky; top: 1rem; }
@media (max-width: 1040px) {
    .mp-create-layout { grid-template-columns: 1fr; }
    .mp-create-sticky { position: static; }
}

/* ---- cards ---- */
.mp-create-card { padding: 0.95rem 1.05rem 1.1rem; margin-bottom: 0.9rem; }
.mp-create-card .mp-card-head { margin-bottom: 0.85rem; }
.mp-create-cardtitle { display: flex; align-items: flex-start; gap: 0.65rem; min-width: 0; }
.mp-create-cardtitle h2 { margin: 0; font-size: 1.02rem; letter-spacing: -0.015em; }
.mp-create-cardtitle p { margin: 0.15rem 0 0; font-size: 0.78rem; }
.mp-create-cardicon {
    width: 31px; height: 31px; flex: 0 0 auto; display: grid; place-items: center;
    border: 1px solid var(--mp-control-border); border-radius: 8px;
    color: var(--mp-accent); background: var(--mp-surface-2); font-weight: 800; font-size: 0.8rem;
}

/* ---- ruleset picker + preview ---- */
.mp-create-picker {
    display: grid; grid-template-columns: minmax(220px, 0.8fr) minmax(0, 1.2fr); gap: 0.9rem;
    padding: 0.85rem; border: 1px solid var(--mp-control-border); border-radius: 10px;
    background: linear-gradient(105deg, color-mix(in srgb, var(--mp-accent) 9%, transparent), transparent 45%), var(--mp-surface-2);
}
.mp-create-preview { min-width: 0; padding-left: 0.85rem; border-left: 1px solid var(--mp-border); }
.mp-create-preview-line { display: flex; align-items: flex-start; justify-content: space-between; gap: 0.6rem; margin-bottom: 0.5rem; }
.mp-create-preview-name { font-size: 0.95rem; font-weight: 750; }
.mp-create-preview-meta { color: var(--mp-muted); font-size: 0.78rem; }
.mp-create-badges { display: flex; flex-wrap: wrap; gap: 0.35rem; }
.mp-create-badges .mp-badge { font-size: 0.68rem; text-transform: none; letter-spacing: 0; }
@media (max-width: 760px) {
    .mp-create-picker { grid-template-columns: 1fr; }
    .mp-create-preview { padding: 0.8rem 0 0; border-left: 0; border-top: 1px solid var(--mp-border); }
}

/* ---- skeleton (selector not yet resolved) ---- */
.mp-create-skeleton { display: grid; gap: 0.5rem; padding: 0.85rem; border: 1px solid var(--mp-border); border-radius: 10px; }
.mp-create-skeleton-bar { display: block; height: 38px; border-radius: 7px; background: var(--mp-surface-2); }
.mp-create-skeleton-bar.short { width: 55%; height: 14px; }

/* ---- notices ---- */
.mp-create-notice, .mp-create-alert {
    display: flex; gap: 0.6rem; margin-top: 0.75rem; padding: 0.65rem 0.7rem;
    border: 1px solid var(--mp-border); border-radius: 8px;
    color: var(--mp-muted); background: var(--mp-surface-2); font-size: 0.8rem; line-height: 1.5;
}
.mp-create-notice strong, .mp-create-alert strong { color: var(--mp-text); }
.mp-create-notice.info { border-color: color-mix(in srgb, var(--mp-info) 45%, transparent); background: color-mix(in srgb, var(--mp-info) 9%, transparent); }
.mp-create-notice.warning { border-color: color-mix(in srgb, var(--mp-accent) 45%, transparent); background: color-mix(in srgb, var(--mp-accent) 9%, transparent); }
.mp-create-alert { margin: 0 0 1rem; border-color: var(--mp-nolift); background: color-mix(in srgb, var(--mp-nolift) 12%, transparent); }
.mp-create-notice-icon { flex: 0 0 auto; color: var(--mp-accent); font-weight: 800; }
.mp-create-alert .mp-create-notice-icon { color: var(--mp-nolift); }

/* ---- 12-column form grid (mock-up f12/f8/f6/f4/f3 spans) ---- */
.mp-create-grid { display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); gap: 0.8rem; }
.mp-create-field { min-width: 0; grid-column: span 12; }
.mp-create-f12 { grid-column: span 12; }
.mp-create-f8 { grid-column: span 8; }
.mp-create-f6 { grid-column: span 6; }
.mp-create-f4 { grid-column: span 4; }
.mp-create-f3 { grid-column: span 3; }
.mp-create-field label { display: block; margin-bottom: 0.3rem; color: #a0aaba; font-size: 0.72rem; font-weight: 720; }
.mp-create-field label span { color: var(--mp-muted); font-weight: 550; }
.mp-create-help { margin-top: 0.3rem; color: var(--mp-muted); font-size: 0.7rem; }
@media (max-width: 760px) {
    .mp-create-f8, .mp-create-f6, .mp-create-f4, .mp-create-f3 { grid-column: span 12; }
}

/* ---- sticky summary ---- */
.mp-create-summary-list { display: grid; gap: 0; margin-top: 0.55rem; }
.mp-create-summary-row {
    display: flex; align-items: baseline; justify-content: space-between; gap: 0.75rem;
    padding: 0.5rem 0; border-bottom: 1px solid var(--mp-border);
}
.mp-create-summary-row:last-child { border-bottom: 0; }
.mp-create-summary-row span { color: var(--mp-muted); font-size: 0.75rem; }
.mp-create-summary-row strong { min-width: 0; text-align: right; font-size: 0.8rem; overflow-wrap: anywhere; }
.mp-create-check { display: flex; align-items: flex-start; gap: 0.5rem; margin-top: 0.7rem; color: var(--mp-muted); font-size: 0.75rem; line-height: 1.5; }
.mp-create-actions { display: grid; gap: 0.5rem; margin-top: 0.9rem; }
.mp-create-actions .mp-btn { width: 100%; min-height: 36px; text-align: center; }
.mp-create-foot { margin: 0.7rem 0 0; color: var(--mp-muted); font-size: 0.7rem; text-align: center; }

@media (max-width: 640px) {
    /* 44px touch targets, matching the Setup/profile/admin rules above. */
    .mp-create-scope .form-control, .mp-create-scope .mp-btn { min-height: 44px; }
    .mp-create-card { padding: 0.85rem 0.9rem 1rem; }
}

/* ==== Email notifications WP4 (spec §4, §9) — Communications workspace, settings, composer, providers ====
   Everything below is scoped under .mp-comms-scope (CommunicationsPanel's outer wrapper, plus the Setup tab's
   compact CommsSummaryCard and the results-publish dialog's email option). Reuses --mp-* tokens and the existing
   .mp-card/.mp-btn/.mp-badge/.mp-table/.mp-toggle-line/.mp-overflow/.mp-muted/.form-control system — no new CSS
   framework, no copy from the mock-up's own :root variables (WP0 §1.3). Breakpoints per spec §9: desktop >=1280
   (default), tablet 768-1279, mobile <=767 — no new fixed page max-width is introduced. */

.mp-comms-scope { width: 100%; max-width: none; }
.mp-comms-scope .mp-muted { color: var(--mp-muted); }

.mp-comms-view-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 1rem; flex-wrap: wrap; margin-bottom: 0.85rem; }
.mp-comms-view-head h2 { margin: 0 0 0.2rem; }
.mp-comms-header-actions { display: flex; gap: 0.5rem; flex-wrap: wrap; }

.mp-comms-status { border-radius: 10px; padding: 0.7rem 0.9rem; font-weight: 700; margin-bottom: 0.75rem; }
.mp-comms-status.success { border: 1px solid var(--mp-good); color: var(--mp-good); background: color-mix(in srgb, var(--mp-good) 12%, var(--mp-surface)); }
.mp-comms-status.error { border: 1px solid var(--mp-nolift); color: var(--mp-nolift); background: color-mix(in srgb, var(--mp-nolift) 12%, var(--mp-surface)); }
.mp-comms-status.warn { border: 1px solid var(--mp-accent); color: var(--mp-accent); background: color-mix(in srgb, var(--mp-accent) 12%, var(--mp-surface)); font-weight: 700; padding: 0.4rem 0.6rem; border-radius: 8px; }

.mp-comms-scope .mp-banner {
    display: flex; gap: 0.7rem; align-items: flex-start; border-radius: 10px; padding: 0.75rem 0.9rem;
    margin-bottom: 0.85rem; border: 1px solid color-mix(in srgb, var(--mp-info, #4da3ff) 40%, var(--mp-border));
    background: color-mix(in srgb, var(--mp-info, #4da3ff) 8%, var(--mp-surface));
}
.mp-comms-scope .mp-banner.warn { border-color: color-mix(in srgb, var(--mp-accent) 45%, var(--mp-border)); background: color-mix(in srgb, var(--mp-accent) 9%, var(--mp-surface)); }
.mp-comms-scope .mp-banner.bad { border-color: color-mix(in srgb, var(--mp-nolift) 45%, var(--mp-border)); background: color-mix(in srgb, var(--mp-nolift) 9%, var(--mp-surface)); }
.mp-comms-scope .mp-banner b { display: block; margin-bottom: 0.15rem; }

.mp-comms-grid2 { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1rem; align-items: start; }
.mp-comms-grid4 { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 0.85rem; }
.mp-comms-two-col { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0 0.85rem; }
.mp-comms-full { grid-column: 1 / -1; }

.mp-comms-metric-value { font-size: 1.35rem; font-weight: 850; margin: 0.35rem 0 0.3rem; }
.mp-comms-section-title { display: flex; align-items: center; justify-content: space-between; gap: 0.85rem; margin-bottom: 0.5rem; flex-wrap: wrap; }
.mp-comms-section-title h3 { margin: 0; }
.mp-comms-row-actions { display: flex; gap: 0.5rem; white-space: nowrap; }
.mp-comms-footer-actions { display: flex; justify-content: flex-end; gap: 0.5rem; flex-wrap: wrap; margin-top: 0.9rem; padding-top: 0.85rem; border-top: 1px solid var(--mp-border); }
.mp-comms-savebar { display: flex; justify-content: flex-end; margin-top: 1rem; }

.mp-comms-scope .mp-title { font-weight: 760; }
.mp-comms-table-wrap { overflow-x: auto; }

.mp-comms-provider-row {
    display: flex; align-items: center; gap: 0.75rem; padding: 0.7rem 0.85rem; border: 1px solid var(--mp-border);
    border-radius: 10px; margin-bottom: 0.5rem; cursor: pointer; text-decoration: none; color: inherit;
}
.mp-comms-provider-row.selected { border-color: var(--mp-accent); box-shadow: 0 0 0 2px color-mix(in srgb, var(--mp-accent) 12%, transparent); }
.mp-comms-provider-row input[type="radio"] { width: 1.05rem; height: 1.05rem; accent-color: var(--mp-accent); flex: 0 0 auto; }
.mp-comms-provider-row > span.mp-badge { margin-left: auto; }

.mp-comms-rule { display: grid; grid-template-columns: 42px minmax(0, 1fr) auto; align-items: start; gap: 0.85rem; padding: 0.85rem 0; border-top: 1px solid var(--mp-border); }
.mp-comms-rule:first-of-type { border-top: 0; }
.mp-comms-rule h4 { margin: 0 0 0.2rem; }
.mp-comms-rule p { margin: 0; }
.mp-comms-rule-icon { width: 1.8rem; height: 1rem; }
.mp-comms-rule > a.mp-linkbtn { white-space: nowrap; }
@media (max-width: 767px) {
    .mp-comms-rule { grid-template-columns: 42px minmax(0, 1fr); }
    .mp-comms-rule > a.mp-linkbtn { grid-column: 2; }
}

.mp-comms-recipients { margin-top: 0.6rem; display: flex; flex-direction: column; gap: 0.4rem; max-width: 26rem; }
.mp-comms-recipient-row { display: flex; align-items: center; gap: 0.5rem; }
.mp-comms-recipient-row .form-control { flex: 1 1 auto; }

.mp-comms-chip-row { display: flex; gap: 0.45rem; flex-wrap: wrap; margin: 0.4rem 0 0.7rem; }
.mp-comms-chip {
    display: inline-flex; align-items: center; gap: 0.35rem; border: 1px solid var(--mp-border); background: var(--mp-surface-2);
    color: var(--mp-muted); border-radius: 999px; padding: 0.4rem 0.7rem; cursor: pointer; font-size: 0.82rem;
}
.mp-comms-chip.selected { border-color: var(--mp-accent); color: var(--mp-text); background: color-mix(in srgb, var(--mp-accent) 10%, var(--mp-surface-2)); }
.mp-comms-chip input[type="checkbox"] { accent-color: var(--mp-accent); }

.mp-comms-count {
    display: flex; gap: 0.85rem; align-items: center; padding: 0.7rem 0.8rem; border-radius: 10px;
    border: 1px solid color-mix(in srgb, var(--mp-info, #4da3ff) 30%, var(--mp-border));
    background: color-mix(in srgb, var(--mp-info, #4da3ff) 7%, var(--mp-surface)); margin: 0.6rem 0;
}
.mp-comms-count strong { font-size: 1.35rem; }

.mp-comms-review { display: grid; grid-template-columns: 8rem 1fr; gap: 0.5rem 0.6rem; margin: 0; }
.mp-comms-review dt { color: var(--mp-muted); }
.mp-comms-review dd { margin: 0; overflow-wrap: anywhere; }

.mp-comms-radio-row { display: flex; gap: 0.5rem; flex-wrap: wrap; }
.mp-comms-radio-choice {
    display: inline-flex; align-items: center; gap: 0.4rem; border: 1px solid var(--mp-border); border-radius: 9px;
    padding: 0.5rem 0.75rem; cursor: pointer; font-size: 0.85rem;
}
.mp-comms-radio-choice.selected { border-color: var(--mp-accent); background: color-mix(in srgb, var(--mp-accent) 8%, transparent); }
.mp-comms-radio-choice input[type="radio"] { accent-color: var(--mp-accent); }

.mp-comms-editor-tools {
    display: flex; gap: 0.2rem; flex-wrap: wrap; align-items: center; border: 1px solid var(--mp-border);
    border-bottom: 0; border-radius: 9px 9px 0 0; padding: 0.35rem; background: var(--mp-surface-2);
}
.mp-comms-editor-tools button {
    border: 0; background: transparent; color: var(--mp-muted); padding: 0.3rem 0.5rem; border-radius: 5px; cursor: pointer;
}
.mp-comms-editor-tools button:hover { color: var(--mp-text); background: var(--mp-surface-3, var(--mp-surface)); }
.mp-comms-editor-tools select {
    margin-left: auto; background: var(--mp-control-bg); color: var(--mp-text); border: 1px solid var(--mp-control-border);
    border-radius: 6px; padding: 0.2rem 0.4rem; font-size: 0.8rem;
}
.mp-comms-editor-textarea { border-radius: 0 0 9px 9px !important; }

/* Email preview (email-redesign WP0 §2): the rendered HTML document sits in a sandboxed iframe (it is now a
   complete StrengthMeetEmailFrame document, not an author fragment, so it must never be injected inline), and the
   authored plain-text alternative renders below it in a <pre> — whitespace-preserving, word-wrapped so a long
   action URL never forces the card wider than its column. */
.mp-comms-preview-frame {
    display: block; width: 100%; height: 32rem; border: 1px solid var(--mp-border); border-radius: 8px;
    background: #ffffff; margin-top: 0.5rem;
}
.mp-comms-preview-body {
    border: 1px solid var(--mp-border); border-radius: 8px; padding: 0.75rem 0.9rem; background: var(--mp-surface-2);
    white-space: pre-wrap; word-break: break-word; font-family: inherit; font-size: 0.85rem; margin: 0.5rem 0 0;
}

.mp-comms-webhook-reveal { border-color: var(--mp-accent); margin-bottom: 0.85rem; }
.mp-comms-reveal-row { display: flex; gap: 0.5rem; align-items: center; }
.mp-comms-reveal-row .form-control { flex: 1 1 auto; font-family: monospace; font-size: 0.8rem; }

.mp-comms-summary-card .mp-comms-summary-list { display: grid; grid-template-columns: auto 1fr; gap: 0.35rem 0.7rem; margin: 0.5rem 0 0.85rem; font-size: 0.85rem; }
.mp-comms-summary-card dt { color: var(--mp-muted); }
.mp-comms-summary-card dd { margin: 0; }

/* Native <dialog> chrome — same shape as ResultsWorkspace's mp-rw-dialog, kept as an independent class here so
   this feature never depends on another feature's CSS-isolated stylesheet (which would not even apply, since
   isolation scopes rules to elements ResultsWorkspace itself renders). */
.mp-comms-dialog {
    background: var(--mp-surface); color: var(--mp-text); border: 1px solid var(--mp-border);
    border-radius: 12px; padding: 1.25rem 1.4rem; width: min(30rem, calc(100vw - 2rem)); max-width: 30rem;
}
.mp-comms-dialog::backdrop { background: rgba(0, 0, 0, 0.55); }
.mp-comms-dialog h3 { margin-top: 0; }
.mp-comms-dialog-wide { width: min(46rem, calc(100vw - 2rem)); max-width: 46rem; max-height: calc(100vh - 4rem); overflow-y: auto; }

.mp-comms-entry-picker { margin: 0.6rem 0; padding-top: 0.5rem; border-top: 1px dashed var(--mp-border); }
.mp-comms-entry-search { margin: 0.5rem 0 0.75rem; max-width: 24rem; }

/* Mobile card fallback for tables (mock-up pattern, spec §9) — hidden by default, swapped in under the mobile
   breakpoint below. */
.mp-comms-mobile-cards { display: none; }
.mp-comms-mobile-row { border: 1px solid var(--mp-border); background: var(--mp-surface-2); padding: 0.75rem; border-radius: 10px; margin-bottom: 0.5rem; }
.mp-comms-mobile-split { display: flex; justify-content: space-between; align-items: center; gap: 0.6rem; margin-top: 0.4rem; }

/* ---- tablet (768-1279px) ---- */
@media (max-width: 1279px) {
    .mp-comms-grid4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* ---- mobile (<=767px) ---- */
@media (max-width: 767px) {
    .mp-comms-grid2, .mp-comms-two-col, .mp-comms-grid4 { grid-template-columns: 1fr; }
    .mp-comms-full { grid-column: auto; }
    .mp-comms-view-head { flex-direction: column; align-items: stretch; }
    .mp-comms-header-actions { width: 100%; }
    .mp-comms-header-actions .mp-btn { flex: 1 1 auto; text-align: center; }
    .mp-comms-desktop-table { display: none; }
    .mp-comms-mobile-cards { display: block; }
    .mp-comms-review { grid-template-columns: 1fr; gap: 0.15rem; }
    .mp-comms-review dd { margin-bottom: 0.5rem; }
    .mp-comms-dialog { padding: 1rem; }
}

/* ---- Email notifications WP6: pre-start locked-board panel (LockedBoardPanel.razor) ----
   Shared by Scoreboard/PlatformDisplay/RunMeet — everything renders around it (roster/grid shape
   stays visible; see each page's own hidden-cell rendering), so this is a quiet inline card, not a full takeover. */
.mp-lock-panel {
    display: flex; flex-direction: column; align-items: center; text-align: center; gap: 0.4rem;
    padding: 1.6rem 1.2rem; margin: 0.75rem 0; border: 1px dashed var(--mp-border); border-radius: 12px;
    background: var(--mp-surface-2);
}
.mp-lock-panel .mp-lock-icon { font-size: 1.8rem; line-height: 1; }
.mp-lock-panel b { font-size: 1.05rem; }
.mp-lock-panel .mp-lock-sub { color: var(--mp-muted); font-size: 0.85rem; max-width: 36rem; }

/* OBS-safe variant (Overlay.razor): no opaque backdrop over the transparent canvas, thin accent border, small
   footprint centred over whatever the scene composites behind it. */
.mp-ovl-lock-panel {
    display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 0.5rem;
    position: fixed; left: 50%; top: 46%; transform: translate(-50%, -50%); z-index: 20;
    padding: 1.2rem 1.6rem; border-radius: 12px; text-align: center; max-width: 26rem;
    background: color-mix(in srgb, var(--mp-bg, #0d1117) 74%, transparent);
    border: 1px solid color-mix(in srgb, var(--mp-accent, #f0a500) 45%, transparent);
    color: var(--mp-text, #e6edf3);
}
.mp-ovl-lock-panel .mp-ovl-lock-icon { font-size: 2rem; }
.mp-ovl-lock-panel b { font-size: 1rem; }
.mp-ovl-lock-panel .mp-lock-sub { font-size: 0.78rem; opacity: 0.85; }

/* ==== Lift-result-rollback: "Undo last lift result" (RunMeet.razor toolbar + UndoLastResultDialog +
   RecentResultsDrawer + run-board-undo.js) ====
   Reuses the existing --mp-* tokens and .mp-card/.mp-btn/.mp-badge/.mp-lights/.mp-light system throughout — no new
   styling framework. Native <dialog> chrome mirrors .mp-comms-dialog's shape (see that rule's own comment) so this
   feature doesn't depend on another feature's CSS-isolated stylesheet. */

.mp-undo-toolbar {
    display: flex; align-items: center; gap: 0.6rem; flex-wrap: wrap;
    padding-left: 0.6rem; margin-left: 0.2rem; border-left: 1px solid var(--mp-border);
}
.mp-undo-hint { font-size: 0.78rem; white-space: nowrap; }
.mp-undo-toolbar .mp-badge { margin-left: 0.35rem; }

.mp-undo-dialog, .mp-undo-drawer {
    background: var(--mp-surface); color: var(--mp-text); border: 1px solid var(--mp-border);
    border-radius: 12px; padding: 1.25rem 1.4rem;
}
.mp-undo-dialog { width: min(30rem, calc(100vw - 2rem)); max-width: 30rem; max-height: calc(100vh - 4rem); overflow-y: auto; }
.mp-undo-dialog::backdrop, .mp-undo-drawer::backdrop { background: rgba(0, 0, 0, 0.55); }
.mp-undo-dialog-title { margin: 0 0 0.75rem; display: flex; align-items: center; gap: 0.4rem; color: var(--mp-nolift); }

.mp-undo-target {
    border: 1px solid var(--mp-border); border-radius: 10px; padding: 0.75rem 0.9rem; margin-bottom: 0.85rem;
    background: var(--mp-surface-2);
}
.mp-undo-target-row { display: flex; align-items: baseline; gap: 0.6rem; flex-wrap: wrap; }
.mp-undo-target-name { font-weight: 800; font-size: 1.02rem; }
.mp-undo-target-lift { color: var(--mp-muted); font-size: 0.88rem; }
.mp-undo-target-meta { display: flex; align-items: center; gap: 0.6rem; flex-wrap: wrap; margin-top: 0.5rem; font-size: 0.8rem; }
.mp-undo-lights[hidden] { display: none; }

.mp-undo-impact { color: var(--mp-muted); font-size: 0.85rem; margin: 0 0 0.85rem; }

.mp-undo-stale-notice {
    border: 1px solid var(--mp-accent); background: color-mix(in srgb, var(--mp-accent) 14%, var(--mp-surface));
    border-radius: 10px; padding: 0.65rem 0.85rem; margin-bottom: 0.85rem; font-size: 0.85rem; font-weight: 650;
}

.mp-undo-reasons { border: 0; padding: 0; margin: 0 0 0.85rem; }
.mp-undo-reasons legend { font-size: 0.78rem; font-weight: 650; color: var(--mp-muted); margin-bottom: 0.4rem; padding: 0; }
.mp-undo-reason {
    display: flex; align-items: center; gap: 0.5rem; padding: 0.4rem 0.15rem; font-size: 0.9rem; cursor: pointer;
}
.mp-undo-reason input[type="radio"] { accent-color: var(--mp-accent); width: 1.05rem; height: 1.05rem; flex: 0 0 auto; }

.mp-undo-dialog textarea.form-control { min-height: 4rem; resize: vertical; width: 100%; box-sizing: border-box; }

.mp-undo-dialog-error {
    display: flex; align-items: center; gap: 0.6rem; flex-wrap: wrap;
    color: var(--mp-nolift); font-weight: 700; margin-top: 0.7rem; font-size: 0.85rem;
}
.mp-undo-dialog-actions { display: flex; justify-content: flex-end; gap: 0.5rem; margin-top: 1.1rem; }

/* Recent-results drawer: a right-hand sheet (same reasoning as .mp-e-drawer, but a native <dialog> for the free
   focus trap/Escape/focus-return .mp-e-drawer never got). ::backdrop only paints once showModal() is used. */
.mp-undo-drawer {
    /* The UA <dialog> stylesheet sets its own max-width (~100vw - 6px - 2em); without an explicit override here it
       wins over the plain `width` below and the drawer renders narrower than min(32rem, 100%) on a narrow viewport. */
    position: fixed; inset: 0 0 0 auto; margin: 0; width: min(32rem, 100%); max-width: min(32rem, 100%);
    height: 100%; max-height: 100vh;
    border-radius: 0; border-left: 1px solid var(--mp-border); border-top: 0; border-right: 0; border-bottom: 0;
    overflow-y: auto;
}
.mp-undo-drawer-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 0.6rem; margin-bottom: 0.6rem; }
.mp-undo-drawer-head h3 { margin: 0; }
.mp-undo-drawer-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 0.5rem; }
.mp-undo-drawer-row {
    display: grid; grid-template-columns: 1.6rem 1fr auto; align-items: center; gap: 0.7rem;
    border: 1px solid var(--mp-border); border-radius: 10px; padding: 0.6rem 0.75rem; background: var(--mp-surface-2);
}
.mp-undo-drawer-row.next-to-undo { border-color: var(--mp-accent); }
.mp-undo-drawer-row.rolled-back { opacity: 0.55; }
.mp-undo-drawer-order { color: var(--mp-muted); font-weight: 700; font-size: 0.85rem; text-align: center; }
.mp-undo-drawer-name { font-weight: 700; }
.mp-undo-drawer-meta { font-size: 0.78rem; margin-top: 0.15rem; }
.mp-undo-drawer-status {
    font-size: 0.72rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.03em; text-align: right;
    color: var(--mp-muted); white-space: nowrap;
}
.mp-undo-drawer-status.next-to-undo { color: var(--mp-accent); }
.mp-undo-drawer-status.rolled-back { color: var(--mp-muted); text-decoration: line-through; }

/* Post-success banner (run-board-undo.js renders this from sessionStorage after the reload it triggers). */
.mp-undo-banner {
    display: flex; align-items: center; justify-content: space-between; gap: 0.75rem; flex-wrap: wrap;
    border: 1px solid var(--mp-good); background: color-mix(in srgb, var(--mp-good) 12%, var(--mp-surface));
    border-radius: 10px; padding: 0.7rem 0.9rem; margin: 0 0 0.75rem; font-weight: 650;
}
@media (prefers-reduced-motion: no-preference) {
    .mp-undo-banner { animation: mp-undo-banner-in 0.18s ease-out; }
    @keyframes mp-undo-banner-in { from { opacity: 0; transform: translateY(-4px); } to { opacity: 1; transform: none; } }
}

/* ---- mobile (<=520px): dialog/drawer actions stack full width, toolbar wraps (spec) ---- */
@media (max-width: 520px) {
    .mp-undo-toolbar { width: 100%; border-left: 0; padding-left: 0; margin-left: 0; }
    .mp-undo-toolbar .mp-btn { width: 100%; text-align: center; }
    .mp-undo-hint { width: 100%; white-space: normal; }
    .mp-undo-dialog { width: 100%; max-width: 100%; padding: 1rem; }
    .mp-undo-dialog-actions { flex-direction: column-reverse; }
    .mp-undo-dialog-actions .mp-btn { width: 100%; text-align: center; }
    .mp-undo-drawer { width: 100%; max-width: 100%; }
    .mp-undo-drawer-row { grid-template-columns: 1.4rem 1fr; }
    .mp-undo-drawer-status { grid-column: 1 / -1; text-align: left; margin-top: 0.2rem; }
    .mp-undo-banner { flex-direction: column; align-items: stretch; }
    .mp-undo-banner .mp-btn { width: 100%; text-align: center; }
}

/* ==== Self-service account capabilities (WP2, docs/specs/account-capabilities/{WP0-architecture-and-parity.md,
   account-capabilities-ui-mockup.html}) ====
   ADDITIVE ONLY — nothing above this comment is touched. AccountCapabilitiesCard.razor renders under
   .mp-profile-scope (a sibling of the main profile EditForm), so it inherits that scope's dark .form-control/
   .mp-card/.mp-profile-card-head/.mp-profile-card-body treatment already defined above and only needs its own
   grid/tile/status-pill/dialog/boundary chrome here. Only --mp-* tokens are used, same rule as every other section
   in this file (WP0 §2 rule 5). Active state is conveyed by TEXT ("Active"/"Not enabled"), never colour alone —
   the green tint on .active is a reinforcing cue only. */

.mp-capability-card-head { align-items: flex-start; }
.mp-capability-private-pill {
    border-radius: 999px; border: 1px solid var(--mp-border); color: var(--mp-muted);
    padding: 0.3rem 0.6rem; font-size: 0.72rem; white-space: nowrap; flex: 0 0 auto;
}
.mp-capability-intro { margin: 0 0 1.1rem; color: var(--mp-muted); max-width: 66ch; }

/* ---- Two-up capability grid (mock ".capability-grid") — minmax(0,1fr) is load-bearing: without it a long
   organisation name or email can force the grid track wider than the viewport (WP2 overflow requirement at
   320/390px). ---- */
.mp-capability-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0.9rem; }
.mp-capability-tile {
    display: flex; flex-direction: column; min-width: 0; min-height: 15rem;
    padding: 1.1rem; border-radius: 12px; border: 1px solid var(--mp-border); background: var(--mp-surface-2);
    transition: border-color .18s ease, background-color .18s ease;
}
.mp-capability-tile.active {
    border-color: color-mix(in srgb, var(--mp-good) 55%, var(--mp-border));
    background: color-mix(in srgb, var(--mp-good) 9%, var(--mp-surface-2));
}
.mp-capability-top { display: flex; justify-content: space-between; align-items: flex-start; gap: 0.75rem; }
.mp-capability-symbol {
    width: 2.5rem; height: 2.5rem; flex: 0 0 auto; display: grid; place-items: center;
    border: 1px solid var(--mp-border); border-radius: 10px; background: var(--mp-surface); color: var(--mp-accent);
    font-size: 1.1rem;
}
/* ---- Status pill: text-first, never colour alone. A leading dot is a supplementary visual cue only. ---- */
.mp-capability-status {
    display: inline-flex; align-items: center; gap: 0.4rem; width: max-content;
    border: 1px solid var(--mp-border); border-radius: 999px; padding: 0.25rem 0.55rem;
    color: var(--mp-muted); font-size: 0.7rem; font-weight: 800;
}
.mp-capability-status::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: var(--mp-muted); flex: 0 0 auto; }
.mp-capability-tile.active .mp-capability-status {
    color: var(--mp-good); border-color: var(--mp-good);
    background: color-mix(in srgb, var(--mp-good) 14%, transparent);
}
.mp-capability-tile.active .mp-capability-status::before { background: var(--mp-good); }
.mp-capability-tile h3 { margin: 1rem 0 0.3rem; font-size: 1.05rem; letter-spacing: -0.01em; }
.mp-capability-tile > p { margin: 0; color: var(--mp-muted); font-size: 0.82rem; }
.mp-capability-detail { margin-top: 0.65rem !important; color: #d7dde6 !important; font-size: 0.78rem !important; overflow-wrap: anywhere; }
.mp-capability-action { margin-top: auto; padding-top: 1rem; display: flex; flex-direction: column; gap: 0.5rem; }
.mp-capability-action form { margin: 0; }
.mp-capability-action .mp-btn { width: 100%; text-align: center; min-height: 2.6rem; }

/* Disabled "Enabled" button: legible green-tinted state, deliberately NOT the browser-default greyed-out
   .mp-btn:disabled (opacity:0.45) — an active capability is a confirmation, not an error/unavailable state. */
.mp-capability-btn-enabled:disabled {
    opacity: 1; cursor: default; background: color-mix(in srgb, var(--mp-good) 22%, var(--mp-surface));
    color: #baf0d2; border: 1px solid color-mix(in srgb, var(--mp-good) 55%, var(--mp-border));
}
.mp-capability-cta {
    display: inline-flex; align-items: center; justify-content: center; width: 100%; min-height: 2.6rem;
    border-radius: 8px; border: 1px solid var(--mp-border); background: var(--mp-surface); color: var(--mp-accent);
    font-weight: 700; text-decoration: none; text-align: center;
}
.mp-capability-cta:hover { border-color: var(--mp-accent); }

/* ---- Boundary note (mock ".boundary") — the "not staff permissions" disclosure. ---- */
.mp-capability-boundary {
    display: grid; grid-template-columns: auto 1fr; gap: 0.7rem; align-items: flex-start;
    margin-top: 1.1rem; padding: 0.85rem 0.95rem; border: 1px solid var(--mp-border); border-radius: 10px;
    background: var(--mp-bg, #0d1117); color: var(--mp-muted); font-size: 0.78rem;
}
.mp-capability-boundary strong { display: block; color: var(--mp-text); margin-bottom: 0.15rem; }

/* ---- Director setup dialog (mock "#director-dialog") — native <dialog>, JS-enhanced open/close in
   wwwroot/js/accountCapabilities.js. Rendered with the plain `open` attribute on a server-side validation
   failure (no-JS fallback), so its layout must also look correct un-modal-ised, not just via ::backdrop. ---- */
.mp-capability-dialog {
    width: min(32rem, calc(100% - 1.75rem)); padding: 0; margin: auto;
    border: 1px solid var(--mp-border); border-radius: 14px; background: var(--mp-surface); color: var(--mp-text);
    box-shadow: 0 20px 60px rgba(0, 0, 0, 0.45);
}
.mp-capability-dialog::backdrop { background: rgba(3, 5, 8, 0.78); }
.mp-capability-dialog-head {
    display: flex; justify-content: space-between; gap: 1rem;
    padding: 1.2rem 1.25rem 0.9rem; border-bottom: 1px solid var(--mp-border);
}
.mp-capability-dialog-head h2 { margin: 0; font-size: 1.2rem; }
.mp-capability-dialog-head p { margin: 0.3rem 0 0; color: var(--mp-muted); font-size: 0.8rem; }
.mp-capability-dialog-close {
    width: 2.1rem; height: 2.1rem; flex: 0 0 auto; border-radius: 8px; border: 1px solid var(--mp-border);
    background: var(--mp-surface-2); color: var(--mp-text); cursor: pointer; font-size: 1.1rem; line-height: 1;
}
.mp-capability-dialog-body { padding: 1.15rem 1.25rem; }
.mp-capability-dialog-body label { display: block; font-size: 0.78rem; font-weight: 800; margin-bottom: 0.4rem; color: var(--mp-muted); }
.mp-capability-help { margin: 0.45rem 0 0; color: var(--mp-muted); font-size: 0.75rem; }
.mp-capability-field-error { min-height: 1.1rem; color: var(--mp-nolift); font-size: 0.75rem; margin: 0.3rem 0 0; }
.mp-capability-dialog-summary {
    display: grid; gap: 0.5rem; margin-top: 1rem; padding: 0.8rem;
    border: 1px solid var(--mp-border); border-radius: 10px; background: var(--mp-bg, #0d1117);
    color: var(--mp-muted); font-size: 0.75rem;
}
.mp-capability-dialog-summary span::before { content: "\2713"; color: var(--mp-good); font-weight: 900; margin-right: 0.5rem; }
.mp-capability-dialog-actions { display: flex; gap: 0.6rem; justify-content: flex-end; padding: 0 1.25rem 1.25rem; }
.mp-capability-dialog-actions .mp-btn { min-width: 8rem; }

/* ---- Responsive: 2-up from ~700px, stacked below (mock's 900px breakpoint kept, tightened to this card's own
   grid rather than the mockup's full 2-col page layout, which this app's /profile doesn't use). ---- */
@media (max-width: 700px) {
    .mp-capability-grid { grid-template-columns: minmax(0, 1fr); }
    .mp-capability-tile { min-height: 0; }
}
@media (max-width: 560px) {
    .mp-capability-dialog-actions { flex-direction: column-reverse; }
    .mp-capability-dialog-actions .mp-btn { width: 100%; }
    .mp-capability-private-pill { display: none; }
}

/* ---- Handler-delegation WP5: multi-handler workspace additions (appended; the .mp-handlers-scope base block
   further up is unchanged). Stats strip, per-lifter groups and the filter row all collapse to one column on
   small screens; touch targets inherit the existing 44px rule from the shared scope. ---- */
.mp-handlers-stats { display: grid; grid-template-columns: repeat(3, 1fr); gap: 0.6rem; margin: 0 0 0.8rem; }
.mp-handlers-stat { border: 1px solid var(--mp-border); border-radius: 10px; padding: 0.6rem 0.8rem; background: var(--mp-surface); display: flex; flex-direction: column; gap: 0.15rem; }
.mp-handlers-stat b { font-size: 1.3rem; letter-spacing: -0.02em; }
.mp-handlers-filterform { margin: 0 0 0.8rem; }
.mp-handlers-filter-grid { display: grid; grid-template-columns: 1fr 1fr 2fr auto; gap: 0.6rem; align-items: end; }
.mp-handlers-group { border: 1px solid var(--mp-border); border-radius: 12px; margin: 0 0 0.8rem; overflow: hidden; }
.mp-handlers-group-head { display: flex; justify-content: space-between; align-items: center; gap: 0.6rem; padding: 0.6rem 0.8rem; background: color-mix(in srgb, var(--mp-surface) 88%, var(--mp-text) 4%); }
.mp-handlers-group .mp-handlers-row { border: 0; border-top: 1px solid var(--mp-border); border-radius: 0; margin: 0; }
@media (max-width: 640px) {
    .mp-handlers-stats { grid-template-columns: 1fr; }
    .mp-handlers-filter-grid { grid-template-columns: 1fr; }
    .mp-handlers-group-head { flex-wrap: wrap; }
}

/* ==== meet-lifecycle-reliability WP0 §7: referee test-mode toolbar/dialog/banner/monitor (RunMeet.razor +
   run-board-referee-mode.js) ====
   ADDITIVE ONLY — nothing above this comment is touched. Reuses the existing --mp-* tokens, .mp-btn/.mp-badge/
   .mp-light system (same dots as the undo dialog's mp-light, §"Lift-result-rollback" block above) and the native
   <dialog> chrome shape already established by .mp-undo-dialog/.mp-capability-dialog. Pointer targets stay >=40px
   desktop / >=44px mobile (WP0 §7 / spec accessibility rule) via the shared .mp-btn min-height plus the explicit
   mobile bump below. */

.mp-refmode-btn { display: inline-flex; align-items: center; gap: 0.5rem; }
.mp-refmode-dot {
    width: 9px; height: 9px; border-radius: 50%; flex: 0 0 auto;
    background: var(--mp-good); box-shadow: 0 0 0 3px color-mix(in srgb, var(--mp-good) 22%, transparent);
}
.mp-refmode-btn.test .mp-refmode-dot {
    background: var(--mp-accent); box-shadow: 0 0 0 3px color-mix(in srgb, var(--mp-accent) 28%, transparent);
}
.mp-refmode-btn.test { border-color: var(--mp-accent); color: #ffd978; background: color-mix(in srgb, var(--mp-accent) 16%, var(--mp-surface-2)); }

/* ---- Confirmation dialog: same native-<dialog> shape as .mp-undo-dialog/.mp-capability-dialog (WP0 §2 rule 6 —
   no new dialog chrome framework). ---- */
.mp-refmode-dialog {
    background: var(--mp-surface); color: var(--mp-text); border: 1px solid var(--mp-border);
    border-radius: 16px; padding: 1.25rem 1.4rem;
    width: min(34rem, calc(100vw - 2rem)); max-width: 34rem; max-height: calc(100vh - 4rem); overflow-y: auto;
}
.mp-refmode-dialog::backdrop { background: rgba(0, 0, 0, 0.72); }
.mp-refmode-dialog-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 0.85rem; margin-bottom: 0.85rem; }
.mp-refmode-dialog-head h3 { margin: 0.15rem 0 0; }
.mp-refmode-eyebrow { color: var(--mp-accent); font-size: 0.7rem; font-weight: 800; letter-spacing: 0.09em; text-transform: uppercase; }
/* Nit 8(a): was ~22x30px (glyph size + padding only) — under the >=40px pointer-target rule this file's own
   comment above states. min-width/min-height + centering keep the glyph visually unchanged. */
.mp-refmode-dialog-close {
    display: inline-flex; align-items: center; justify-content: center;
    min-width: 40px; min-height: 40px; border: 0; background: transparent; color: var(--mp-muted);
    font-size: 1.4rem; line-height: 1; cursor: pointer; padding: 0;
}
.mp-refmode-dialog-close:hover { color: var(--mp-text); }
.mp-refmode-notice {
    border: 1px solid var(--mp-border); border-radius: 10px; padding: 0.75rem 0.9rem; margin-bottom: 0.75rem;
    background: var(--mp-surface-2); font-size: 0.88rem;
}
.mp-refmode-notice ul { margin: 0.5rem 0 0; padding-left: 1.2rem; }
.mp-refmode-notice li { margin-bottom: 0.2rem; }
.mp-refmode-dialog-error {
    display: flex; align-items: center; gap: 0.6rem; flex-wrap: wrap;
    color: var(--mp-nolift); font-weight: 700; margin-top: 0.7rem; font-size: 0.85rem;
}
.mp-refmode-dialog-actions { display: flex; justify-content: flex-end; gap: 0.5rem; margin-top: 1.1rem; }

/* ---- Sticky test banner: directly under the board header, full width, amber. Stays in the DOM once eligible
   (hidden toggled) so run-board-referee-mode.js can hide it in place on a poll-detected natural expiry. ---- */
.mp-refmode-banner {
    display: flex; align-items: center; gap: 0.9rem; flex-wrap: wrap;
    margin: 0 0 0.85rem; padding: 0.75rem 0.95rem;
    border: 1px solid var(--mp-accent); border-radius: 12px;
    background: color-mix(in srgb, var(--mp-accent) 16%, var(--mp-surface));
    position: sticky; top: 0; z-index: 5;
}
.mp-refmode-banner[hidden] { display: none; }
.mp-refmode-banner-icon {
    display: grid; place-items: center; width: 2.2rem; height: 2.2rem; flex: 0 0 auto;
    border-radius: 8px; background: var(--mp-accent); color: #241a04; font-weight: 900; font-size: 1.05rem;
}
.mp-refmode-banner-text { display: flex; flex-direction: column; gap: 0.15rem; min-width: 0; flex: 1 1 auto; }
.mp-refmode-banner-text strong { color: #ffe3a3; }
.mp-refmode-banner-actions { display: flex; align-items: center; gap: 0.6rem; flex-wrap: wrap; flex: 0 0 auto; }
.mp-refmode-banner-error {
    display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap;
    color: #ffb3b6; font-weight: 700; font-size: 0.82rem;
}
.mp-refmode-banner-error[hidden] { display: none; }
/* Must-fix 1: while consecutive status-poll failures leave the displayed mode unconfirmed, run-board-referee-mode.js
   swaps the countdown's text for "unconfirmed" and adds this class — a visual flag alongside the banner error text,
   never colour alone. */
[data-mp-ref-countdown].mp-refmode-unconfirmed { font-style: italic; text-decoration: underline dotted; opacity: 0.85; }

/* ---- Diagnostics monitor: in the current-attempt card area (mp-run-leftcol), visible only while Test is
   active. Colour is never the only signal — every light dot has its enum name as text beside it. ---- */
.mp-refmode-monitor {
    border: 1px solid var(--mp-accent); border-radius: 11px; padding: 0.85rem 0.95rem;
    background: color-mix(in srgb, var(--mp-accent) 10%, var(--mp-surface));
}
.mp-refmode-monitor[hidden] { display: none; }
.mp-refmode-monitor-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 0.6rem; margin-bottom: 0.6rem; }
.mp-refmode-monitor-head h3 { margin: 0; font-size: 0.95rem; }
.mp-refmode-lights { display: flex; flex-wrap: wrap; gap: 0.75rem; margin-bottom: 0.6rem; }
.mp-refmode-light { display: flex; align-items: center; gap: 0.4rem; font-size: 0.85rem; }
.mp-refmode-light-label { color: var(--mp-muted); font-weight: 700; min-width: 2.6rem; }
.mp-refmode-light-dot { width: 20px; height: 20px; border-radius: 50%; flex: 0 0 auto; border: 2px solid #000; }
.mp-refmode-light-value { font-weight: 700; }
.mp-refmode-monitor-received, .mp-refmode-monitor-count { margin: 0.2rem 0 0; font-size: 0.82rem; }

/* ---- Responsive: pointer targets >=44px, banner actions stack, no document-level horizontal scroll at 390px
   (spec — verified by a companion Playwright viewport test, not just eyeballed CSS). ---- */
@media (max-width: 720px) {
    .mp-refmode-banner { flex-direction: column; align-items: stretch; position: static; }
    .mp-refmode-banner-actions { flex-direction: column; align-items: stretch; width: 100%; }
    .mp-refmode-banner-actions .mp-btn { width: 100%; min-height: 44px; }
    .mp-refmode-btn { min-height: 44px; }
    .mp-refmode-dialog { width: 100%; max-width: 100%; padding: 1rem; }
    .mp-refmode-dialog-actions { flex-direction: column-reverse; }
    .mp-refmode-dialog-actions .mp-btn { width: 100%; min-height: 44px; }
    .mp-refmode-lights { gap: 0.6rem 1rem; }

    /* Pre-existing gap this WP surfaced (not referee-mode-specific, but the banner/monitor live inside
       .mp-run-leftcol, so a document-level "no horizontal overflow at 390px" check catches it): .mp-run-leftcol
       was a fixed flex: 0 0 500px column with no mobile treatment anywhere in this file, which alone overflows a
       390px viewport regardless of anything referee-mode adds. Stack it to full width below the same 720px
       breakpoint every other section of this file already uses; the run-board table itself already scrolls
       internally (.mp-run-grid's own overflow:auto), so this is the only change needed. Default desktop test
       viewports (1280px+) are unaffected — RunBoardVisualUiTests never sets a narrow viewport. */
    .mp-run-body { flex-wrap: wrap; }
    .mp-run-leftcol { flex: 1 1 100%; max-width: 100%; }
}

/* ---- Registration grid stability (WP2) ---- */
/* The sort headings are real controls (role="button" + tabindex="0" in the markup, Enter/Space handled in
   registration-grid.js), so keyboard users must be able to SEE which one they are on. */
.mp-reg .mp-rsort-label:focus-visible {
    outline: 2px solid var(--mp-accent); outline-offset: 2px; border-radius: 3px;
}
/* Multi-sort priority is carried by the badge's TEXT ("1", "2", …), never by colour alone (WCAG 1.4.1). The
   pill styling only makes the number legible next to the arrow; :not(:empty) keeps inactive headers clean. */
.mp-reg .mp-rsort-ord:not(:empty) {
    display: inline-flex; align-items: center; justify-content: center;
    min-width: 0.95rem; height: 0.95rem; margin-left: 0.1rem; padding: 0 0.15rem;
    border-radius: 999px; background: var(--mp-accent); color: var(--mp-bg);
    font-size: 0.55rem; font-weight: 700; line-height: 1;
}
/* Scroll anchoring re-points the viewport at whatever the browser picked as "the" anchor when content around it
   resizes. The grid's height is re-pinned after every DOM patch, which made that anchoring silently move the
   window (and the grid) — a scroll nobody asked for. This page is not meant to scroll at the window level at all. */
body:has(.mp-reg-wrap) { overflow-anchor: none; }
.mp-reg-wrap, .mp-reg-wrap * { overflow-anchor: none; }

/* ---- WP1 rapid-add: Registration add-competitor success/error feedback (spec §7.1/§7.2) ----
   Status is never conveyed by colour alone: a ✓/⚠ glyph is baked into the message text itself (Registration.razor),
   so screen-reader users and colour-blind users both get the outcome from the text, not just the accent colour. */
.mp-add-hint { margin: 0 0 0.6rem; font-size: 0.8rem; }
.mp-add-status { margin: 0.6rem 0; min-height: 1.2rem; }
.mp-add-status-msg { display: inline-flex; align-items: center; gap: 0.35rem; font-size: 0.85rem; font-weight: 700; }
.mp-add-status-success { color: var(--mp-good); }
.mp-add-status-error { color: var(--mp-nolift); }

/* ==== referee-lights-device WP4 (spec §8): "Ref lights" device-connection panel (RunMeet.razor +
   run-board-device-keys.js) ====
   ADDITIVE ONLY — nothing above this comment is touched. The dialog itself reuses .mp-refmode-dialog/
   .mp-refmode-dialog-head/.mp-refmode-eyebrow/.mp-refmode-dialog-close/.mp-refmode-notice/.mp-refmode-dialog-error/
   .mp-refmode-dialog-actions wholesale (same native-<dialog> chrome as the referee test-mode and undo dialogs —
   WP0 §2 rule 6, no new dialog chrome framework); this block only adds the few rules those classes don't already
   cover: the status/reveal layout and the reveal rows' Copy-button grid (an .mp-board-row usually assumes the
   4-column board-launcher shape — .mp-devkey-reveal-row narrows it to input/textarea + button + status). */

.mp-devkey-current-row { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; }
.mp-devkey-current p, .mp-devkey-status p { margin: 0.2rem 0 0; font-size: 0.85rem; }
.mp-devkey-warning { color: #ffe3a3; font-weight: 600; }

.mp-devkey-reveal[hidden] { display: none; }
.mp-devkey-reveal-notice {
    border: 1px solid var(--mp-accent); border-radius: 10px; padding: 0.6rem 0.8rem; margin-bottom: 0.7rem;
    background: color-mix(in srgb, var(--mp-accent) 14%, var(--mp-surface-2)); font-size: 0.85rem; font-weight: 600;
}
.mp-devkey-reveal label { display: block; margin: 0.6rem 0 0.25rem; font-size: 0.78rem; }
/* Narrows the shared .mp-board-row (board-launcher's icon/label/copy/status 4-col grid) to this dialog's own
   input-or-textarea + Copy + status shape — same principle as .mp-comms-reveal-row's flex layout for the
   Communications webhook-secret reveal, just on the shared grid class per the brief's "replicate that structure"
   guidance so director-ui.js's existing announceCopied()/.mp-board-copy-status wiring works unmodified. */
.mp-devkey-reveal-row.mp-board-row {
    grid-template-columns: minmax(0, 1fr) auto auto; align-items: center; padding: 0; border-radius: 0;
}
.mp-devkey-reveal-row.mp-board-row:hover { background: none; }
.mp-devkey-reveal-row .form-control { font-family: monospace; font-size: 0.8rem; resize: none; }
.mp-devkey-reveal-row input[readonly], .mp-devkey-reveal-row textarea[readonly] {
    background: var(--mp-bg); color: var(--mp-text);
}

@media (max-width: 720px) {
    .mp-devkey-reveal-row.mp-board-row { grid-template-columns: 1fr; justify-items: stretch; }
    .mp-devkey-dialog-actions { flex-direction: column-reverse; }
    .mp-devkey-dialog-actions .mp-btn, .mp-devkey-actions-primary { width: 100%; }
    .mp-devkey-actions-primary { display: flex; flex-direction: column; gap: 0.5rem; }
}

/* ==== record-sets-opl-export WP2 (WP0 §5): "Federation record sets" setup panel (RecordBookPanel.razor +
   Components/Meets/RecordSets/RecordSetDetailPanel.razor) ====
   ADDITIVE ONLY — nothing above this comment is touched. Reuses the existing --mp-* tokens and the
   .mp-card/.mp-setup-sec/.mp-tool-disclosure/.mp-compact-row/.mp-badge/.mp-table/.mp-entry-warning/.mp-form-err/
   .mp-setup-addrow/.mp-setup-subhead/.form-control/.mp-btn/.mp-multiselect system throughout — no new CSS
   framework (WP0 §2 rule 6 house style). Layout: a set list that always stacks ABOVE its detail editor (the
   simplest correct reading of "mobile stacks list above editor" — this panel already lives in a single fairly
   narrow flex column inside .mp-setup-tools, so a two-column desktop rail was judged not worth the extra
   responsive-breakpoint surface for this WP; see WP2-handoff.md). */

.mp-recordsets-metrics {
    display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 0.6rem; margin: 0.6rem 0;
}
.mp-recordsets-metric {
    padding: 0.6rem 0.7rem; border: 1px solid var(--mp-border); border-radius: 10px; background: var(--mp-surface-2);
}
.mp-recordsets-metric span { display: block; font-size: 0.72rem; }
.mp-recordsets-metric strong { display: block; margin-top: 0.2rem; font-size: 1.25rem; letter-spacing: -0.02em; }

.mp-recordsets-formgrid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0.7rem; }

.mp-recordsets-add > summary { padding: 0.2rem 0; }

.mp-recordsets-list { display: grid; gap: 0.55rem; margin-top: 0.6rem; }
a.mp-recordsets-row {
    display: block; border: 1px solid var(--mp-border); border-radius: 11px; padding: 0.7rem 0.85rem;
    background: var(--mp-surface); color: inherit; text-decoration: none; transition: border-color 0.15s ease, background 0.15s ease;
}
a.mp-recordsets-row:hover { background: var(--mp-surface-2); }
a.mp-recordsets-row.active { border-color: var(--mp-accent); background: color-mix(in srgb, var(--mp-accent) 10%, var(--mp-surface)); }
.mp-recordsets-row-top { display: flex; align-items: flex-start; justify-content: space-between; gap: 0.6rem; flex-wrap: wrap; }
.mp-recordsets-row-title { display: flex; align-items: center; gap: 0.4rem; flex-wrap: wrap; }
.mp-recordsets-row-title strong { font-size: 0.95rem; }
.mp-recordsets-row-badges { display: flex; gap: 0.35rem; flex-wrap: wrap; }
.mp-recordsets-row-meta { margin-top: 0.3rem; font-size: 0.8rem; }
.mp-recordsets-row-elig { margin-top: 0.15rem; font-size: 0.78rem; }

.mp-recordsets-detail {
    margin-top: 0.9rem; padding-top: 0.9rem; border-top: 1px solid var(--mp-border);
}
.mp-recordsets-section + .mp-recordsets-section { margin-top: 1rem; }

.mp-recordsets-success { color: var(--mp-good); font-weight: 600; }

.mp-recordsets-eligibility-body.mp-recordsets-locked-fields {
    opacity: 0.55; pointer-events: none;
}

.mp-recordsets-actions { display: flex; justify-content: flex-end; gap: 0.5rem; margin-top: 0.6rem; flex-wrap: wrap; }

.mp-recordsets-version-strip { display: grid; grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr)); gap: 0.5rem; }
a.mp-recordsets-version {
    display: block; border: 1px solid var(--mp-border); border-radius: 9px; padding: 0.55rem 0.6rem;
    background: var(--mp-surface-2); color: inherit; text-decoration: none; font-size: 0.78rem;
}
a.mp-recordsets-version.active { border-color: var(--mp-good); background: color-mix(in srgb, var(--mp-good) 14%, var(--mp-surface-2)); }
a.mp-recordsets-version strong { display: block; font-size: 0.8rem; }
a.mp-recordsets-version span { display: block; margin-top: 0.15rem; color: var(--mp-muted); }

.mp-recordsets-dropzone {
    border: 1px dashed var(--mp-border); border-radius: 11px; padding: 0.75rem 0.85rem;
    display: flex; justify-content: space-between; align-items: center; gap: 0.75rem; flex-wrap: wrap;
    background: var(--mp-surface-2);
}
.mp-recordsets-dropzone strong { display: block; font-size: 0.85rem; }
.mp-recordsets-dropzone span { display: block; margin-top: 0.15rem; font-size: 0.75rem; }

/* Overlap warning region — deliberately its own visual language (amber, not red) and no role="alert"/"status"
   (WP0 §6.3): an overlap is expected/allowed, so it must read as a heads-up, not an error or a live status update. */
.mp-recordsets-warning {
    margin-top: 0.6rem; padding: 0.7rem 0.85rem; border-radius: 11px;
    border: 1px solid #61431d; background: color-mix(in srgb, var(--mp-accent) 14%, var(--mp-surface));
}
.mp-recordsets-warning strong { display: block; margin-bottom: 0.3rem; font-size: 0.85rem; }
.mp-recordsets-warning ul { margin: 0; padding-left: 1.1rem; font-size: 0.8rem; }
.mp-recordsets-warning li { margin-bottom: 0.2rem; }

.mp-recordsets-tablewrap { overflow-x: auto; max-width: 100%; }

@media (max-width: 720px) {
    .mp-recordsets-metrics { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .mp-recordsets-formgrid { grid-template-columns: minmax(0, 1fr); }
    .mp-recordsets-actions {
        position: sticky; bottom: 0; z-index: 4; margin: 0.6rem -1.1rem -1.1rem; padding: 0.7rem 1.1rem;
        background: color-mix(in srgb, var(--mp-surface) 96%, transparent); border-top: 1px solid var(--mp-border);
        justify-content: stretch;
    }
    .mp-recordsets-actions .mp-btn { flex: 1 1 auto; }
    .mp-recordsets-dropzone { flex-direction: column; align-items: stretch; }
}
/* ^ this close brace was MISSING: the 720px record-sets media block silently swallowed every rule below it
   (the whole .mp-oplx-* card and .mp-oplxe-* editor blocks were CSS-nested inside it and applied only at
   <= 720px). Balance is now policed by StylesheetBraceBalanceTests alongside the comment guard. */
/* opl exports */
/* ==== OpenPowerlifting submissions card (record-sets/OPL-export WP4, docs/specs/record-sets-opl-export/{WP0-
   architecture-and-contracts.md,ui-mockup.html}) ====
   ADDITIVE ONLY — nothing above this comment is touched. OpenPowerliftingExportsCard.razor renders as a sibling of
   ResultsWorkspace's own markup, INSIDE ResultsWorkspace.razor.css's `.mp-rw-scope` element, but Blazor CSS
   isolation only reaches markup a component's own stylesheet targets with `::deep`, and ResultsWorkspace.razor.css
   has no such rule for this card's classes — so this card owns its full dark control/card/dialog treatment here,
   the same way `.mp-setup-scope`/`.mp-comms-scope` each own theirs, rather than silently inheriting unstyled
   `.form-control`s. Only --mp-* tokens are used (WP0 §2 rule 5) and every table/badge/button reuses the shared
   .mp-table/.mp-badge/.mp-btn/.mp-muted/.mp-eyebrow system — no second styling framework. */

.mp-oplx-scope { display: flex; flex-direction: column; gap: 1rem; }
.mp-oplx-header { display: flex; justify-content: space-between; align-items: flex-start; gap: 1rem; flex-wrap: wrap; }
.mp-oplx-header h2 { margin: 0 0 0.3rem; }
.mp-oplx-header-actions { display: flex; gap: 0.5rem; flex-wrap: wrap; align-items: center; }
.mp-oplx-header-actions form { margin: 0; }

.mp-oplx-status { border-radius: 10px; padding: 0.65rem 0.85rem; font-weight: 700; }
.mp-oplx-status.success {
    border: 1px solid var(--mp-good); color: var(--mp-good);
    background: color-mix(in srgb, var(--mp-good) 12%, var(--mp-surface));
}
.mp-oplx-status.error {
    border: 1px solid var(--mp-nolift); color: var(--mp-nolift);
    background: color-mix(in srgb, var(--mp-nolift) 12%, var(--mp-surface));
}

/* ---- Rail + detail workspace (mirrors the mockup's two-column "Export profiles" layout) ---- */
/* results-scoreboard-workspace ADR-1 §4: "compact horizontal profile bar" replacing the old tall sidebar-rail /
   detail-panel grid — the grid-first workspace (ResultsExportEditor.razor) needs the full content width, not a
   permanent 240-300px sidebar. Deliberately CSS-only: the DOM shape (.mp-oplx-rail, [data-export-profile],
   .mp-oplx-rail-sub) is unchanged — ResultsExportProfileUiTests/ResultsExportResponsiveUiTests' selectors keep
   working, and the mobile "rail stacks above detail" assertion holds at every width now, not just <=640px. */
.mp-oplx-workspace { display: flex; flex-direction: column; gap: 0.7rem; min-width: 0; }
.mp-oplx-rail { padding: 0; overflow: hidden; }
.mp-oplx-rail-head { display: flex; justify-content: space-between; align-items: center; gap: 0.6rem; padding: 0.6rem 0.75rem; border-bottom: 1px solid var(--mp-border); }
.mp-oplx-rail-head h3 { margin: 0; font-size: 0.95rem; }
/* Horizontal tab row — overflow-x:auto is the "responsive overflow/profile picker for narrow screens" affordance
   (spec §4.1): once tabs no longer fit, the row scrolls sideways inside ITS OWN wrapper rather than the document
   (same discipline as .mp-oplxe-scroller). */
.mp-oplx-rail-list { display: flex; flex-direction: row; gap: 0.4rem; padding: 0.5rem; max-height: none; overflow-x: auto; overflow-y: hidden; }
.mp-oplx-rail-item {
    flex: 0 0 auto; min-width: 12rem; max-width: 18rem;
    display: block; text-decoration: none; color: inherit; border: 1px solid transparent; border-radius: 10px;
    padding: 0.7rem 0.75rem; background: transparent; transition: background-color .14s ease, border-color .14s ease;
}
.mp-oplx-rail-item:hover { background: var(--mp-surface-2); }
.mp-oplx-rail-item.active { background: var(--mp-surface-2); border-color: var(--mp-control-border-focus); box-shadow: inset 3px 0 var(--mp-accent); }
.mp-oplx-rail-top { display: flex; justify-content: space-between; align-items: flex-start; gap: 0.6rem; }
.mp-oplx-rail-title { font-weight: 750; font-size: 0.88rem; }
.mp-oplx-rail-sub { margin-top: 0.35rem; font-size: 0.74rem; line-height: 1.45; }

.mp-oplx-detail { padding: 1rem 1.1rem 1.1rem; display: flex; flex-direction: column; gap: 0.9rem; min-width: 0; }
.mp-oplx-detail-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 1rem; flex-wrap: wrap; }
.mp-oplx-detail-head h2 { margin: 0.2rem 0 0.3rem; font-size: 1.25rem; }

/* ---- Sections (mirrors the mockup's ".section") ---- */
.mp-oplx-section { border: 1px solid var(--mp-border); border-radius: 12px; padding: 0.9rem 1rem; background: var(--mp-surface-2); }
.mp-oplx-section h4 { margin: 0 0 0.3rem; font-size: 0.92rem; }
.mp-oplx-section-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 0.9rem; margin-bottom: 0.5rem; flex-wrap: wrap; }
.mp-oplx-section-head h3, .mp-oplx-section-head h4 { margin: 0 0 0.2rem; }

.mp-oplx-disclosure { border: 1px solid var(--mp-border); border-radius: 12px; background: var(--mp-surface-2); overflow: visible; }
.mp-oplx-disclosure > summary { list-style: none; cursor: pointer; padding: 0.8rem 1rem; display: flex; justify-content: space-between; align-items: center; gap: 0.8rem; }
.mp-oplx-disclosure > summary::-webkit-details-marker { display: none; }
.mp-oplx-disclosure[open] > summary { border-bottom: 1px solid var(--mp-border); }
.mp-oplx-summary-title { font-weight: 750; font-size: 0.9rem; }
.mp-oplx-disclosure-body { padding: 0.9rem 1rem 1rem; }

.mp-oplx-form-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0.7rem; }
.mp-oplx-form-grid.three { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.mp-field label { display: block; color: var(--mp-muted); font-size: 0.76rem; font-weight: 700; margin-bottom: 0.3rem; }
.mp-help { color: var(--mp-muted); margin-top: 0.3rem; font-size: 0.72rem; line-height: 1.4; }

.mp-oplx-toggle { display: flex; align-items: center; gap: 0.5rem; margin-top: 0.7rem; font-size: 0.85rem; }
.mp-oplx-toggle input[type="checkbox"] { width: 1.05rem; height: 1.05rem; }

/* ---- Dark control theme, scoped to this card (same shape as .mp-setup-scope/.mp-comms-scope) ---- */
.mp-oplx-scope .form-control,
.mp-oplx-scope .mp-multiselect > summary.msd-control {
    display: block; width: 100%; min-height: 2.35rem; padding: 0 0.65rem; color: var(--mp-text);
    background: var(--mp-control-bg); border: 1px solid var(--mp-control-border); border-radius: 7px;
    box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.2); outline: none;
    transition: border-color .14s ease, background-color .14s ease, box-shadow .14s ease;
}
.mp-oplx-scope .form-control::placeholder { color: var(--mp-control-placeholder); opacity: 1; }
.mp-oplx-scope .form-control:hover:not(:disabled):not([readonly]),
.mp-oplx-scope .mp-multiselect > summary.msd-control:hover { background: var(--mp-control-bg-hover); border-color: #435164; }
.mp-oplx-scope .form-control:focus-visible, .mp-oplx-scope .form-control:focus,
.mp-oplx-scope .mp-multiselect[open] > summary.msd-control {
    border-color: var(--mp-control-border-focus); background: #19212b;
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--mp-control-border-focus) 22%, transparent), inset 0 1px 1px rgba(0, 0, 0, 0.2);
}
.mp-oplx-scope select.form-control {
    appearance: none; -webkit-appearance: none;
    background-image: linear-gradient(45deg, transparent 50%, #7d8999 50%), linear-gradient(135deg, #7d8999 50%, transparent 50%);
    background-position: calc(100% - 15px) 52%, calc(100% - 10px) 52%; background-size: 4px 4px, 4px 4px; background-repeat: no-repeat;
    padding-right: 2rem;
}
.mp-oplx-scope input[type="date"].form-control { color-scheme: dark; }

/* ---- Severity notices (blocking = role="alert"; warning = neither role="alert" NOR role="status" — a warning is
   not a live success announcement; success uses role="status" on .mp-oplx-status.success above, never here). ---- */
.mp-oplx-notice { border-radius: 10px; padding: 0.65rem 0.8rem; font-size: 0.82rem; margin: 0.6rem 0; }
.mp-oplx-notice ul { margin: 0.4rem 0 0; padding-left: 1.1rem; }
.mp-oplx-notice li { margin: 0.15rem 0; }
.mp-oplx-notice code { font-size: 0.78em; }
.mp-oplx-notice.bad { border: 1px solid var(--mp-nolift); color: var(--mp-nolift); background: color-mix(in srgb, var(--mp-nolift) 10%, var(--mp-surface)); }
.mp-oplx-notice.warn { border: 1px solid var(--mp-accent); color: var(--mp-accent); background: color-mix(in srgb, var(--mp-accent) 10%, var(--mp-surface)); }
.mp-oplx-notice.good { border: 1px solid var(--mp-good); color: var(--mp-good); background: color-mix(in srgb, var(--mp-good) 10%, var(--mp-surface)); }

/* ---- Preview panel (ResultsExportPreviewPanel.razor) ---- */
.mp-oplx-preview { padding: 0.95rem 1rem 1.1rem; }
.mp-oplx-ministats { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 0.6rem; margin: 0.5rem 0; }
.mp-oplx-stat { background: var(--mp-surface-2); border: 1px solid var(--mp-border); border-radius: 9px; padding: 0.6rem 0.7rem; text-align: center; }
.mp-oplx-stat strong { display: block; font-size: 1.15rem; }
.mp-oplx-stat span { color: var(--mp-muted); font-size: 0.68rem; text-transform: uppercase; letter-spacing: 0.03em; }
.mp-oplx-stat.warn strong { color: var(--mp-accent); }
.mp-oplx-stat.bad strong { color: var(--mp-nolift); }

.mp-oplx-map-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 0.6rem; margin: 0.6rem 0; }
.mp-oplx-map-item { border: 1px solid var(--mp-border); background: var(--mp-surface-2); border-radius: 9px; padding: 0.55rem 0.65rem; min-width: 0; }
.mp-oplx-map-item span { display: block; color: var(--mp-muted); font-size: 0.66rem; text-transform: uppercase; letter-spacing: 0.04em; }
.mp-oplx-map-item strong { display: block; margin-top: 0.25rem; font-size: 0.82rem; overflow-wrap: anywhere; }

.mp-oplx-coverage-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0.6rem; margin: 0.6rem 0; }
.mp-oplx-coverage-card { padding: 0.7rem 0.75rem; border-radius: 10px; background: var(--mp-surface-2); border: 1px solid var(--mp-border); }
.mp-oplx-coverage-card span:first-child { display: block; color: var(--mp-muted); font-size: 0.72rem; }
.mp-oplx-coverage-card strong { display: block; font-size: 1.35rem; margin: 0.25rem 0; }
.mp-oplx-coverage-card span.mp-muted { font-size: 0.7rem; }
.mp-oplx-coverage-card.good strong { color: var(--mp-good); }
.mp-oplx-coverage-card.warn strong { color: var(--mp-accent); }
.mp-oplx-coverage-card.bad strong { color: var(--mp-nolift); }

.mp-oplx-table-wrap { overflow-x: auto; border: 1px solid var(--mp-border); border-radius: 10px; }
.mp-oplx-table-wrap table.mp-table { min-width: 42rem; margin: 0; }
.mp-oplx-table-wrap table.mp-table th, .mp-oplx-table-wrap table.mp-table td { white-space: nowrap; }

.mp-oplx-refresh-row { display: flex; align-items: center; gap: 0.6rem; flex-wrap: wrap; }
.mp-oplx-refresh-row form { margin: 0; }
.mp-oplx-sticky-actions { display: flex; justify-content: flex-end; align-items: center; gap: 0.6rem; flex-wrap: wrap; }

/* ---- Native <dialog> chrome for "Add export profile" (same shape as ResultsWorkspace's own mp-rw-dialog, kept
   independent here since platform.css cannot reach a Blazor-CSS-isolated class from another component). ---- */
.mp-oplx-dialog {
    background: var(--mp-surface); color: var(--mp-text); border: 1px solid var(--mp-border);
    border-radius: 12px; padding: 1.25rem 1.4rem; width: min(28rem, calc(100vw - 2rem)); max-width: 28rem;
}
.mp-oplx-dialog::backdrop { background: rgba(0, 0, 0, 0.55); }
.mp-oplx-dialog-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 1rem; margin-bottom: 0.3rem; }
.mp-oplx-dialog-head h3 { margin: 0; }
.mp-oplx-dialog-actions { display: flex; justify-content: flex-end; gap: 0.5rem; margin-top: 1rem; }

/* ---- Responsive: the rail is now a horizontal bar at every width (see its own rules above), so it already
   stacks above .mp-oplx-detail without a breakpoint override; sticky action bars still pin full-width at the
   bottom of their section (spec §9 / mockup mobile behaviour), matching .mp-setup-sec's convention. ---- */
@media (max-width: 640px) {
    .mp-oplx-header { flex-direction: column; align-items: stretch; }
    .mp-oplx-form-grid, .mp-oplx-form-grid.three { grid-template-columns: 1fr; }
    .mp-oplx-ministats { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .mp-oplx-map-grid { grid-template-columns: 1fr 1fr; }
    .mp-oplx-coverage-grid { grid-template-columns: 1fr; }
    .mp-oplx-sticky-actions {
        position: sticky; bottom: 0; z-index: 4; margin: 0 -1rem -1rem; padding: 0.75rem 1rem;
        background: color-mix(in srgb, var(--mp-surface) 96%, transparent); border-top: 1px solid var(--mp-border);
    }
    .mp-oplx-sticky-actions .mp-btn { flex: 1 1 auto; text-align: center; }
    .mp-oplx-dialog { padding: 1rem; }
}

/* =====================================================================================================
   OPL export editor (OPL export editor programme, PLAN §9). Own "mp-oplxe-" prefix — the "mp-oplx-" block
   above is owned by OpenPowerliftingExportsCard and pinned by ResultsExportProfileUiTests/
   ResultsExportResponsiveUiTests selectors; this block is additive only, appended at the end of the region.
   ===================================================================================================== */
.mp-oplxe-scope { display: flex; flex-direction: column; gap: 0.9rem; min-width: 0; max-width: 100%; }

.mp-oplxe-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 1rem; flex-wrap: wrap; }
.mp-oplxe-head h2 { margin: 0.2rem 0 0.3rem; font-size: 1.15rem; }
.mp-oplxe-state { text-align: right; display: flex; flex-direction: column; align-items: flex-end; gap: 0.35rem; }
.mp-oplxe-save-state { font-size: 0.78rem; font-weight: 700; color: var(--mp-muted); }
.mp-oplxe-save-state.good { color: var(--mp-good); }
.mp-oplxe-save-state.bad { color: var(--mp-nolift); }
.mp-oplxe-save-state.warn { color: var(--mp-accent); }

.mp-oplxe-health { display: grid; grid-template-columns: repeat(5, minmax(90px, 1fr)); gap: 0.55rem; }
.mp-oplxe-stat { border: 1px solid var(--mp-border); border-radius: 9px; padding: 0.55rem 0.65rem; background: var(--mp-surface-2); text-align: center; }
.mp-oplxe-stat strong { display: block; font-size: 1.1rem; }
.mp-oplxe-stat span { display: block; font-size: 0.66rem; color: var(--mp-muted); text-transform: uppercase; letter-spacing: 0.04em; }
.mp-oplxe-stat.warn strong { color: var(--mp-accent); }
.mp-oplxe-stat.bad strong { color: var(--mp-nolift); }

.mp-oplxe-conflict-actions { display: flex; gap: 0.5rem; margin-top: 0.5rem; flex-wrap: wrap; }

/* ---- Issues strip (severity styling mirrors .mp-oplx-notice — never role="status" for a warning). ---- */
.mp-oplxe-issues { display: flex; flex-direction: column; gap: 0.6rem; }
.mp-oplxe-issue-strip { display: flex; flex-direction: column; gap: 0.5rem; }
.mp-oplxe-issue-list { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0.5rem; }
.mp-oplxe-issue {
    border: 0; border-radius: 8px; padding: 0.55rem 0.65rem; text-align: left; cursor: pointer;
    background: var(--mp-surface); box-shadow: inset 3px 0 var(--mp-nolift); color: var(--mp-text);
}
.mp-oplxe-issue:hover { filter: brightness(1.04); }
.mp-oplxe-issue.mp-oplxe-issue-static { cursor: default; box-shadow: inset 3px 0 var(--mp-muted); }
.mp-oplxe-issue b { display: block; font-size: 0.8rem; margin-bottom: 0.15rem; }
.mp-oplxe-issue span { font-size: 0.7rem; color: var(--mp-muted); }

/* ---- Meta fields ---- */
.mp-oplxe-meta-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 0.6rem; }
.mp-oplxe-meta-input.changed { border-color: var(--mp-accent); background: color-mix(in srgb, var(--mp-accent) 10%, var(--mp-surface)); }
.mp-oplxe-meta-input.invalid { border-color: var(--mp-nolift); background: color-mix(in srgb, var(--mp-nolift) 10%, var(--mp-surface)); }
.mp-oplxe-changed-note { color: var(--mp-accent); font-size: 0.66rem; font-weight: 700; margin-left: 0.35rem; }
.mp-oplxe-cell-error { display: block; color: var(--mp-nolift); font-size: 0.68rem; margin-top: 0.2rem; }

/* ---- SHOULD-FIX 4: per-field "Use default" — the only UI path that sends Value=null (clear the override) for
   a meta field, as opposed to typing "" (a legitimate explicit blank override). ---- */
.mp-oplxe-meta-reset {
    margin-left: 0.4rem; border: 0; background: transparent; color: var(--mp-accent);
    font-size: 0.66rem; font-weight: 700; text-decoration: underline; padding: 0; cursor: pointer;
}
.mp-oplxe-meta-reset:disabled { cursor: not-allowed; opacity: 0.5; text-decoration: none; }

/* ---- Grid toolbar ---- */
.mp-oplxe-grid-section { display: flex; flex-direction: column; gap: 0.6rem; min-width: 0; }
.mp-oplxe-toolbar { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; }
.mp-oplxe-search input {
    height: 2.2rem; border: 1px solid var(--mp-control-border); border-radius: 7px; padding: 0 0.7rem;
    background: var(--mp-control-bg); color: var(--mp-text); width: 14rem; max-width: 100%;
}
.mp-oplxe-segmented { display: flex; border: 1px solid var(--mp-control-border); border-radius: 7px; overflow: hidden; }
.mp-oplxe-segmented button { border: 0; border-right: 1px solid var(--mp-control-border); background: var(--mp-surface); color: var(--mp-text); padding: 0.4rem 0.6rem; font-size: 0.78rem; }
.mp-oplxe-segmented button:last-child { border-right: 0; }
.mp-oplxe-segmented button.active { background: var(--mp-accent); color: #1b1b16; font-weight: 700; }
.mp-oplxe-toolbar-spacer { flex: 1 1 auto; }
.mp-oplxe-dirty-count { color: var(--mp-accent); font-size: 0.76rem; font-weight: 700; }
.mp-oplxe-note { font-size: 0.72rem; }

/* ---- Grid scroller: the scroller — not the document — owns horizontal overflow (PLAN §7 responsive rule). ---- */
.mp-oplxe-scroller { overflow-x: auto; overflow-y: auto; max-width: 100%; min-width: 0; max-height: 32rem; border: 1px solid var(--mp-border); border-radius: 10px; }
.mp-oplxe-grid { border-collapse: separate; border-spacing: 0; width: max-content; min-width: 100%; font-size: 0.78rem; }
.mp-oplxe-grid th {
    position: sticky; top: 0; z-index: 5; background: var(--mp-surface-2); color: var(--mp-muted);
    font-size: 0.66rem; text-transform: uppercase; letter-spacing: 0.03em; text-align: left;
    padding: 0.4rem 0.45rem; border-right: 1px solid var(--mp-border); border-bottom: 1px solid var(--mp-border);
    white-space: nowrap;
}
.mp-oplxe-grid thead tr:first-child th { top: 0; }
.mp-oplxe-grid thead tr:last-child th:not([rowspan]) { top: 1.9rem; }
.mp-oplxe-group { background: var(--mp-surface); text-align: center; color: var(--mp-text); }
.mp-oplxe-grid td { padding: 0.2rem 0.3rem; border-right: 1px solid var(--mp-border); border-bottom: 1px solid var(--mp-border); background: var(--mp-surface); vertical-align: middle; height: 2.4rem; }
.mp-oplxe-row.excluded td { background: var(--mp-surface-2); color: var(--mp-muted); }
.mp-oplxe-row.excluded .mp-oplxe-cell { text-decoration: line-through; }
.mp-oplxe-row.has-error td { background: color-mix(in srgb, var(--mp-nolift) 4%, var(--mp-surface)); }
.mp-oplxe-row.dirty .mp-oplxe-col-lifter { box-shadow: inset 3px 0 var(--mp-accent), 3px 0 5px rgba(0, 0, 0, 0.06); }

.mp-oplxe-col-include { position: sticky; left: 0; z-index: 4; width: 4.6rem; min-width: 4.6rem; background: var(--mp-surface); }
.mp-oplxe-col-lifter { position: sticky; left: 4.6rem; z-index: 4; width: 11rem; min-width: 11rem; background: var(--mp-surface); box-shadow: 3px 0 5px rgba(0, 0, 0, 0.06); }
.mp-oplxe-grid th.mp-oplxe-col-include, .mp-oplxe-grid th.mp-oplxe-col-lifter { z-index: 8; background: var(--mp-surface-2); }
.mp-oplxe-lifter-name { font-weight: 700; }
.mp-oplxe-lifter-meta { font-size: 0.66rem; }
.mp-oplxe-include-toggle { display: flex; align-items: center; gap: 0.3rem; font-size: 0.7rem; font-weight: 700; margin-top: 0.15rem; }

.mp-oplxe-cell-wrap { position: relative; min-width: 4.4rem; }
.mp-oplxe-cell {
    width: 100%; min-width: 4.2rem; height: 1.9rem; border: 1px solid transparent; border-radius: 5px;
    background: transparent; color: var(--mp-text); padding: 0 0.35rem;
}
.mp-oplxe-cell:hover:not(:disabled) { border-color: var(--mp-control-border); background: var(--mp-control-bg); }
.mp-oplxe-cell:focus-visible { outline: 2px solid var(--mp-accent); outline-offset: 1px; }
.mp-oplxe-cell.changed { border-color: var(--mp-accent); background: color-mix(in srgb, var(--mp-accent) 12%, var(--mp-surface)); }
.mp-oplxe-cell.invalid { border-color: var(--mp-nolift); background: color-mix(in srgb, var(--mp-nolift) 12%, var(--mp-surface)); }

/* ---- adversarial-review finding 1: the explicit per-cell reset control that replaced the destructive
   double-click gesture. Absolutely positioned inside .mp-oplxe-cell-wrap (now position:relative above) so it
   costs no extra grid column, and only ever rendered by the markup when that cell is actually changed. ---- */
.mp-oplxe-cell-reset {
    position: absolute; top: 0.15rem; right: 0.15rem; z-index: 2;
    width: 1.05rem; height: 1.05rem; line-height: 1; padding: 0; font-size: 0.6rem;
    border: 1px solid var(--mp-control-border); border-radius: 50%; background: var(--mp-surface);
    color: var(--mp-muted); display: flex; align-items: center; justify-content: center; cursor: pointer;
}
.mp-oplxe-cell-reset:hover:not(:disabled) { background: var(--mp-nolift); color: #fff; border-color: var(--mp-nolift); }
.mp-oplxe-cell-reset:disabled { cursor: not-allowed; opacity: 0.5; }

.mp-oplxe-status-cell { min-width: 7.5rem; }
.mp-oplxe-row-state { font-size: 0.68rem; font-weight: 700; color: var(--mp-muted); }
.mp-oplxe-row-state.bad { color: var(--mp-nolift); }
.mp-oplxe-row-state.manual { color: var(--mp-accent); }
.mp-oplxe-icon-btn { border: 1px solid var(--mp-control-border); background: var(--mp-surface); border-radius: 5px; padding: 0.15rem 0.4rem; color: var(--mp-text); font-size: 0.68rem; margin-top: 0.2rem; }
.mp-oplxe-empty { text-align: center; padding: 1rem; }

/* ---- Finding -> cell focus flash (ResultsExportEditor.razor.js). Fixed row height/column widths above mean this
   never reflows the grid — only a transient outline. ---- */
.mp-oplxe-flash { animation: mp-oplxe-flash-kf 1.2s ease; }
@keyframes mp-oplxe-flash-kf {
    0%, 100% { box-shadow: none; }
    30% { box-shadow: 0 0 0 3px color-mix(in srgb, var(--mp-nolift) 45%, transparent); }
}

/* ---- Footer ---- */
.mp-oplxe-footer { display: flex; align-items: center; gap: 0.6rem; flex-wrap: wrap; padding-top: 0.4rem; border-top: 1px solid var(--mp-border); }
.mp-oplxe-footer-right { margin-left: auto; display: flex; align-items: center; gap: 0.55rem; flex-wrap: wrap; }
.mp-oplxe-generate-note { font-size: 0.72rem; color: var(--mp-nolift); font-weight: 700; }

@media (max-width: 900px) {
    .mp-oplxe-health { grid-template-columns: repeat(3, minmax(0, 1fr)); }
    .mp-oplxe-meta-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .mp-oplxe-issue-list { grid-template-columns: 1fr; }
}
@media (max-width: 640px) {
    .mp-oplxe-head { flex-direction: column; align-items: stretch; }
    .mp-oplxe-state { align-items: flex-start; text-align: left; }
    .mp-oplxe-health { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .mp-oplxe-meta-grid { grid-template-columns: 1fr; }
    .mp-oplxe-toolbar { flex-direction: column; align-items: stretch; }
    .mp-oplxe-toolbar-spacer { display: none; }
    /* Narrow-width overflow guard: the segmented filter's five no-wrap buttons have a min-content width
       (~305px) wider than the card's content box at 360px viewports. In a column flex container that widens
       the whole flex LINE, and align-items:stretch then drags every sibling out past the viewport edge
       (ResponsiveLayout offender: right=387 at vw=360). Letting the segments wrap and capping every toolbar
       child at the container's width keeps the page from scrolling sideways — the grid's own scroller stays
       the only horizontal-scroll surface. */
    .mp-oplxe-segmented { flex-wrap: wrap; }
    .mp-oplxe-segmented button { flex: 1 1 auto; }
    .mp-oplxe-toolbar > * { min-width: 0; max-width: 100%; }
    .mp-oplxe-search input { width: 100%; }
    .mp-oplxe-footer {
        position: sticky; bottom: 0; z-index: 4; margin: 0 -1rem -1rem; padding: 0.7rem 1rem;
        background: color-mix(in srgb, var(--mp-surface) 96%, transparent); border-top: 1px solid var(--mp-border);
    }
    .mp-oplxe-footer-right { width: 100%; justify-content: flex-end; }
}

/* ---- Results-source section (workspace-layout rework, mock-up "1. Choose lifters from this competition"). ---- */
.mp-oplxe-source-field { max-width: 26rem; }
.mp-oplxe-source-field select { margin-top: 0.2rem; }
.mp-oplxe-source-note { display: block; margin-top: 0.3rem; color: var(--mp-accent); font-size: 0.76rem; }

/* ---- Column-view select (mock-up "3. Edit upload data" toolbar). ---- */
.mp-oplxe-view-select { height: 2.1rem; }

/* ---- "Edit all" per-row affordance + drawer (mock-up "Edit all" side panel). A second VIEW over the SAME pending
   state the grid edits, not a parallel write path — see ResultsExportEditorDrawer's header comment. ---- */
.mp-oplxe-editall-btn { float: right; margin-left: 0.4rem; }
/* BLOCKER 2 (cross-review): both overlay drawers (this "Edit all" drawer AND the issues drawer, which shares
   this same .mp-oplxe-backdrop/.mp-oplxe-drawer pair) must render ABOVE .mp-board-fullscreen (z-index 1000,
   platform.css:426) — the OPL editor's own full-screen wrapper — or "Review issues"/"Edit all" open invisibly
   underneath it while full screen is active. This also puts them above .mp-sb-exit's 1100 — a DIFFERENT
   surface's (scoreboard) always-on-top control that never coexists on screen with the OPL editor, so that
   ordering is incidental, not a real stacking conflict. */
.mp-oplxe-backdrop { position: fixed; inset: 0; background: rgba(10, 11, 14, 0.45); z-index: 1200; }
.mp-oplxe-drawer {
    position: fixed; inset: 0 0 0 auto; width: min(34rem, 94vw); background: var(--mp-surface); z-index: 1210;
    box-shadow: -20px 0 45px rgba(10, 11, 14, 0.35); display: flex; flex-direction: column; border-left: 1px solid var(--mp-border);
}
.mp-oplxe-drawer-head { padding: 1rem 1.1rem; border-bottom: 1px solid var(--mp-border); display: flex; align-items: flex-start; gap: 0.7rem; }
.mp-oplxe-drawer-head h2 { margin: 0.15rem 0 0.2rem; font-size: 1.1rem; }
.mp-oplxe-drawer-reason { margin: 0.3rem 0 0; color: var(--mp-nolift); font-size: 0.78rem; font-weight: 700; }
.mp-oplxe-drawer-close { margin-left: auto; border: 1px solid var(--mp-border); background: var(--mp-surface); border-radius: 6px; width: 2.1rem; height: 2.1rem; color: var(--mp-text); }
.mp-oplxe-drawer-body { overflow-y: auto; padding: 0.9rem 1.1rem; flex: 1 1 auto; }
.mp-oplxe-drawer-group { margin-bottom: 1.1rem; }
.mp-oplxe-drawer-group h3 { font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.05em; color: var(--mp-muted); margin: 0 0 0.5rem; }
.mp-oplxe-drawer-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0.6rem; }
.mp-oplxe-drawer-actions { margin-top: auto; border-top: 1px solid var(--mp-border); padding: 0.8rem 1.1rem; display: flex; justify-content: flex-end; gap: 0.5rem; }

/* ---- Row status: distinct visual states beyond the base bad/manual palette (mock-up parity requirement E —
   automatic / manually included / manually removed / overridden / automatically-excluded-with-reason / warning). ---- */
.mp-oplxe-row-state.auto-excluded { color: var(--mp-muted); font-weight: 600; }
.mp-oplxe-row-state.warn { color: var(--mp-accent); }

/* ---- Raw file preview disclosure (rendered by the island from _state — replaces the always-open legacy panel). ---- */
.mp-oplxe-raw-preview .mp-oplx-table-wrap { max-height: 24rem; overflow-y: auto; }
.mp-oplxe-raw-table th, .mp-oplxe-raw-table td { white-space: nowrap; font-size: 0.76rem; }

/* =====================================================================================================
   Workspace rework (results-scoreboard-workspace ADR-1 §4) — health-bar action buttons, issue drawer,
   smart-filter builder, selection/bulk bar, full-screen head extras, download footer.
   ===================================================================================================== */

/* Blocking/warning health-bar stats are now real <button>s (open the issue drawer) — reset button chrome onto
   the existing .mp-oplxe-stat look, add a visible disabled state (nothing to open when the count is zero). */
.mp-oplxe-stat-btn { border: 1px solid var(--mp-border); cursor: pointer; font: inherit; }
.mp-oplxe-stat-btn:disabled { cursor: default; opacity: 0.55; }
.mp-oplxe-stat-btn:not(:disabled):hover { border-color: var(--mp-control-border-focus); }
.mp-oplxe-stat-save { display: flex; flex-direction: column; align-items: center; gap: 0.1rem; }
.mp-oplxe-stat-save .mp-oplxe-save-state { font-size: 0.66rem; margin-top: 0.1rem; }

/* ---- Issue drawer (ResultsExportIssuesPanel.razor) ---- */
.mp-oplxe-issues-drawer .mp-oplxe-drawer-body { display: flex; flex-direction: column; gap: 0.7rem; }
.mp-oplxe-issue-group { border: 1px solid var(--mp-border); border-radius: 10px; padding: 0.7rem 0.8rem; background: var(--mp-surface-2); }
.mp-oplxe-issue-group.bad { box-shadow: inset 3px 0 var(--mp-nolift); }
.mp-oplxe-issue-group.warn { box-shadow: inset 3px 0 var(--mp-accent); }
.mp-oplxe-issue-group-head { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; }
.mp-oplxe-issue-group-actions { display: flex; gap: 0.4rem; flex-wrap: wrap; margin-top: 0.55rem; }

/* ---- Smart filter builder (a compact popover disclosure in the toolbar) ---- */
.mp-oplxe-filters { position: relative; border-radius: 7px; background: var(--mp-surface); }
.mp-oplxe-filters > summary { padding: 0.4rem 0.65rem; font-size: 0.78rem; border-radius: 7px; }
.mp-oplxe-filters[open] > summary { border-bottom: 0; }
.mp-oplxe-filters .mp-oplx-disclosure-body {
    position: absolute; top: calc(100% + 4px); left: 0; z-index: 20; width: max(24rem, 100%);
    background: var(--mp-surface); border: 1px solid var(--mp-border); border-radius: 10px;
    box-shadow: 0 14px 38px rgba(0, 0, 0, 0.35); padding: 0.7rem;
}
.mp-oplxe-filter-rule { display: grid; grid-template-columns: 1fr 1fr 1fr auto; gap: 0.4rem; align-items: center; margin-bottom: 0.4rem; }
.mp-oplxe-filter-rule select, .mp-oplxe-filter-rule input { height: 2rem; font-size: 0.78rem; }
.mp-oplxe-filter-actions { display: flex; gap: 0.5rem; margin-top: 0.4rem; }

/* ---- Selection extras + bulk field-edit bar ---- */
.mp-oplxe-visible-count { font-size: 0.76rem; }
.mp-oplxe-bulk {
    display: flex; flex-wrap: wrap; align-items: end; gap: 0.6rem; padding: 0.6rem 0.7rem;
    border: 1px solid var(--mp-control-border-focus); border-radius: 10px;
    background: color-mix(in srgb, var(--mp-accent) 8%, var(--mp-surface-2));
}
.mp-oplxe-bulk-field { min-width: 10rem; }
.mp-oplxe-bulk label span { display: block; font-size: 0.68rem; color: var(--mp-muted); margin-bottom: 0.15rem; }
.mp-oplxe-bulk .form-control { height: 2.2rem; }
.mp-oplxe-toggle.small { font-size: 0.76rem; gap: 0.3rem; margin-top: 0; }
.mp-oplxe-toggle.small input[type="checkbox"] { width: 0.95rem; height: 0.95rem; }

/* ---- Full-screen head (data-grid-fs-head — shares Registration/Weigh-ins' .mp-grid-fs-head base rules; these
   extend it with the extra fields ADR-1 §4 asks for: save status + a Ready/blocking badge). ---- */
.mp-grid-fs-head .mp-oplxe-save-state { font-size: 0.7rem; font-weight: 700; color: color-mix(in srgb, #fff 80%, transparent); }
.mp-grid-fs-head .mp-badge { margin-left: 0.3rem; }

/* ---- Footer download button ---- */
.mp-oplxe-footer .mp-oplxe-generate-note { font-size: 0.72rem; color: var(--mp-nolift); font-weight: 700; }

/* ---- Division row selection (OpenPowerliftingExportsCard.razor profile settings — spec §6.4) ---- */
.mp-oplx-strategy-options { display: flex; flex-direction: column; gap: 0.6rem; margin: 0.6rem 0; }
.mp-oplx-strategy-option { display: flex; align-items: flex-start; gap: 0.6rem; padding: 0.6rem 0.7rem; border: 1px solid var(--mp-border); border-radius: 9px; cursor: pointer; }
.mp-oplx-strategy-option:has(input:checked) { border-color: var(--mp-control-border-focus); background: color-mix(in srgb, var(--mp-accent) 6%, var(--mp-surface)); }
.mp-oplx-strategy-option input[type="radio"] { margin-top: 0.2rem; width: 1.05rem; height: 1.05rem; flex: 0 0 auto; }
.mp-oplx-strategy-help { display: block; margin-top: 0.2rem; line-height: 1.4; }
.mp-oplx-division-priority { border: 1px solid var(--mp-border); border-radius: 10px; padding: 0.7rem 0.8rem; margin-top: 0.4rem; background: var(--mp-surface-2); }
.mp-oplx-division-priority-list { list-style: none; margin: 0.5rem 0; padding: 0; display: flex; flex-direction: column; gap: 0.35rem; }
.mp-oplx-division-priority-item {
    display: flex; align-items: center; gap: 0.5rem; padding: 0.4rem 0.55rem;
    border: 1px solid var(--mp-border); border-radius: 7px; background: var(--mp-surface);
}
.mp-oplx-division-priority-item.bad { border-color: var(--mp-nolift); background: color-mix(in srgb, var(--mp-nolift) 8%, var(--mp-surface)); }
.mp-oplx-priority-handle { cursor: grab; color: var(--mp-muted); }
.mp-oplx-priority-name { flex: 1 1 auto; font-weight: 650; font-size: 0.85rem; }
.mp-oplx-priority-actions { display: flex; gap: 0.3rem; }
.mp-oplx-priority-add-row { display: flex; gap: 0.5rem; }
.mp-oplx-priority-add-row select { flex: 1 1 auto; }

@media (max-width: 640px) {
    .mp-oplxe-drawer { width: 100vw; }
    .mp-oplxe-drawer-grid { grid-template-columns: 1fr; }
    .mp-oplxe-source-field { max-width: none; }
    .mp-oplxe-filter-rule { grid-template-columns: 1fr; }
    .mp-oplxe-filters .mp-oplx-disclosure-body { position: static; width: auto; box-shadow: none; }
    .mp-oplxe-bulk { flex-direction: column; align-items: stretch; }
}

/* ==== nzpu-competition-provisioning WP5a ====
   ADDITIVE ONLY — nothing above this comment is touched. Two small layout-only additions: the read-only NZPU
   source badge/notice on MeetAccessPanel's row (data-access-source, data-nzpu-access-notice) reuses the existing
   .mp-badge/.mp-card/.mp-fed-row-sub primitives verbatim and needs no new rule at all; the one new selector below
   is PaymentSetupPanel's NZPU readiness banner, which needs its badge and "Published from NZPU" link laid out on
   one row above the existing payment banner. */
.mp-nzpu-readiness { display: flex; align-items: center; gap: 0.6rem; flex-wrap: wrap; }
/* ==== end WP5a ==== */
