/* AI-Generated */
/*
 * MatchCaddy application styles.
 *
 * Loaded after Bootstrap. Two responsibilities:
 *   1. Re-point Bootstrap's own components at the token layer, so ~40 existing
 *      templates written in `.card` / `.btn` / `.badge` inherit the new design
 *      without being rewritten.
 *   2. Provide `.mc-*` components for patterns Bootstrap has no equivalent for
 *      (bottom nav, page header, empty state, entity card, stat).
 *
 * Requires tokens.css. Never hard-code a color, radius, or shadow here.
 */

/* ==========================================================================
   1. Base
   ========================================================================== */

*,
*::before,
*::after {
    box-sizing: border-box;
}

html {
    -webkit-text-size-adjust: 100%;
}

body {
    min-height: 100dvh;
    margin: 0;
    display: flex;
    flex-direction: column;
    background-color: var(--mc-canvas);
    color: var(--mc-text);
    font-family: var(--mc-font-sans);
    font-size: var(--mc-text-base);
    line-height: var(--mc-leading-normal);
    font-weight: var(--mc-weight-normal);
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    font-variant-numeric: tabular-nums;
}

h1, h2, h3, h4, h5, h6,
.h1, .h2, .h3, .h4, .h5, .h6 {
    margin-top: 0;
    color: var(--mc-text);
    font-weight: var(--mc-weight-semibold);
    line-height: var(--mc-leading-tight);
    letter-spacing: var(--mc-tracking-tight);
}

h1, .h1 { font-size: var(--mc-text-3xl); }
h2, .h2 { font-size: var(--mc-text-2xl); }
h3, .h3 { font-size: var(--mc-text-xl); }
h4, .h4 { font-size: var(--mc-text-lg); }
h5, .h5 { font-size: var(--mc-text-md); }
h6, .h6 { font-size: var(--mc-text-base); font-weight: var(--mc-weight-semibold); }

p { margin-top: 0; }

a {
    color: var(--mc-accent);
    text-decoration: none;
    transition: color var(--mc-duration-fast) var(--mc-ease-out);
}

a:hover {
    color: var(--mc-accent-hover);
    text-decoration: underline;
}

hr {
    border: 0;
    border-top: 1px solid var(--mc-border);
    opacity: 1;
    margin: var(--mc-space-6) 0;
}

small, .small { font-size: var(--mc-text-sm); }

/* Bootstrap's text utilities resolve to fixed grays that break in dark mode. */
.text-muted { color: var(--mc-text-muted) !important; }
.text-body { color: var(--mc-text) !important; }
.text-subtle { color: var(--mc-text-subtle) !important; }

/* A single visible focus treatment for every interactive element. Mouse users
   never see it (:focus-visible), keyboard users always do. */
:focus { outline: none; }

:focus-visible {
    outline: 2px solid var(--mc-accent);
    outline-offset: 2px;
    border-radius: var(--mc-radius-sm);
}

::selection {
    background-color: var(--mc-accent-soft);
    color: var(--mc-accent-soft-text);
}

/* ==========================================================================
   2. App shell
   ========================================================================== */

.mc-main {
    flex: 1 0 auto;
    width: 100%;
    max-width: var(--mc-container-max);
    margin-inline: auto;
    padding-inline: var(--mc-gutter);
    padding-block: var(--mc-section-gap) var(--mc-space-10);
}

/* Bottom nav is fixed on phones, so the shell reserves its height plus the iOS
   home-indicator inset. Without this the last card is unreachable. */
@media (max-width: 767.98px) {
    body.has-bottom-nav .mc-main {
        padding-bottom: calc(var(--mc-bottom-nav-height) + var(--mc-safe-bottom) + var(--mc-space-6));
    }
}

.mc-skip-link {
    position: absolute;
    left: var(--mc-space-3);
    top: var(--mc-space-3);
    z-index: var(--mc-z-toast);
    padding: var(--mc-space-2) var(--mc-space-4);
    border-radius: var(--mc-radius-md);
    background-color: var(--mc-surface);
    color: var(--mc-text);
    box-shadow: var(--mc-shadow-md);
    font-weight: var(--mc-weight-semibold);
    transform: translateY(-200%);
    transition: transform var(--mc-duration-base) var(--mc-ease-out);
}

.mc-skip-link:focus {
    transform: translateY(0);
}

/* ==========================================================================
   3. Top bar (desktop-primary, condensed on mobile)
   ========================================================================== */

.mc-topbar {
    position: sticky;
    top: 0;
    z-index: var(--mc-z-sticky);
    background-color: var(--mc-surface);
    border-bottom: 1px solid var(--mc-border);
}

.mc-topbar__inner {
    display: flex;
    align-items: center;
    gap: var(--mc-space-4);
    width: 100%;
    max-width: var(--mc-container-max);
    min-height: var(--mc-topbar-height);
    margin-inline: auto;
    padding-inline: var(--mc-gutter);
}

.mc-topbar__brand {
    display: inline-flex;
    align-items: center;
    flex-shrink: 0;
    text-decoration: none;
}

.mc-topbar__brand:hover { text-decoration: none; }

.mc-topbar__brand img {
    height: 32px;
    width: auto;
    display: block;
}

/*
 * The logo is a dark navy lockup, so on dark ground it is inverted to read.
 *
 * .mc-brand-lockup is the same wordmark used large on the landing page hero.
 * It was omitted here originally: the topbar mark inverted correctly while the
 * hero rendered navy-on-near-black at roughly 1.3:1, so in dark mode the first
 * thing a visitor saw was the product's own name, illegible. A text-contrast
 * sweep cannot catch this - the wordmark is pixels, not text.
 */
:root[data-theme="dark"] .mc-topbar__brand img,
:root[data-theme="dark"] .mc-brand-lockup { filter: brightness(0) invert(1); }

@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) .mc-topbar__brand img,
    :root:not([data-theme="light"]) .mc-brand-lockup {
        filter: brightness(0) invert(1);
    }
}

.mc-topbar__nav {
    display: none;
    align-items: center;
    gap: var(--mc-space-1);
    margin-right: auto;
}

@media (min-width: 768px) {
    .mc-topbar__nav { display: flex; }
}

.mc-topbar__link {
    display: inline-flex;
    align-items: center;
    gap: var(--mc-space-2);
    /* The token layer declares a 44px touch floor for every interactive
       element; these were set to 38px, contradicting it. */
    min-height: var(--mc-touch-min);
    padding-inline: var(--mc-space-3);
    border-radius: var(--mc-radius-md);
    color: var(--mc-text-muted);
    font-size: var(--mc-text-base);
    font-weight: var(--mc-weight-medium);
    white-space: nowrap;
    transition: background-color var(--mc-duration-fast) var(--mc-ease-out),
                color var(--mc-duration-fast) var(--mc-ease-out);
}

.mc-topbar__link:hover {
    background-color: var(--mc-surface-sunken);
    color: var(--mc-text);
    text-decoration: none;
}

.mc-topbar__link[aria-current="page"] {
    background-color: var(--mc-accent-soft);
    color: var(--mc-accent-soft-text);
}

.mc-topbar__link i { font-size: 0.9em; }

.mc-topbar__actions {
    display: flex;
    align-items: center;
    gap: var(--mc-space-2);
    margin-left: auto;
}

/*
 * Touch-floor repairs found by measuring rendered geometry rather than reading
 * CSS. Each of these declared a size that looked fine in source but rendered
 * under 44px in at least one viewport.
 */

/* Icon-only at narrow widths (the label is d-none below sm), so height alone
   was satisfied while width collapsed to 39px. */
.mc-topbar__actions .btn { min-width: var(--mc-touch-min); }

/* The logo is a link and therefore a tap target, not just an image. */
.mc-topbar__brand { min-height: var(--mc-touch-min); }

/*
 * A `btn-link p-0` around a 1.2rem glyph rendered 24x21 - the smallest
 * interactive element in the app, and it toggles a real preference.
 *
 * Qualified with .btn deliberately. `.btn-link` sets `min-height: auto` at the
 * same specificity as a bare `.toggle-favorite-btn`, and it is declared later
 * in this file, so the unqualified rule set a height that was immediately
 * thrown away - the button still measured 21px tall while the CSS read as
 * though it were fixed. Two classes (0,2,0) beat it regardless of order.
 */
.btn.toggle-favorite-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: var(--mc-touch-min);
    min-height: var(--mc-touch-min);
}

/* Visible only on focus, but a keyboard user still has to hit it. */
.mc-skip-link { min-height: var(--mc-touch-min); display: inline-flex; align-items: center; }

