/* Shared UI vocabulary — classes that more than one page speaks.
   tokens.css defines the values (colors, type, spacing); this file defines
   the recurring *patterns* built from them. Loads after tokens.css and
   BEFORE the component stylesheets, so a component can specialise a
   vocabulary class at equal specificity.

   The same adoption rule as tokens: a pattern moves here once a second
   page needs it, and component CSS keeps only what is specific to its
   page. No raw colors here either — scripts/checkDesignTokens.js checks
   this file with the component stylesheets. */

/* ── Page introduction ──────────────────────────────────────────────
   A single, quiet heading block for settings-style pages (Coaches, VIP).
   Legacy pages keep their own heading styles until they opt in. */
.page-intro {
    display: grid;
    gap: var(--space-2);
    margin: 0 0 var(--space-5);
}

.page-intro .page-title {
    margin: 0;
    font-size: var(--text-2xl);
    font-weight: 600;
    letter-spacing: var(--tracking-tight);
    line-height: var(--leading-tight);
    color: var(--color-text);
}

.page-intro .page-description {
    max-width: 62ch;
    margin: 0;
    font-size: var(--text-base);
    font-weight: 400;
    line-height: var(--leading-body);
    color: var(--color-text-secondary);
}

/* ── Buttons ────────────────────────────────────────────────────────
   Three weights, one meaning each, so a button's colour tells the
   operator what kind of thing it does before they read the label. Works
   on a native <button> or on a PrimeVue <p-button>; both are covered.

   .bo-btn-primary    blue         The affirmative commit on this surface:
                                   Save, or the one Add that creates the
                                   record. At most one per surface.

   .bo-btn-secondary  transparent  Supporting actions that open, reveal or
                                   navigate rather than commit — "Add price
                                   tier" opens the dialog, it does not save
                                   anything yet.

   .bo-btn-decisive   black        The headline action of the surface — the
                                   one thing the page exists to let someone
                                   do. On Coaches that is "Mark settled", a
                                   statement that a coach has been paid; on
                                   Club Prices it is "Add price tier", which
                                   opens a dialog but is still what an
                                   operator came to the page for. One per
                                   page at most: its weight is the whole
                                   point, and it stops meaning anything if
                                   it is spent on ordinary saves.

   Quiet destructive actions are not a fourth weight: they stay PrimeVue's
   severity="danger" text, so Remove and Delete read as available without
   competing with the commit beside them. */
.bo-btn-primary,
.bo-btn-secondary,
.bo-btn-decisive,
.p-button.bo-btn-primary,
.p-button.bo-btn-secondary,
.p-button.bo-btn-decisive {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-2);
    min-height: 32px;
    padding: 6px 14px;
    border: 1px solid transparent;
    border-radius: var(--radius-sm);
    font: inherit;
    font-size: var(--text-md);
    font-weight: 500;
    line-height: 1.25;
    cursor: pointer;
    transition: background-color 0.14s ease, border-color 0.14s ease, color 0.14s ease;
}

.bo-btn-primary,
.p-button.bo-btn-primary {
    border-color: var(--color-primary);
    background: var(--color-primary);
    color: var(--color-on-primary);
}

.bo-btn-primary:not(:disabled):hover,
.p-button.bo-btn-primary:not(:disabled):hover {
    border-color: var(--color-primary-hover);
    background: var(--color-primary-hover);
}

.bo-btn-secondary,
.p-button.bo-btn-secondary {
    border-color: var(--color-border-strong);
    background: transparent;
    color: var(--color-text-secondary);
}

.bo-btn-secondary:not(:disabled):hover,
.p-button.bo-btn-secondary:not(:disabled):hover {
    border-color: var(--color-text-secondary);
    background: var(--color-surface-hover);
    color: var(--color-text);
}

.bo-btn-decisive,
.p-button.bo-btn-decisive {
    border-color: var(--color-text);
    background: var(--color-text);
    color: var(--color-on-primary);
}

.bo-btn-decisive:not(:disabled):hover,
.p-button.bo-btn-decisive:not(:disabled):hover {
    border-color: var(--color-text-secondary);
    background: var(--color-text-secondary);
}

.bo-btn-primary:disabled,
.bo-btn-secondary:disabled,
.bo-btn-decisive:disabled,
.p-button.bo-btn-primary:disabled,
.p-button.bo-btn-secondary:disabled,
.p-button.bo-btn-decisive:disabled {
    border-color: var(--color-border);
    background: var(--color-surface-hover);
    color: var(--color-text-tertiary);
    cursor: default;
}

/* ── Two-pane workspace ─────────────────────────────────────────────
   One bordered surface split by a single hairline: the narrow pane sets
   something up, the wide pane shows or writes the result. VIP (add a
   member / the member list) and Notifications (pick recipients / write
   the message) are the same shape, so it lives here.

   Usage: .bo-workspace on the p-card, .bo-workspace-grid inside it, and
   .bo-pane on each half — .bo-pane-divided on the second one to draw the
   rule. Below 768px the panes stack and the rule moves to the top edge,
   because a hairline between columns means nothing once there is one
   column. A page adds only what is specific to it: column widths that
   differ from the default, and the content inside. */
.bo-workspace.p-card {
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    box-shadow: none;
    /* The player/court search dropdowns overflow their pane. */
    overflow: visible;
}

.bo-workspace .p-card-body,
.bo-workspace .p-card-content {
    padding: 0;
}

.bo-workspace-grid {
    display: grid;
    grid-template-columns: minmax(260px, 320px) minmax(0, 1fr);
}

.bo-pane {
    min-width: 0;
    padding: var(--space-5);
}