/* Icon-only control used for theme toggle and overflow menus. */
.mc-icon-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: var(--mc-touch-min);
    height: var(--mc-touch-min);
    padding: 0;
    border: 1px solid transparent;
    border-radius: var(--mc-radius-md);
    background-color: transparent;
    color: var(--mc-text-muted);
    font-size: var(--mc-text-md);
    cursor: pointer;
    transition: background-color var(--mc-duration-fast) var(--mc-ease-out),
                color var(--mc-duration-fast) var(--mc-ease-out);
}

.mc-icon-btn:hover {
    background-color: var(--mc-surface-sunken);
    color: var(--mc-text);
}

/* ==========================================================================
   4. Bottom navigation (mobile-primary)
   ========================================================================== */

.mc-bottom-nav {
    position: fixed;
    inset-inline: 0;
    bottom: 0;
    z-index: var(--mc-z-bottom-nav);
    display: flex;
    align-items: stretch;
    background-color: var(--mc-surface);
    box-shadow: var(--mc-shadow-nav);
    padding-bottom: var(--mc-safe-bottom);
    /* Frosted only where supported; the solid background above is the fallback. */
    backdrop-filter: saturate(180%) blur(12px);
}

@media (min-width: 768px) {
    .mc-bottom-nav { display: none; }
}

.mc-bottom-nav__item {
    flex: 1 1 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 3px;
    min-height: var(--mc-bottom-nav-height);
    padding: var(--mc-space-2) var(--mc-space-1);
    border: 0;
    background: none;
    color: var(--mc-text-subtle);
    font-size: var(--mc-text-2xs);
    font-weight: var(--mc-weight-medium);
    line-height: 1;
    text-decoration: none;
    transition: color var(--mc-duration-fast) var(--mc-ease-out);
    -webkit-tap-highlight-color: transparent;
}

.mc-bottom-nav__item:hover { text-decoration: none; }

.mc-bottom-nav__item i {
    font-size: 1.15rem;
    line-height: 1;
}

.mc-bottom-nav__item[aria-current="page"] {
    color: var(--mc-accent);
}

.mc-bottom-nav__item:active {
    background-color: var(--mc-surface-sunken);
}

/* Count badge anchored to the icon, not the label, so it survives text wrap. */
.mc-bottom-nav__icon {
    position: relative;
    display: inline-flex;
}

.mc-bottom-nav__badge {
    position: absolute;
    top: -4px;
    left: 100%;
    transform: translateX(-40%);
    min-width: 16px;
    height: 16px;
    padding-inline: 4px;
    border-radius: var(--mc-radius-pill);
    background-color: var(--mc-danger);
    color: #fff;
    font-size: 10px;
    font-weight: var(--mc-weight-bold);
    line-height: 16px;
    text-align: center;
}

/* ==========================================================================
   5. Page header
   ========================================================================== */

.mc-page-header {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    gap: var(--mc-space-3) var(--mc-space-4);
    margin-bottom: var(--mc-section-gap);
}

.mc-page-header__text { flex: 1 1 260px; min-width: 0; }

.mc-page-header__eyebrow {
    display: block;
    margin-bottom: var(--mc-space-1);
    color: var(--mc-text-subtle);
    font-size: var(--mc-text-xs);
    font-weight: var(--mc-weight-semibold);
    letter-spacing: var(--mc-tracking-caps);
    text-transform: uppercase;
}

.mc-page-header__title {
    margin: 0;
    font-size: var(--mc-text-2xl);
    font-weight: var(--mc-weight-bold);
}

.mc-page-header__subtitle {
    margin: var(--mc-space-1) 0 0;
    color: var(--mc-text-muted);
    font-size: var(--mc-text-md);
}

.mc-page-header__actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--mc-space-2);
}

/* On phones the primary action goes full width rather than crowding the title. */
@media (max-width: 575.98px) {
    .mc-page-header__actions { width: 100%; }
    .mc-page-header__actions > .btn { flex: 1 1 auto; }
}

/* ==========================================================================
   6. Cards
   ========================================================================== */

.card {
    background-color: var(--mc-surface);
    border: 1px solid var(--mc-border);
    border-radius: var(--mc-radius-lg);
    box-shadow: var(--mc-shadow-sm);
    color: var(--mc-text);
}

/* Templates lean on Bootstrap's border-0 + shadow-sm idiom; keep them coherent
   with the token elevation instead of letting Bootstrap's flat shadow win. */
.card.border-0 { border-color: transparent; }
.card.shadow-sm { box-shadow: var(--mc-shadow-sm) !important; }
.card.shadow { box-shadow: var(--mc-shadow-md) !important; }

.card-header {
    display: flex;
    align-items: center;
    gap: var(--mc-space-3);
    min-height: 56px;
    padding: var(--mc-space-3) var(--mc-space-5);
    background-color: transparent;
    border-bottom: 1px solid var(--mc-border);
    border-radius: var(--mc-radius-lg) var(--mc-radius-lg) 0 0 !important;
    font-weight: var(--mc-weight-semibold);
}

.card-header h1,
.card-header h2,
.card-header h3,
.card-header h5,
.card-header h6 {
    margin: 0;
    font-size: var(--mc-text-md);
    font-weight: var(--mc-weight-semibold);
}

/*
 * Legacy header fills. Templates paint these bars in bg-primary, bg-success,
 * bg-secondary and friends - a solid blue or green slab above the content that
 * predates the token layer and fights the accent. Every variant is neutralized
 * so the panel surface shows through and the heading carries normal ink.
 *
 * This covers modal headers too: the "New Tee Time" dialog opened with a solid
 * green bar and white text, which read as a different product from the page
 * behind it.
 */
.card-header[class*="bg-"],
.modal-header[class*="bg-"] {
    background-color: transparent !important;
    background-image: none !important;
    color: var(--mc-text) !important;
    border-color: var(--mc-border) !important;
}

.card-header[class*="bg-"] :is(h1, h2, h3, h4, h5, h6, .modal-title),
.modal-header[class*="bg-"] :is(h1, h2, h3, h4, h5, h6, .modal-title) {
    color: var(--mc-text) !important;
}

/* Those bars paired white close buttons with the fill; without the fill the
   white-on-white button would vanish. */
.modal-header .btn-close-white,
.card-header .btn-close-white { filter: none; }

.card-body { padding: var(--mc-space-5); }

.card-footer {
    padding: var(--mc-space-3) var(--mc-space-5);
    background-color: transparent;
    border-top: 1px solid var(--mc-border);
}

@media (max-width: 575.98px) {
    .card-body { padding: var(--mc-space-4); }
    .card-header { padding-inline: var(--mc-space-4); }
}

.hover-shadow {
    transition: transform var(--mc-duration-base) var(--mc-ease-out),
                box-shadow var(--mc-duration-base) var(--mc-ease-out),
                border-color var(--mc-duration-base) var(--mc-ease-out);
}

.hover-shadow:hover {
    transform: translateY(-2px);
    box-shadow: var(--mc-shadow-md) !important;
    border-color: var(--mc-border-strong);
}

/* The dashboard alternates row tints via {% cycle %}; retire the stripe and let
   spacing separate rows, but keep the hooks so the template still validates. */
.tee-time-even,
.tee-time-odd { background-color: var(--mc-surface); }

.tee-time-link {
    display: block;
    color: inherit;
    text-decoration: none;
}

.tee-time-link:hover { color: inherit; text-decoration: none; }

/* ==========================================================================
   7. Entity card - the repeating tee-time / friend / contact row
   ========================================================================== */

/*
 * A grid, not a flex row, and this matters for alignment.
 *
 * Previously the link was `flex: 1 1 auto` beside a variable number of action
 * buttons, so a row whose status hid one button (FULL has no lock control) grew
 * ~60px wider than its neighbors and the whole list failed to line up. A fixed
 * second track means the content column is identical on every row regardless of
 * how many actions that row happens to render.
 */
.mc-entity {
    display: grid;
    grid-template-columns: minmax(0, 1fr) var(--mc-entity-actions-width, 9.5rem);
    align-items: center;
    gap: var(--mc-space-4);
    padding-block: var(--mc-space-4);
    border-bottom: 1px solid var(--mc-border-subtle);
}

.mc-entity:last-child { border-bottom: 0; }
.mc-entity:first-child { padding-top: 0; }

/* Rows are separated by rules and rhythm rather than by a border each. Four
   bordered cards in a column read as a stack of boxes, not as a list. */
.mc-entity__link {
    min-width: 0;
    display: block;
    padding: 0;
    border: 0;
    background: none;
    color: inherit;
    text-decoration: none;
    transition: color var(--mc-duration-fast) var(--mc-ease-out);
}

.mc-entity__link:hover {
    color: inherit;
    text-decoration: none;
}

.mc-entity__link:hover .mc-entity__title { color: var(--mc-accent); }

.mc-entity__title {
    display: flex;
    align-items: baseline;
    gap: var(--mc-space-2);
    margin: 0 0 var(--mc-space-1);
    font-size: var(--mc-text-lg);
    font-weight: var(--mc-weight-semibold);
    letter-spacing: var(--mc-tracking-tight);
    color: var(--mc-text);
    transition: color var(--mc-duration-fast) var(--mc-ease-out);
}

.mc-entity__meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--mc-space-2) var(--mc-space-4);
    color: var(--mc-text-muted);
    font-size: var(--mc-text-sm);
}

.mc-entity__meta-item {
    display: inline-flex;
    align-items: center;
    gap: var(--mc-space-2);
    white-space: nowrap;
}

.mc-entity__meta-item i {
    color: var(--mc-text-subtle);
    width: 1em;
    text-align: center;
}

.mc-entity__actions {
    display: flex;
    flex-direction: row;
    align-items: center;
    justify-content: flex-end;
    gap: var(--mc-space-2);
}

/* Row actions stack beside the card on desktop and become a wrapped row on
   phones, where a vertical stack would stretch the card unreasonably tall. */
/* On phones the fixed action track would starve the title, so the row stacks
   and the actions return to the flow beneath it. */
@media (max-width: 575.98px) {
    .mc-entity {
        grid-template-columns: minmax(0, 1fr);
        gap: var(--mc-space-3);
    }
    .mc-entity__actions { justify-content: flex-start; }
}

/* ==========================================================================
   8. Buttons
   ========================================================================== */

.btn {
    --mc-btn-bg: transparent;
    --mc-btn-fg: var(--mc-text);
    --mc-btn-border: transparent;
    --mc-btn-bg-hover: transparent;

    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--mc-space-2);
    min-height: var(--mc-touch-min);
    padding: var(--mc-space-2) var(--mc-space-4);
    border: 1px solid var(--mc-btn-border);
    border-radius: var(--mc-radius-md);
    background-color: var(--mc-btn-bg);
    color: var(--mc-btn-fg);
    font-family: inherit;
    font-size: var(--mc-text-base);
    font-weight: var(--mc-weight-semibold);
    line-height: 1.2;
    white-space: nowrap;
    cursor: pointer;
    transition: background-color var(--mc-duration-fast) var(--mc-ease-out),
                border-color var(--mc-duration-fast) var(--mc-ease-out),
                color var(--mc-duration-fast) var(--mc-ease-out),
                transform var(--mc-duration-fast) var(--mc-ease-out);
    -webkit-tap-highlight-color: transparent;
}

.btn:hover {
    background-color: var(--mc-btn-bg-hover);
    color: var(--mc-btn-fg);
    text-decoration: none;
}

.btn:active { transform: translateY(1px); }

.btn:focus-visible {
    outline: none;
    box-shadow: var(--mc-focus-ring);
}

.btn:disabled,
.btn.disabled {
    opacity: 0.55;
    cursor: not-allowed;
    transform: none;
}

/* Bootstrap's own size modifiers would undercut the 44px touch floor, so the
   small variant trims padding and type but never the minimum height. */
.btn-sm {
    min-height: var(--mc-touch-min);
    padding: var(--mc-space-1) var(--mc-space-3);
    font-size: var(--mc-text-sm);
}

.btn-lg {
    min-height: var(--mc-touch-comfortable);
    padding: var(--mc-space-3) var(--mc-space-6);
    font-size: var(--mc-text-md);
}

/* Primary action = accent green. The navy brand is reserved for chrome, where
   it reads as identity rather than as "click me". */
.btn-primary,
.btn-success {
    --mc-btn-bg: var(--mc-accent);
    --mc-btn-bg-hover: var(--mc-accent-hover);
    --mc-btn-border: var(--mc-accent);
    --mc-btn-fg: var(--mc-text-on-accent);
}

.btn-primary:hover,
.btn-success:hover { border-color: var(--mc-accent-hover); }

.btn-secondary {
    --mc-btn-bg: var(--mc-surface-sunken);
    --mc-btn-bg-hover: var(--mc-border);
    --mc-btn-border: var(--mc-border);
    --mc-btn-fg: var(--mc-text);
}

.btn-danger {
    --mc-btn-bg: var(--mc-danger);
    --mc-btn-bg-hover: var(--mc-red-700);
    --mc-btn-border: var(--mc-danger);
    --mc-btn-fg: #fff;
}

.btn-danger:focus-visible { box-shadow: var(--mc-focus-ring-danger); }

.btn-warning {
    --mc-btn-bg: var(--mc-warning);
    --mc-btn-bg-hover: var(--mc-amber-700);
    --mc-btn-border: var(--mc-warning);
    --mc-btn-fg: #fff;
}

.btn-light {
    --mc-btn-bg: var(--mc-surface);
    --mc-btn-bg-hover: var(--mc-surface-sunken);
    --mc-btn-border: var(--mc-border);
    --mc-btn-fg: var(--mc-text);
}

.btn-link {
    --mc-btn-fg: var(--mc-accent);
    min-height: auto;
    padding: var(--mc-space-1) var(--mc-space-2);
    text-decoration: none;
}

.btn-link:hover { --mc-btn-fg: var(--mc-accent-hover); text-decoration: underline; }

.btn-outline-primary,
.btn-outline-success {
    --mc-btn-border: var(--mc-accent);
    --mc-btn-fg: var(--mc-accent);
    --mc-btn-bg-hover: var(--mc-accent-soft);
}

.btn-outline-secondary {
    --mc-btn-border: var(--mc-border-strong);
    --mc-btn-fg: var(--mc-text-muted);
    --mc-btn-bg-hover: var(--mc-surface-sunken);
}

.btn-outline-secondary:hover { color: var(--mc-text); }

.btn-outline-danger {
    --mc-btn-border: var(--mc-danger);
    --mc-btn-fg: var(--mc-danger);
    --mc-btn-bg-hover: var(--mc-danger-soft);
}

.btn-outline-warning {
    --mc-btn-border: var(--mc-warning);
    --mc-btn-fg: var(--mc-warning-soft-text);
    --mc-btn-bg-hover: var(--mc-warning-soft);
}

.btn-outline-light {
    --mc-btn-border: rgba(255, 255, 255, 0.45);
    --mc-btn-fg: #fff;
    --mc-btn-bg-hover: rgba(255, 255, 255, 0.14);
}

/* Icon-only buttons: square, and they must carry an aria-label in markup. */
.btn-icon {
    width: var(--mc-touch-min);
    min-width: var(--mc-touch-min);
    padding-inline: 0;
}

.btn-group > .btn { border-radius: var(--mc-radius-md); }

.btn-group > .btn:not(:last-child) {
    border-top-right-radius: 0;
    border-bottom-right-radius: 0;
}

.btn-group > .btn:not(:first-child) {
    border-top-left-radius: 0;
    border-bottom-left-radius: 0;
    margin-left: -1px;
}

/* ==========================================================================
   9. Badges & pills
   ========================================================================== */

.badge {
    display: inline-flex;
    align-items: center;
    gap: var(--mc-space-1);
    padding: 0.3em 0.65em;
    border-radius: var(--mc-radius-pill);
    font-size: var(--mc-text-xs);
    font-weight: var(--mc-weight-semibold);
    letter-spacing: var(--mc-tracking-wide);
    line-height: 1.35;
}

/* Solid status fills are loud when several sit in one list. Soft tints keep the
   semantic color legible while letting the row content stay dominant. */
.badge.bg-primary   { background-color: var(--mc-info-soft) !important;    color: var(--mc-info-soft-text) !important; }
.badge.bg-secondary { background-color: var(--mc-surface-sunken) !important; color: var(--mc-text-muted) !important; }
.badge.bg-success   { background-color: var(--mc-success-soft) !important; color: var(--mc-success-soft-text) !important; }
.badge.bg-danger    { background-color: var(--mc-danger-soft) !important;  color: var(--mc-danger-soft-text) !important; }
.badge.bg-warning   { background-color: var(--mc-warning-soft) !important; color: var(--mc-warning-soft-text) !important; }
.badge.bg-info      { background-color: var(--mc-info-soft) !important;    color: var(--mc-info-soft-text) !important; }
.badge.bg-light     { background-color: var(--mc-surface-sunken) !important; color: var(--mc-text-muted) !important; }
.badge.bg-dark      { background-color: var(--mc-surface-inverse) !important; color: var(--mc-text-inverse) !important; }

/* Counts in tabs and nav stay solid - they are notifications, not statuses. */
.nav-link .badge.bg-danger,
.mc-count-badge {
    background-color: var(--mc-danger) !important;
    color: #fff !important;
}

/* ==========================================================================
   10. Forms
   ========================================================================== */

.form-label {
    display: block;
    margin-bottom: var(--mc-space-2);
    color: var(--mc-text);
    font-size: var(--mc-text-sm);
    font-weight: var(--mc-weight-semibold);
}