.bo-pane-divided {
    border-left: 1px solid var(--color-border);
}

@media (max-width: 768px) {
    .bo-workspace-grid {
        grid-template-columns: 1fr;
    }

    .bo-pane-divided {
        border-top: 1px solid var(--color-border);
        border-left: 0;
    }
}

/* ── Data tables ────────────────────────────────────────────────────
   The house recipe for PrimeVue DataTables (coaches settlement + history,
   VIP members): uppercase micro-labels for headers, row rules only,
   first/last columns flush with the surface padding. A component
   stylesheet adds only what is specific to its table — the min-width for
   its column set and any per-column treatment. Horizontal scrolling comes
   from PrimeVue's own .p-datatable-table-container (overflow-x: auto by
   default), so none is declared here. */
.bo-table .p-datatable-table {
    width: 100%;
}

.bo-table .p-datatable-thead > tr > th {
    padding: 10px var(--space-3);
    border-width: 0 0 1px;
    border-color: var(--color-border-subtle);
    background: transparent;
    font-size: var(--text-xs);
    font-weight: 600;
    letter-spacing: 0.02em;
    color: var(--color-text-tertiary);
    text-transform: uppercase;
    white-space: nowrap;
}

.bo-table .p-datatable-tbody > tr > td {
    padding: 12px var(--space-3);
    border-width: 0 0 1px;
    border-color: var(--color-border-subtle);
    font-size: var(--text-md);
    vertical-align: middle;
}

/* A table ends quietly inside its card: the card's edge is the final rule,
   not a second, competing line. This is deliberately shared so every
   migrated table keeps the same compact, calm reading surface. */
.bo-table .p-datatable-tbody > tr:last-child > td {
    border-bottom-width: 0;
}

.bo-table .p-datatable-thead > tr > th:first-child,
.bo-table .p-datatable-tbody > tr > td:first-child {
    padding-left: 0;
}

.bo-table .p-datatable-thead > tr > th:last-child,
.bo-table .p-datatable-tbody > tr > td:last-child {
    padding-right: 0;
}

/* ── Sort controls ─────────────────────────────────────────────────
   A visible neutral indicator says a column can be sorted before the
   operator discovers it by accident. The active state is restrained: it
   makes the current order findable without turning table headings into a
   toolbar. Pages opt in with this class; static columns remain plain text. */
.bo-sort {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 0;
    border: 0;
    background: transparent;
    color: inherit;
    font: inherit;
    letter-spacing: inherit;
    text-transform: inherit;
    cursor: pointer;
    white-space: nowrap;
}

.bo-sort:hover,
.bo-sort:focus-visible,
.bo-sort.is-active {
    color: var(--color-text);
}

.bo-sort:focus-visible {
    outline: 2px solid var(--color-primary);
    outline-offset: 3px;
    border-radius: var(--radius-sm);
}

.bo-sort-icon {
    color: var(--color-text-tertiary);
    font-size: var(--text-xs);
    line-height: 1;
}

.bo-sort.is-active .bo-sort-icon {
    color: var(--color-primary);
}

/* ── Page tabs ─────────────────────────────────────────────────────
   Top-level navigation between the views of one page (VIP's membership
   types, Bookings' calendar and recurring series). Deliberately quieter
   than dialog tabs: no surface of its own, so the strip reads as a label
   row over the page rather than a second card stacked above the content.
   Promoted here 2026-08-29 when Bookings became the second page to need
   it — it was VIP's local .vip-tabs first. */
.bo-page-tabs .p-tablist,
.bo-page-tabs .p-tablist-tab-list,
.bo-page-tabs .p-tab {
    border-radius: 0;
    background: transparent;
}

.bo-page-tabs .p-tab {
    padding: var(--space-2) var(--space-3);
    font-size: var(--text-base);
    font-weight: 500;
}

/* Pages that carry their content in panels (VIP) get the gap; a page that
   uses the strip purely as navigation (Bookings) has no panels to space. */
.bo-page-tabs .p-tabpanels {
    padding: var(--space-6) 0 0;
    background: transparent;
}

.bo-page-tabs .p-tabpanel {
    padding: 0;
}

/* ── Dialog tabs ───────────────────────────────────────────────────
   Profile-style dialogs use tabs to separate distinct tasks without
   nesting another dialog or making the primary task an accordion. The
   square tab edge keeps the navigation structural rather than pill-like.
   Coaches and Players share this treatment; each supplies only its panel
   content. */
.bo-dialog-tabs .p-tablist-tab-list,
.bo-dialog-tabs .p-tab {
    border-radius: 0;
}

.bo-dialog-tabs .p-tabpanels {
    padding: var(--space-4) 0 0;
    background: transparent;
}

.bo-dialog-tabs .p-tabpanel {
    padding: 0;
}

/* PrimeVue's stock close icon is a square target. Dialogs are transient
   layers, so their dismissal control is intentionally softer and circular.
   This applies to every migrated page dialog, not only the Players editor. */
.p-dialog .p-dialog-header .p-dialog-header-close {
    width: 28px;
    height: 28px;
    min-width: 28px;
    min-height: 28px;
    padding: 0;
    border: 1px solid transparent;
    border-radius: var(--radius-full);
    background: transparent;
    color: var(--color-text-secondary);
}

.p-dialog .p-dialog-header .p-dialog-header-close:hover {
    background: var(--color-surface-hover);
    color: var(--color-text);
}

.p-dialog .p-dialog-header .p-dialog-header-close:focus-visible {
    outline: 2px solid var(--color-primary);
    outline-offset: 2px;
}