.form-text {
    margin-top: var(--mc-space-2);
    color: var(--mc-text-muted);
    font-size: var(--mc-text-sm);
}

.form-control,
.form-select {
    min-height: var(--mc-touch-min);
    padding: var(--mc-space-2) var(--mc-space-3);
    border: 1px solid var(--mc-border-strong);
    border-radius: var(--mc-radius-md);
    background-color: var(--mc-surface);
    color: var(--mc-text);
    font-family: inherit;
    /* 16px minimum prevents iOS Safari from zooming the viewport on focus. */
    font-size: max(16px, var(--mc-text-base));
    line-height: 1.4;
    transition: border-color var(--mc-duration-fast) var(--mc-ease-out),
                box-shadow var(--mc-duration-fast) var(--mc-ease-out);
}

@media (min-width: 768px) {
    .form-control,
    .form-select { font-size: var(--mc-text-base); }
}

.form-control::placeholder { color: var(--mc-text-subtle); }

.form-control:focus,
.form-select:focus {
    border-color: var(--mc-accent);
    box-shadow: var(--mc-focus-ring);
    background-color: var(--mc-surface);
    color: var(--mc-text);
    outline: none;
}

.form-control:disabled,
.form-select:disabled {
    background-color: var(--mc-surface-sunken);
    color: var(--mc-text-subtle);
    cursor: not-allowed;
}

.form-select {
    /* Chevron is inlined so it can follow currentColor across themes. */
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%236f7994' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 6l4 4 4-4'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right var(--mc-space-3) center;
    background-size: 16px 16px;
    padding-right: var(--mc-space-10);
    appearance: none;
}

textarea.form-control { min-height: 96px; line-height: var(--mc-leading-normal); }

.input-group > .form-control,
.input-group > .form-select { border-radius: 0; }

.input-group > :first-child { border-start-start-radius: var(--mc-radius-md); border-end-start-radius: var(--mc-radius-md); }
.input-group > :last-child  { border-start-end-radius: var(--mc-radius-md); border-end-end-radius: var(--mc-radius-md); }

.input-group-text {
    display: flex;
    align-items: center;
    min-height: var(--mc-touch-min);
    padding: var(--mc-space-2) var(--mc-space-3);
    border: 1px solid var(--mc-border-strong);
    background-color: var(--mc-surface-sunken);
    color: var(--mc-text-muted);
    font-size: var(--mc-text-sm);
}

/* Templates pin these to white, which is unreadable on a dark surface. */
.input-group-text.bg-white,
.form-control.bg-white {
    background-color: var(--mc-surface) !important;
    color: var(--mc-text-muted);
}

.form-check { min-height: var(--mc-touch-min); display: flex; align-items: center; gap: var(--mc-space-2); padding-left: 0; }
.form-check .form-check-input { margin-left: 0; margin-top: 0; float: none; }
.form-check-label { margin: 0; cursor: pointer; }

.form-check-input {
    width: 1.15rem;
    height: 1.15rem;
    border: 1px solid var(--mc-border-strong);
    background-color: var(--mc-surface);
    cursor: pointer;
    flex-shrink: 0;
}

.form-check-input:checked {
    background-color: var(--mc-accent);
    border-color: var(--mc-accent);
}

.form-check-input:focus {
    border-color: var(--mc-accent);
    box-shadow: var(--mc-focus-ring);
}

.form-switch .form-check-input { width: 2.25rem; border-radius: var(--mc-radius-pill); }

/* ==========================================================================
   11. Tabs (segmented on mobile, underline on desktop)
   ========================================================================== */

.nav-tabs {
    gap: var(--mc-space-1);
    border-bottom: 1px solid var(--mc-border);
    flex-wrap: nowrap;
    overflow-x: auto;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
}

.nav-tabs::-webkit-scrollbar { display: none; }

.nav-tabs .nav-link {
    display: inline-flex;
    align-items: center;
    gap: var(--mc-space-2);
    min-height: var(--mc-touch-min);
    padding: var(--mc-space-2) var(--mc-space-3);
    border: 0;
    border-bottom: 2px solid transparent;
    border-radius: 0;
    background: none;
    color: var(--mc-text-muted);
    font-size: var(--mc-text-base);
    font-weight: var(--mc-weight-medium);
    white-space: nowrap;
    transition: color var(--mc-duration-fast) var(--mc-ease-out),
                border-color var(--mc-duration-fast) var(--mc-ease-out);
}

.nav-tabs .nav-link:hover {
    border-bottom-color: var(--mc-border-strong);
    color: var(--mc-text);
}

.nav-tabs .nav-link.active {
    background: none;
    border-bottom-color: var(--mc-accent);
    color: var(--mc-text);
    font-weight: var(--mc-weight-semibold);
}

.nav-pills .nav-link {
    min-height: var(--mc-touch-min);
    border-radius: var(--mc-radius-md);
    color: var(--mc-text-muted);
    font-weight: var(--mc-weight-medium);
}

.nav-pills .nav-link.active {
    background-color: var(--mc-accent-soft);
    color: var(--mc-accent-soft-text);
}

/* ==========================================================================
   12. Empty state
   ========================================================================== */

.mc-empty {
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    padding: var(--mc-space-10) var(--mc-space-5);
}

/* Inside a panel an empty state should stay compact rather than inheriting the
   height of whatever sits beside it. */
.mc-panel > .mc-empty { padding-block: var(--mc-space-8); }

/*
 * Sidebar variant: left-aligned, no icon, minimal padding. The centerd
 * icon-over-text treatment is built for a wide main column; dropped into a
 * 300px rail it reads as an oversized placeholder.
 */
.mc-empty--compact {
    align-items: flex-start;
    text-align: left;
    padding: 0;
}

.mc-empty--compact .mc-empty__icon { display: none; }

.mc-empty--compact .mc-empty__title {
    color: var(--mc-text-subtle);
    font-weight: var(--mc-weight-normal);
    margin-bottom: 0;
}

.mc-empty__icon {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 56px;
    height: 56px;
    margin-bottom: var(--mc-space-4);
    border-radius: var(--mc-radius-pill);
    background-color: var(--mc-surface-sunken);
    color: var(--mc-text-subtle);
    font-size: 1.4rem;
}

.mc-empty__title {
    margin: 0 0 var(--mc-space-2);
    font-size: var(--mc-text-md);
    font-weight: var(--mc-weight-semibold);
    color: var(--mc-text);
}

.mc-empty__body {
    max-width: 42ch;
    margin: 0 0 var(--mc-space-5);
    color: var(--mc-text-muted);
    font-size: var(--mc-text-base);
}

.mc-empty__body:last-child { margin-bottom: 0; }

/* ==========================================================================
   13. Stat
   ========================================================================== */

/*
 * Stats are bare by default - no box, no border, no icon. Separation comes from
 * the grid's hairlines below, and hierarchy from the size gap between a large
 * tabular value and a small quiet label. Boxing each stat (the previous
 * treatment) produced seven nested rectangles inside one card and read as a
 * 2015 widget wall.
 */
.mc-stat {
    min-width: 0;
}

.mc-stat__label {
    display: block;
    margin-bottom: var(--mc-space-1);
    color: var(--mc-text-subtle);
    font-size: var(--mc-text-sm);
    font-weight: var(--mc-weight-normal);
    line-height: var(--mc-leading-snug);
}

.mc-stat__value {
    font-family: var(--mc-font-num);
    font-size: var(--mc-text-3xl);
    font-weight: var(--mc-weight-semibold);
    line-height: 1.1;
    letter-spacing: var(--mc-tracking-tight);
    color: var(--mc-text);
    font-variant-numeric: tabular-nums;
}

.mc-stat__value a { color: inherit; text-decoration: none; }
.mc-stat__value a:hover { color: var(--mc-accent); }

/* An absent value should recede, not sit at the same weight as a real one. */
.mc-stat__value--empty {
    color: var(--mc-text-subtle);
    font-weight: var(--mc-weight-normal);
    font-size: var(--mc-text-lg);
}

.mc-stat__hint {
    margin: var(--mc-space-1) 0 0;
    color: var(--mc-text-subtle);
    font-size: var(--mc-text-sm);
}

/*
 * Separation by space alone - no rules, no cell padding, no fills.
 *
 * An earlier version drew hairlines by letting a 1px gap expose the container
 * color. It aligned badly and, more importantly, read as a table: swapping
 * gray boxes for a bordered grid is a lateral move, not a simplification.
 *
 * Cell padding is also deliberately zero. Padding here was previously applied
 * with :nth-child(odd/even), which keys off DOM position rather than visual
 * position, so a full-width cell inherited whichever rule its index happened to
 * match and sat at a different left edge from its neighbors. With no padding
 * every label starts flush to its column, and a wide cell is flush with the
 * first - alignment is structural rather than something to keep in sync.
 */
.mc-stat-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    column-gap: var(--mc-space-6);
    row-gap: var(--mc-space-6);
}

.mc-stat-grid > .mc-stat--wide { grid-column: 1 / -1; }

/* Three across on desktop, two on phones. The odd tile wraps to its own row
   rather than stretching, so the column widths stay equal across both rows. */
.mc-stat-grid--3 { grid-template-columns: repeat(2, minmax(0, 1fr)); }

@media (min-width: 768px) {
    .mc-stat-grid--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

/* A KPI row: four across on desktop, two on phones. Same bare treatment as the
   two-up grid - the number is the content, spacing does the separating. */
.mc-stat-grid--4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }

@media (min-width: 768px) {
    .mc-stat-grid--4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

/* A stat whose value is a word rather than a numeral should not sit at numeral
   size - "Improving" at 3xl reads as a headline, not a measurement. */
.mc-stat__value--word {
    font-size: var(--mc-text-lg);
    font-weight: var(--mc-weight-semibold);
    letter-spacing: normal;
}

/* Ruled navigation list - replaces a grid of identical cards each ending in an
   identical button, where six equal choices read as no choice at all. */
.mc-nav-list { display: flex; flex-direction: column; }

.mc-nav-list__item {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--mc-space-4);
    padding-block: var(--mc-space-4);
    border-bottom: 1px solid var(--mc-border-subtle);
    color: inherit;
    text-decoration: none;
    transition: color var(--mc-duration-fast) var(--mc-ease-out);
}

.mc-nav-list__item:last-child { border-bottom: 0; }
.mc-nav-list__item:hover { color: inherit; text-decoration: none; }
.mc-nav-list__item:hover .mc-nav-list__title { color: var(--mc-accent); }

.mc-nav-list__title {
    margin: 0 0 var(--mc-space-1);
    font-size: var(--mc-text-md);
    font-weight: var(--mc-weight-semibold);
    color: var(--mc-text);
    transition: color var(--mc-duration-fast) var(--mc-ease-out);
}

.mc-nav-list__desc { margin: 0; color: var(--mc-text-muted); font-size: var(--mc-text-sm); }
.mc-nav-list__chev { color: var(--mc-text-subtle); flex-shrink: 0; }

@media (max-width: 575.98px) {
    .mc-nav-list__item { flex-direction: column; gap: var(--mc-space-1); }
    .mc-nav-list__chev { display: none; }
}

/* ==========================================================================
   13a. Hero, meter, sparkline - the data-forward pieces
   ========================================================================== */

/*
 * The dashboard's focal point. Sits on --mc-brand, which resolves to a dark
 * surface in BOTH themes (navy in light, near-black in dark), so the white text
 * on it is legible either way and the block never inverts into a white slab.
 */
.mc-hero {
    display: block;
    padding: var(--mc-space-6);
    margin-bottom: var(--mc-space-6);
    border-radius: var(--mc-radius-xl);
    background-color: var(--mc-brand);
    color: #fff;
    text-decoration: none;
    transition: transform var(--mc-duration-base) var(--mc-ease-out),
                box-shadow var(--mc-duration-base) var(--mc-ease-out);
}

.mc-hero:hover {
    color: #fff;
    text-decoration: none;
    transform: translateY(-2px);
    box-shadow: var(--mc-shadow-lg);
}

.mc-hero:focus-visible { outline: 2px solid var(--mc-accent); outline-offset: 3px; }

.mc-hero__eyebrow {
    display: block;
    margin-bottom: var(--mc-space-2);
    /* Was green-200, left over from the green accent. The label is decorative,
       so it takes a light step of the brand navy; the meter below it keeps
       green because "how full is the roster" is a status, which is the role
       green now owns. */
    color: var(--mc-navy-200);
    font-size: var(--mc-text-xs);
    font-weight: var(--mc-weight-semibold);
    letter-spacing: var(--mc-tracking-caps);
    text-transform: uppercase;
}

.mc-hero__title {
    margin: 0 0 var(--mc-space-1);
    color: #fff;
    font-size: var(--mc-text-2xl);
    font-weight: var(--mc-weight-bold);
    letter-spacing: var(--mc-tracking-tight);
    line-height: var(--mc-leading-tight);
}

.mc-hero__when {
    margin: 0 0 var(--mc-space-5);
    color: rgba(255, 255, 255, 0.72);
    font-size: var(--mc-text-md);
}

.mc-hero__meter { display: flex; flex-direction: column; gap: var(--mc-space-2); }

.mc-hero__meta {
    color: rgba(255, 255, 255, 0.72);
    font-size: var(--mc-text-sm);
}

/* Fill level for places taken. Always paired with the same count in words -
   a bar alone is unreadable to a screen reader and ambiguous at a glance. */
.mc-meter {
    height: 6px;
    border-radius: var(--mc-radius-pill);
    /* Track colour is a variable so the same meter works on the navy hero and
       on a light panel; only the surface it sits on knows which is right. */
    background-color: var(--mc-meter-track, rgba(255, 255, 255, 0.18));
    overflow: hidden;
}

/*
 * Fill level is a horizontal scale, not a width change. Animating `width`
 * forces layout on every frame; scaleX composites on the GPU and leaves layout
 * untouched. The value arrives as a 0-100 number in --mc-meter-value so the
 * template does not have to know about the transform.
 */
.mc-meter__fill {
    display: block;
    height: 100%;
    width: 100%;
    border-radius: inherit;
    background-color: var(--mc-green-300);
    transform: scaleX(calc(var(--mc-meter-value, 0) / 100));
    transform-origin: left center;
    transition: transform var(--mc-duration-slow) var(--mc-ease-out);
}

@media (prefers-reduced-motion: reduce) {
    .mc-meter__fill { transition: none; }
}

/*
 * Sparkline. Inherits currentColor from its parent so it picks up whatever ink
 * the surrounding stat uses, and needs no theme-specific rule of its own.
 */
.mc-spark {
    display: inline-block;
    width: 72px;
    height: 20px;
    margin-left: var(--mc-space-2);
    color: var(--mc-text-subtle);
    vertical-align: middle;
}

/*
 * Trend color uses the validated diverging pair, not green/red, and only ever
 * alongside the trend stated in words - the line must not be the sole carrier
 * of "good" or "bad".
 *
 * The polarity is inverted relative to intuition because this is golf: a rising
 * score is a worse score. Leaving the sparkline accent-green while the label
 * read "Rising" implied improvement it did not mean.
 */
.mc-spark--better { color: var(--mc-viz-neg); }
.mc-spark--worse { color: var(--mc-viz-pos); }

.mc-spark svg { display: block; width: 100%; height: 100%; overflow: visible; }

@media (max-width: 575.98px) {
    .mc-hero { padding: var(--mc-space-5); }
    .mc-spark { width: 56px; }
}

/* ==========================================================================
   13b. Section & panel - card chrome without the card
   ========================================================================== */

/*
 * A section is a heading in the page flow with its content beneath it. It
 * replaces the card-header pattern, which fenced every group behind a bar and
 * a rule and stacked three horizontal lines before any content was visible.
 */
.mc-section { margin-bottom: var(--mc-space-8); }
.mc-section:last-child { margin-bottom: 0; }

.mc-section__head {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--mc-space-2) var(--mc-space-4);
    margin-bottom: var(--mc-space-4);
    /* Reserving a button's height whether or not this head has one keeps the
       titles of side-by-side sections on the same baseline. Without it a column
       with an action sat ~13px lower than the column beside it. */
    min-height: var(--mc-touch-min);
}

/* Absorbs the free space after the title, which right-aligns any action to the
   column edge - where it lines up with the panel below it. */
.mc-section__head > .mc-section__title { margin-right: auto; }

.mc-section__title {
    margin: 0;
    font-size: var(--mc-text-lg);
    font-weight: var(--mc-weight-semibold);
    letter-spacing: var(--mc-tracking-tight);
}

.mc-section__meta {
    color: var(--mc-text-subtle);
    font-size: var(--mc-text-sm);
}

/* A quiet container for grouped content, with no header bar. */
.mc-panel {
    padding: var(--mc-space-5);
    border: 1px solid var(--mc-border);
    border-radius: var(--mc-radius-lg);
    background-color: var(--mc-surface);
}

.mc-panel--flush { padding: 0; }

/*
 * Sticky form actions. A long settings form had its only save control at the
 * very bottom, so a change made near the top required scrolling past unrelated
 * sections to commit it.
 *
 * On phones it clears the fixed bottom nav; scroll-padding keeps an anchored
 * field from landing underneath the bar when the completion checklist jumps to
 * it.
 */
.mc-form-actions {
    position: sticky;
    bottom: 0;
    z-index: var(--mc-z-sticky);
    display: flex;
    justify-content: flex-end;
    gap: var(--mc-space-3);
    margin-top: var(--mc-space-8);
    padding: var(--mc-space-4) 0;
    background-color: var(--mc-surface);
    border-top: 1px solid var(--mc-border);
}

@media (max-width: 767.98px) {
    body.has-bottom-nav .mc-form-actions {
        bottom: calc(var(--mc-bottom-nav-height) + var(--mc-safe-bottom));
    }
    .mc-form-actions > .btn { flex: 1 1 auto; }
}

/* Anchored jumps land below the sticky top bar rather than under it. */
html { scroll-padding-top: calc(var(--mc-topbar-height) + var(--mc-space-4)); }

/* The completion checklist rows are links now, so they need a hover state. */
a.list-group-item:hover { background-color: var(--mc-surface-sunken); }

/* Simple ruled list: rows separated by hairlines rather than alternating fills. */
.mc-list { display: flex; flex-direction: column; }

.mc-list__row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--mc-space-3);
    padding-block: var(--mc-space-3);
    border-bottom: 1px solid var(--mc-border-subtle);
}

.mc-list__row:last-child { border-bottom: 0; padding-bottom: 0; }
.mc-list__row:first-child { padding-top: 0; }
.mc-list__primary { font-weight: var(--mc-weight-medium); color: var(--mc-text); }
.mc-list__secondary { color: var(--mc-text-subtle); font-size: var(--mc-text-sm); }

/* ==========================================================================
   14. Alerts, modals, dropdowns, tables, pagination
   ========================================================================== */

.alert {
    display: flex;
    align-items: flex-start;
    gap: var(--mc-space-3);
    padding: var(--mc-space-4);
    border: 1px solid transparent;
    border-radius: var(--mc-radius-lg);
    font-size: var(--mc-text-base);
}

.alert-success { background-color: var(--mc-success-soft); border-color: var(--mc-accent-border); color: var(--mc-success-soft-text); }
.alert-danger  { background-color: var(--mc-danger-soft);  border-color: transparent; color: var(--mc-danger-soft-text); }
.alert-warning { background-color: var(--mc-warning-soft); border-color: transparent; color: var(--mc-warning-soft-text); }
.alert-info,
.alert-primary { background-color: var(--mc-info-soft);    border-color: transparent; color: var(--mc-info-soft-text); }
.alert-secondary { background-color: var(--mc-surface-sunken); border-color: var(--mc-border); color: var(--mc-text-muted); }

.alert-dismissible { padding-right: var(--mc-space-12); }

.modal-content {
    border: 1px solid var(--mc-border);
    border-radius: var(--mc-radius-xl);
    background-color: var(--mc-surface);
    box-shadow: var(--mc-shadow-lg);
}

.modal-header,
.modal-footer {
    padding: var(--mc-space-4) var(--mc-space-5);
    border-color: var(--mc-border);
}

.modal-title { font-size: var(--mc-text-lg); font-weight: var(--mc-weight-semibold); }
.modal-body { padding: var(--mc-space-5); }
.modal-backdrop.show { opacity: 0.55; }

/* Dialogs become bottom sheets on phones: reachable by thumb, and the drag
   affordance matches what a native app would present. */
@media (max-width: 575.98px) {
    .modal-dialog:not(.modal-fullscreen) {
        margin: 0;
        position: absolute;
        inset-inline: 0;
        bottom: 0;
        max-width: none;
    }

    .modal-content {
        border-radius: var(--mc-radius-xl) var(--mc-radius-xl) 0 0;
        border-bottom: 0;
        max-height: 92dvh;
        padding-bottom: var(--mc-safe-bottom);
    }

    .modal-body { overflow-y: auto; }

    .modal-header::before {
        content: "";
        position: absolute;
        top: 8px;
        left: 50%;
        transform: translateX(-50%);
        width: 36px;
        height: 4px;
        border-radius: var(--mc-radius-pill);
        background-color: var(--mc-border-strong);
    }

    .modal-header { position: relative; padding-top: var(--mc-space-6); }
    .modal-footer > .btn { flex: 1 1 auto; }
}

.dropdown-menu {
    padding: var(--mc-space-2);
    border: 1px solid var(--mc-border);
    border-radius: var(--mc-radius-lg);
    background-color: var(--mc-surface);
    box-shadow: var(--mc-shadow-md);
}

.dropdown-item {
    display: flex;
    align-items: center;
    gap: var(--mc-space-2);
    min-height: var(--mc-touch-min);
    border-radius: var(--mc-radius-sm);
    color: var(--mc-text);
    font-size: var(--mc-text-base);
}

.dropdown-item:hover,
.dropdown-item:focus { background-color: var(--mc-surface-sunken); color: var(--mc-text); }
.dropdown-divider { border-color: var(--mc-border); }

.table {
    --bs-table-bg: transparent;
    --bs-table-color: var(--mc-text);
    color: var(--mc-text);
    border-color: var(--mc-border);
}

.table > thead th {
    border-bottom: 1px solid var(--mc-border);
    color: var(--mc-text-muted);
    font-size: var(--mc-text-xs);
    font-weight: var(--mc-weight-semibold);
    letter-spacing: var(--mc-tracking-caps);
    text-transform: uppercase;
}

.table > tbody td {
    padding-block: var(--mc-space-3);
    border-color: var(--mc-border-subtle);
    vertical-align: middle;
}

.table-hover > tbody > tr:hover > * {
    --bs-table-accent-bg: var(--mc-surface-sunken);
    background-color: var(--mc-surface-sunken);
    color: var(--mc-text);
}

/* Wide tables scroll inside their own container instead of the page body. */
.table-responsive { border-radius: var(--mc-radius-lg); }

.list-group-item {
    padding: var(--mc-space-3) var(--mc-space-4);
    border-color: var(--mc-border);
    background-color: var(--mc-surface);
    color: var(--mc-text);
}

.pagination { gap: var(--mc-space-1); }

.page-link {
    display: flex;
    align-items: center;
    justify-content: center;
    min-width: var(--mc-touch-min);
    min-height: var(--mc-touch-min);
    border: 1px solid var(--mc-border);
    border-radius: var(--mc-radius-md) !important;
    background-color: var(--mc-surface);
    color: var(--mc-text-muted);
    font-size: var(--mc-text-sm);
    font-weight: var(--mc-weight-medium);
}

.page-link:hover { background-color: var(--mc-surface-sunken); color: var(--mc-text); }

.page-item.active .page-link {
    background-color: var(--mc-accent);
    border-color: var(--mc-accent);
    color: var(--mc-text-on-accent);
}

.page-item.disabled .page-link { background-color: var(--mc-surface); color: var(--mc-text-subtle); }

.progress { background-color: var(--mc-surface-sunken); border-radius: var(--mc-radius-pill); }
.progress-bar { background-color: var(--mc-accent); }

.spinner-border, .spinner-grow { color: var(--mc-accent); }

.tooltip-inner {
    border-radius: var(--mc-radius-md);
    background-color: var(--mc-surface-inverse);
    color: var(--mc-text-inverse);
    font-size: var(--mc-text-sm);
}

/* ==========================================================================
   15. Install prompt
   ========================================================================== */

.mc-install-prompt {
    position: fixed;
    inset-inline: 0;
    bottom: 0;
    z-index: var(--mc-z-toast);
    display: flex;
    align-items: center;
    gap: var(--mc-space-4);
    padding: var(--mc-space-4) var(--mc-gutter);
    padding-bottom: calc(var(--mc-space-4) + var(--mc-safe-bottom));
    background-color: var(--mc-surface-inverse);
    color: var(--mc-text-inverse);
    box-shadow: var(--mc-shadow-lg);
}

/* Clears the bottom nav so the two fixed bars never overlap on phones. */
@media (max-width: 767.98px) {
    body.has-bottom-nav .mc-install-prompt {
        bottom: calc(var(--mc-bottom-nav-height) + var(--mc-safe-bottom));
        padding-bottom: var(--mc-space-4);
    }
}

.mc-install-prompt__text { flex: 1 1 auto; min-width: 0; }
.mc-install-prompt__title { margin: 0; font-size: var(--mc-text-base); font-weight: var(--mc-weight-semibold); }
.mc-install-prompt__body { margin: 2px 0 0; font-size: var(--mc-text-sm); opacity: 0.75; }
.mc-install-prompt__actions { display: flex; align-items: center; gap: var(--mc-space-2); flex-shrink: 0; }

/* ==========================================================================
   16. Footer
   ========================================================================== */

.mc-footer {
    flex-shrink: 0;
    margin-top: auto;
    padding-block: var(--mc-space-6);
    border-top: 1px solid var(--mc-border);
    background-color: var(--mc-surface);
    color: var(--mc-text-subtle);
    font-size: var(--mc-text-sm);
}

.mc-footer__inner {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--mc-space-3);
    max-width: var(--mc-container-max);
    margin-inline: auto;
    padding-inline: var(--mc-gutter);
}

/* Footer links rendered ~20px tall, under the 44px floor. Vertical padding
   gets them there; the row already had the space, so nothing moves visually. */
.mc-footer a {
    display: inline-flex;
    align-items: center;
    min-height: var(--mc-touch-min);
    color: var(--mc-text-muted);
}

.mc-footer a:hover { color: var(--mc-text); }
.mc-footer__links { display: flex; flex-wrap: wrap; gap: var(--mc-space-4); }

/* The bottom nav would otherwise sit on top of the footer's last row. */
@media (max-width: 767.98px) {
    body.has-bottom-nav .mc-footer {
        padding-bottom: calc(var(--mc-space-6) + var(--mc-bottom-nav-height) + var(--mc-safe-bottom));
    }
}

/* ==========================================================================
   16b. Legacy structure adopted into the design language
   ==========================================================================
 * Sixteen templates still carry Bootstrap's card / card-header / display-4
 * markup, ~400 cards and ~60 headers in total. Rewriting that by regex would
 * be far riskier than teaching the system to render it correctly, so these
 * rules make the legacy structure adopt the same language the dashboard's
 * hand-built components use. Templates need not change to benefit.
 */

/* A card becomes a quiet panel: the heavy border and shadow go, since a page
   full of outlined boxes is the single strongest "dated admin panel" signal. */
.card {
    box-shadow: none;
}

.card.shadow-sm,
.card.shadow { box-shadow: none !important; }

/* The header bar becomes a heading in the flow - no fill, no dividing rule. */
.card-header {
    border-bottom: 0;
    padding-bottom: 0;
    min-height: 0;
    padding-top: var(--mc-space-5);
}

.card-header h1,
.card-header h2,
.card-header h3,
.card-header h5,
.card-header h6,
.card-header .h5 {
    font-size: var(--mc-text-lg);
    font-weight: var(--mc-weight-semibold);
    letter-spacing: var(--mc-tracking-tight);
}

/* Bootstrap's display sizes are set for hero type, not for a stat inside a
   panel; at 3.5rem they overwhelmed everything around them. */
.card-text.display-4,
.display-4,
.stat-value {
    font-family: var(--mc-font-num);
    font-size: var(--mc-text-3xl) !important;
    font-weight: var(--mc-weight-semibold) !important;
    line-height: 1.1;
    letter-spacing: var(--mc-tracking-tight);
    font-variant-numeric: tabular-nums;
    color: var(--mc-text);
}

.stat-label,
.card-title {
    color: var(--mc-text-subtle);
    font-size: var(--mc-text-sm);
    font-weight: var(--mc-weight-normal);
}

/* The colored glyph beside a stat is decoration competing with the number. */
.stat-icon { display: none; }

/* display-1 is used for standalone confirmation/status pages, where a large
   glyph is the point; keep it big but stop it shouting in a status color. */
.display-1 { font-size: clamp(2.5rem, 2rem + 2.5vw, 4rem); }

/*
 * Header action clusters. Bootstrap's .d-flex does not wrap, so a header with
 * two or three buttons stayed on one line and pushed the page ~300px wider than
 * a phone viewport - the address book scrolled sideways with its Google import
 * button off-screen entirely. Wrapping is correct at every width; on desktop
 * there is room, so nothing moves.
 */
.card-header .d-flex,
.mc-section__head .d-flex,
.card-header.d-flex {
    flex-wrap: wrap;
    gap: var(--mc-space-2);
}

/* A header whose title and actions no longer fit side by side stacks rather
   than squeezing the title down to a few characters. */
@media (max-width: 575.98px) {
    .card-header.d-flex.justify-content-between { align-items: flex-start !important; }
    .card-header .d-flex > form,
    .card-header .d-flex > .btn { flex: 1 1 auto; }
}

/* Wide tables scroll inside their own box instead of taking the page with them. */
.table-responsive { overflow-x: auto; -webkit-overflow-scrolling: touch; }

/*
 * Legacy stat blocks are wrapped in `p-2 rounded bg-light`, which boxes every
 * number in gray. :has() lets the fill be dropped wherever the box exists only
 * to hold a stat, without touching the ~16 templates that emit it.
 */
.bg-light:has(> .stat-value),
.bg-light:has(> div > .stat-value),
.bg-light:has(.stat-value) {
    background-color: transparent !important;
    padding: 0 !important;
    margin-bottom: var(--mc-space-5) !important;
}

/*
 * Decorative glyphs wearing status-color utilities produced a rainbow that
 * encoded nothing - a yellow star beside a blue envelope beside a green group,
 * all meaning "here is a list item". Neutralized to a single quiet ink.
 *
 * Two exceptions keep their color, because there it is doing work: glyphs
 * inside a button (which owns its own ink) and inside a badge (where the color
 * IS the status, and which always carries a text label too).
 */
i.text-primary,
i.text-success,
i.text-warning,
i.text-info,
i.text-danger,
i.text-secondary {
    color: var(--mc-text-subtle) !important;
}

.btn i.text-primary, .btn i.text-success, .btn i.text-warning,
.btn i.text-info, .btn i.text-danger, .btn i.text-secondary,
.badge i { color: inherit !important; }

/* Tip/callout rows (an icon plus a heading and a line of copy): the gray fill
   turned a three-item list into a stack of chips. Matched on the icon AND the
   heading together so stat blocks and badges, which have neither pairing, are
   left alone. */
.bg-light:has(i):has(h6) {
    background-color: transparent !important;
    padding-inline: 0 !important;
    border-radius: 0 !important;
    border-bottom: 1px solid var(--mc-border-subtle);
}

.bg-light:has(i):has(h6):last-child { border-bottom: 0; }

/* Checklist rows (`list-group-item ... bg-light rounded mb-2` wrapping an icon
   and a line of text) are the same chip-stack pattern without a heading, so
   they need their own match. */
.list-group-item.bg-light:has(i) {
    background-color: transparent !important;
    padding-inline: 0 !important;
    margin-bottom: 0 !important;
    border-radius: 0 !important;
    border-bottom: 1px solid var(--mc-border-subtle) !important;
}

.list-group-item.bg-light:has(i):last-child { border-bottom: 0 !important; }

/*
 * Friend rows carry `list-group-item ... shadow-sm mb-2 rounded`, i.e. a card
 * per person. Same treatment as the tee-time list: rules and rhythm rather than
 * a box each.
 */
.friend-item {
    border-radius: 0 !important;
    box-shadow: none !important;
    margin-bottom: 0 !important;
    padding-inline: 0;
    border-bottom: 1px solid var(--mc-border-subtle) !important;
}

.friend-item:last-child { border-bottom: 0 !important; }

/* Favorite state was a 5px amber slab plus a gray fill. It becomes a thin
   accent rule - the filled star in the row already states the state, so this
   is reinforcement, not the only signal. */
.friend-item.is-favorite {
    background-color: transparent !important;
    border-left: 2px solid var(--mc-accent) !important;
    padding-left: var(--mc-space-4);
}

/* ==========================================================================
   16c. Heading level vs heading size
   ==========================================================================
 * A heading's LEVEL describes document structure; its SIZE belongs to the
 * component it sits in. Correcting the document outline (so screen-reader users
 * get a real heading tree) moved many headings to h2/h3 - and any heading with
 * no component class then fell back to element sizing, which is display scale.
 * A person's name in a list row is legitimately an h3, but it is not 24px type.
 *
 * These rules give unclassed headings inside content containers a content-scale
 * size, so levels can be corrected freely without changing how anything looks.
 */
.card-body h2:not([class*="mc-"]):not(.card-title):not(.modal-title):not(.alert-heading),
.mc-panel h2:not([class*="mc-"]):not(.card-title):not(.alert-heading) {
    font-size: var(--mc-text-lg);
}

.card-body :is(h3, h4, h5, h6):not([class*="mc-"]):not(.card-title):not(.modal-title),
.mc-panel :is(h3, h4, h5, h6):not([class*="mc-"]):not(.card-title) {
    font-size: var(--mc-text-md);
}

/* A person's name heading a list row. */
.friend-name { font-size: var(--mc-text-md); font-weight: var(--mc-weight-semibold); }

/* Bare headings on the analysis pages sit directly in the page, not in a panel. */
.mc-main > div > h2:not([class]) { font-size: var(--mc-text-lg); }
.mc-main > div > h3:not([class]) { font-size: var(--mc-text-md); }

/* ==========================================================================
   17. Utilities & legacy shims
   ========================================================================== */

/* Bootstrap background utilities resolve to fixed colors that survive into dark
   mode as light patches. Re-point the ones the templates actually use. */
.bg-white, .bg-body { background-color: var(--mc-surface) !important; }
.bg-light { background-color: var(--mc-surface-sunken) !important; }
.bg-dark { background-color: var(--mc-surface-inverse) !important; color: var(--mc-text-inverse) !important; }
.border { border-color: var(--mc-border) !important; }
.border-top, .border-bottom, .border-start, .border-end { border-color: var(--mc-border) !important; }

/* Width containers. .mc-main already supplies the page gutter and max width, so
   pages must never nest a Bootstrap .container inside it - that double-pads on
   mobile, where the gutter is already tight. These constrain measure instead. */
.mc-narrow { max-width: 640px; margin-inline: auto; }
.mc-reading { max-width: 72ch; margin-inline: auto; }
.mc-reading p { line-height: var(--mc-leading-relaxed); }
.mc-reading h2 { margin-top: var(--mc-space-8); }

.mc-stack > * + * { margin-top: var(--mc-space-4); }
.mc-cluster { display: flex; flex-wrap: wrap; align-items: center; gap: var(--mc-space-2); }
.mc-truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.mc-divider {
    height: 1px;
    margin-block: var(--mc-space-5);
    background-color: var(--mc-border);
    border: 0;
}

.mc-visually-hidden {
    position: absolute !important;
    width: 1px; height: 1px;
    padding: 0; margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
        scroll-behavior: auto !important;
    }

    .hover-shadow:hover,
    .mc-entity__link:hover,
    .btn:active { transform: none; }
}
/* End AI-Generated */

/* AI-Generated */
/*
 * Roster
 *
 * The answer to "who is actually coming?" on the two pages that exist to give
 * it. Deliberately not a card: the roster is the page's content, not a boxed
 * aside, so it sits in the flow with the meter as its only ornament.
 *
 * Every row states its status in words. The colour on .mc-roster__state is a
 * second signal riding on top of a word that already says the same thing -
 * remove the colour and the roster still reads correctly, which is the test.
 */
.mc-roster {
    /* The meter's white-alpha track is invisible here; give it real ink. */
    --mc-meter-track: var(--mc-gray-200);
    margin-bottom: var(--mc-space-8);
}

.mc-roster__head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--mc-space-3);
    margin-bottom: var(--mc-space-3);
}

.mc-roster__title {
    margin: 0;
    color: var(--mc-text);
    font-size: var(--mc-text-lg);
    font-weight: var(--mc-weight-semibold);
    letter-spacing: var(--mc-tracking-tight);
}

.mc-roster__meter { margin-bottom: var(--mc-space-2); }

.mc-roster__summary {
    margin: 0 0 var(--mc-space-5);
    color: var(--mc-text-muted);
    font-size: var(--mc-text-md);
}

.mc-roster__summary strong {
    color: var(--mc-text);
    font-weight: var(--mc-weight-semibold);
}

.mc-roster__list {
    margin: 0;
    padding: 0;
    list-style: none;
    border-top: 1px solid var(--mc-border-subtle);
}

/*
 * Rows are separated by a rule rather than by gaps between cards. Four people
 * in four floating boxes reads as four unrelated things; a single list reads as
 * one group, which is what a foursome is.
 */
.mc-roster__row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--mc-space-3);
    min-height: var(--mc-touch-min);
    padding: var(--mc-space-3) 0;
    border-bottom: 1px solid var(--mc-border-subtle);
}

.mc-roster__row--out { opacity: 0.72; }

.mc-roster__person {
    display: flex;
    min-width: 0;
    flex-direction: column;
    gap: 2px;
}

.mc-roster__name {
    color: var(--mc-text);
    font-size: var(--mc-text-md);
    font-weight: var(--mc-weight-medium);
    overflow-wrap: anywhere;
}

.mc-roster__note {
    color: var(--mc-text-muted);
    font-size: var(--mc-text-sm);
}

.mc-roster__state {
    flex: none;
    padding: var(--mc-space-1) var(--mc-space-3);
    border-radius: var(--mc-radius-pill);
    background-color: var(--mc-gray-100);
    color: var(--mc-text-muted);
    font-size: var(--mc-text-sm);
    font-weight: var(--mc-weight-medium);
    white-space: nowrap;
}

.mc-roster__state--in {
    background-color: var(--mc-success-soft);
    color: var(--mc-success-soft-text);
}

.mc-roster__state--held {
    background-color: var(--mc-info-soft);
    color: var(--mc-info-soft-text);
}

.mc-roster__state--waiting {
    background-color: var(--mc-warning-soft);
    color: var(--mc-warning-soft-text);
}

/* Declined is the one state that stays neutral. Red would read as an error,
   and "can't make it" is a normal, valid answer to an invitation. */
.mc-roster__state--out {
    background-color: var(--mc-gray-100);
    color: var(--mc-text-muted);
}

/* Under ~380px the state pill and a long email cannot share a line without one
   of them truncating, so the pill drops beneath the name instead. */
@media (max-width: 380px) {
    .mc-roster__row {
        align-items: flex-start;
        flex-direction: column;
        gap: var(--mc-space-2);
    }
}
/* End AI-Generated */

/* AI-Generated */
/*
 * Plain list. A list of facts that are not links and not actions - so no
 * bullets, no icons, and no status chips. Grouping under a heading carries the
 * meaning that a green check and a red cross were carrying before, which means
 * it still reads correctly aloud and in one colour.
 */
.mc-plain-list {
    margin: 0;
    padding: 0;
    list-style: none;
}

.mc-plain-list li {
    padding: var(--mc-space-2) 0;
    border-bottom: 1px solid var(--mc-border-subtle);
    color: var(--mc-text);
}

.mc-plain-list li:last-child { border-bottom: 0; }
/* End AI-Generated */

/* AI-Generated */
/*
 * Comparison delta. The number already sits in a text-success / text-danger
 * cell; this is the same fact in a word, so the table still reads correctly to
 * someone who cannot separate the two colours, or is reading it aloud.
 * It inherits colour from the cell rather than setting its own.
 */
.mc-delta {
    font-size: var(--mc-text-sm);
    font-weight: var(--mc-weight-medium);
    text-transform: lowercase;
}
/* End AI-Generated */

/* AI-Generated */
/*
 * Invitation response. The one decision the whole product exists to collect,
 * usually taken one-handed on a phone at a course.
 *
 * Side by side down to 480px, then stacked - two btn-lg buttons in a row at
 * 360px either squeeze their labels or push the row wider than the viewport.
 * Stacking also separates them: adjacent large targets in the thumb zone are
 * exactly where a mis-tap sends the wrong answer to the organizer.
 */
.mc-response {
    display: flex;
    justify-content: center;
    gap: var(--mc-space-3);
}

.mc-response .btn { min-height: var(--mc-touch-comfortable); }

@media (max-width: 480px) {
    .mc-response { flex-direction: column; }
    /* Full width once stacked, so neither answer looks like the lesser option
       by being narrower than the other. */
    .mc-response .btn { width: 100%; }
}
/* End AI-Generated */

/* AI-Generated */
/*
 * Address book. Lifted from the last inline <style> block in the template tree;
 * the gap and margin were raw values, so they now take spacing steps.
 */
.tag-selection-container {
    max-height: 150px;
    overflow-y: auto;
    border: 1px solid var(--mc-border);
    border-radius: var(--mc-radius-md);
    padding: var(--mc-space-3);
    background-color: var(--mc-surface);
}

.form-check-inline {
    margin-right: var(--mc-space-2);
    margin-bottom: var(--mc-space-2);
}

/* Keeps the row's edit and delete buttons side by side. */
.contact-row td.d-flex { gap: var(--mc-space-2); }
/* End AI-Generated */

/* AI-Generated */
/*
 * Compact Google button. Google's brand terms fix the button's construction, so
 * only its scale is adjusted here - previously done with inline height and
 * font-size attributes repeated at each call site.
 */
.gsi-material-button--compact {
    height: 32px;
    font-size: var(--mc-text-sm);
}

.gsi-material-button--compact .gsi-material-button-icon {
    height: 16px;
    width: 16px;
}

/* A colour picker beside a text input: it should take only the width its
   longest option needs, not an equal share of the input group. */
.mc-select--narrow { max-width: 8rem; }
/* End AI-Generated */

/* AI-Generated */
/*
 * Thin progress bar. Bootstrap's .progress is 1rem tall, which reads as a
 * component; at this weight it reads as a measure of something, which is what
 * profile completion is. Was an inline height on the element.
 */
.mc-progress--thin { height: 10px; }

/*
 * Scrollable option list inside a form - friends, contacts and tags. The height
 * was set inline at five separate call sites, so the lists could drift apart.
 * This is a cap, not a fixed height: a short list still takes only its own room.
 */
.mc-scroll-list {
    max-height: 200px;
    overflow-y: auto;
}
/* End AI-Generated */
