/* Winston's management portal -- modern financial/operational theme.
   Global stylesheet, always loaded (see base.html). Page-family modules
   (appointments.css, schedule.css, dev_menu.css) build on these tokens
   and shared primitives; they do not redefine :root. */

:root {
    /* Primary/operational */
    --wb-primary: #1D4ED8;
    --wb-primary-hover: #1E40AF;
    --wb-primary-tint: #EFF6FF;
    --wb-secondary: #475569;
    --wb-secondary-hover: #334155;

    /* Semantic status -- used by meaning, not decoratively */
    --wb-success: #15803D;
    --wb-success-tint: #F0FDF4;
    --wb-warning: #B45309;
    --wb-warning-tint: #FFFBEB;
    --wb-danger: #B91C1C;
    --wb-danger-tint: #FEF2F2;
    --wb-purple: #6D28D9;
    --wb-purple-tint: #F5F3FF;
    --wb-teal: #0F766E;
    --wb-teal-tint: #F0FDFA;

    /* Navigation shell */
    --wb-nav-bg: #0F172A;
    --wb-nav-bg-active: #1E293B;
    --wb-nav-text: #CBD5E1;
    --wb-nav-text-active: #FFFFFF;
    --wb-nav-accent: var(--wb-primary);

    /* Subtle brand reference only -- sidebar brand lockup, nowhere else.
       Admin-overridable via BusinessSettings.primary_colour/secondary_colour
       (see base.html's inline style on <body>). */
    --wb-brand-accent: #6b1220;
    --wb-brand-accent-secondary: #b8925a;

    /* Card-header dark-navy background -- a gradient, deliberately lighter/
       more blue than --wb-nav-bg (the sidebar's near-black #0F172A) so the
       card header itself reads as "deep navy," not "near black." Its own
       dedicated tokens rather than reusing --wb-nav-bg, so this can keep
       evolving independently of the sidebar. */
    --wb-card-header-bg-start: #1E3A66;
    --wb-card-header-bg-end: #16294A;

    /* Card-header module accents -- see .wb-card-header--* below. Fixed,
       NOT admin-overridable (unlike --wb-brand-accent above): a module's
       colour-coding needs to stay stable regardless of what a given shop
       sets as its own brand colour, so these are separate tokens even
       where the default happens to match (employees/finance). Each module
       now has two shades -- the *-border one keeps the originally-named
       colour (used for the thin left border only) and the *-icon one is a
       lighter tint of the same hue, specifically for keeping the icon
       glyph clearly visible against the dark-navy header background;
       dedicated, standalone values throughout (no longer aliased to
       --wb-teal/--wb-secondary), so a future change to those tokens'
       other uses (dashboard stat cards, secondary buttons) never
       accidentally shifts a module's card-header colour too. */
    --wb-module-appointments-border: #5B7FA6;
    --wb-module-appointments-icon: #9CC2EE;
    --wb-module-pos-border: #0F766E;
    --wb-module-pos-icon: #4DD0C4;
    --wb-module-inventory-border: #1E5631;
    --wb-module-inventory-icon: #5FA876;
    --wb-module-employees-border: #6b1220;
    --wb-module-employees-icon: #C15C74;
    --wb-module-finance-border: #b8925a;
    --wb-module-finance-icon: #D9B77E;
    --wb-module-reports-border: #475569;
    --wb-module-reports-icon: #A8B5C4;
    --wb-module-settings-border: #334155;
    --wb-module-settings-icon: #8C9BAF;

    /* BAT-016: standard helper/instructional text colour -- Winston slate
       blue-grey, reused everywhere via .wb-appt-form__help/.wb-help-text
       (see appointments.css). Deliberately darker than the ticket's first
       suggestion (#66788A, ~4.5:1 against white -- right at the WCAG AA
       floor for normal-size text) since this text also renders italic and
       small; #596B7D gives a safer contrast margin. */
    --wb-help-text: #596B7D;

    /* Neutral surfaces */
    --wb-ink: #0F172A;
    --wb-ink-muted: #475569;
    --wb-ink-faint: #94A3B8;
    --wb-surface: #FFFFFF;
    --wb-surface-alt: #F8FAFC;
    --wb-border: #E2E8F0;
    --wb-border-strong: #CBD5E1;

    --wb-sidebar-width: 260px;
    --wb-topbar-height: 60px;
    --wb-radius: 8px;
    --wb-shadow: 0 1px 3px rgba(15, 23, 42, 0.08), 0 1px 2px rgba(15, 23, 42, 0.06);
    --wb-shadow-raised: 0 4px 12px rgba(15, 23, 42, 0.12);
}

* {
    box-sizing: border-box;
}

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

body {
    margin: 0;
    min-height: 100vh;
    display: flex;
    background-color: var(--wb-surface-alt);
    color: var(--wb-ink);
    font-family: "Inter", "IBM Plex Sans", system-ui, -apple-system, "Segoe UI", sans-serif;
    -webkit-font-smoothing: antialiased;
}

.wb-skip-link {
    position: absolute;
    left: -9999px;
    top: 0;
    z-index: 1000;
    background-color: var(--wb-primary);
    color: #fff;
    padding: 0.6rem 1rem;
    border-radius: 0 0 4px 0;
}

.wb-skip-link:focus {
    left: 0;
}

/* ---------- Sidebar ---------- */

.wb-sidebar {
    position: fixed;
    inset: 0 auto 0 0;
    width: var(--wb-sidebar-width);
    background-color: var(--wb-nav-bg);
    color: var(--wb-nav-text);
    display: flex;
    flex-direction: column;
    overflow-y: auto;
    z-index: 40;
    transform: translateX(-100%);
    transition: transform 0.2s ease;
}

.wb-sidebar.wb-nav--open {
    transform: translateX(0);
    box-shadow: var(--wb-shadow-raised);
}

.wb-sidebar__brand {
    display: flex;
    align-items: center;
    gap: 0.65rem;
    padding: 1.1rem 1.25rem;
    border-bottom: 1px solid rgba(255, 255, 255, 0.08);
}

.wb-sidebar__brand-mark {
    width: 10px;
    height: 28px;
    border-radius: 2px;
    background: linear-gradient(180deg, var(--wb-brand-accent), var(--wb-brand-accent-secondary));
    flex-shrink: 0;
}

.wb-sidebar__brand-name {
    display: block;
    color: #fff;
    font-weight: 700;
    font-size: 1rem;
    line-height: 1.2;
}

.wb-sidebar__brand-tagline {
    display: block;
    font-size: 0.72rem;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--wb-nav-text);
    opacity: 0.7;
}

.wb-sidebar__nav {
    padding: 0.75rem 0.75rem 1.5rem;
}

.wb-sidebar__section {
    margin-bottom: 1.1rem;
}

.wb-sidebar__section-label {
    display: block;
    padding: 0 0.6rem;
    margin-bottom: 0.35rem;
    font-size: 0.7rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--wb-ink-faint);
}

.wb-sidebar__list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 0.1rem;
}

.wb-nav__link {
    display: flex;
    align-items: center;
    gap: 0.65rem;
    padding: 0.5rem 0.6rem;
    border-radius: 6px;
    color: var(--wb-nav-text);
    text-decoration: none;
    font-size: 0.9rem;
    font-weight: 500;
    border-left: 3px solid transparent;
    transition: background-color 0.12s ease, color 0.12s ease;
}

.wb-nav__link:hover {
    background-color: var(--wb-nav-bg-active);
    color: var(--wb-nav-text-active);
}

.wb-nav__link--active {
    background-color: var(--wb-nav-bg-active);
    color: var(--wb-nav-text-active);
    border-left-color: var(--wb-nav-accent);
    font-weight: 600;
}

.wb-nav__link--soon {
    opacity: 0.55;
    cursor: default;
    pointer-events: none;
}

.wb-nav__link-icon {
    font-size: 1rem;
    width: 1.1rem;
    text-align: center;
    flex-shrink: 0;
}

.wb-nav__link-text {
    flex: 1;
}

.wb-nav__soon-pill {
    font-size: 0.65rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    background-color: rgba(255, 255, 255, 0.12);
    color: var(--wb-nav-text);
    padding: 0.1rem 0.4rem;
    border-radius: 999px;
}

.wb-nav__link:focus-visible {
    outline: 2px solid #fff;
    outline-offset: -2px;
}

/* ---------- Topbar & shell ---------- */

.wb-shell__main {
    flex: 1;
    display: flex;
    flex-direction: column;
    min-width: 0;
}

body > .wb-main {
    /* Unauthenticated pages (login) render <main> directly under <body>,
       with no sidebar/topbar -- still needs to fill the flex row. */
    flex: 1;
}

.wb-topbar {
    position: sticky;
    top: 0;
    z-index: 30;
    display: flex;
    align-items: center;
    gap: 1rem;
    height: var(--wb-topbar-height);
    padding: 0 1.5rem;
    background-color: var(--wb-surface);
    border-bottom: 1px solid var(--wb-border);
}

.wb-topbar__title {
    font-weight: 600;
    font-size: 0.95rem;
    color: var(--wb-ink);
}

.wb-topbar__spacer {
    flex: 1;
}

.wb-topbar__user {
    font-size: 0.85rem;
    color: var(--wb-ink-muted);
}

.wb-nav__toggle {
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: 4px;
    background: none;
    border: 1px solid var(--wb-border-strong);
    border-radius: 6px;
    padding: 0.45rem 0.6rem;
    cursor: pointer;
}

.wb-nav__toggle-bar {
    width: 18px;
    height: 2px;
    background-color: var(--wb-ink);
}

.wb-nav__toggle-label {
    display: none;
}

.wb-nav__toggle:focus-visible {
    outline: 2px solid var(--wb-primary);
    outline-offset: 2px;
}

.wb-nav__logout {
    margin: 0;
}

.wb-nav__logout-btn {
    background: none;
    border: 1px solid var(--wb-border-strong);
    color: var(--wb-ink);
    padding: 0.4rem 0.85rem;
    border-radius: 6px;
    cursor: pointer;
    font-size: 0.82rem;
    font-family: inherit;
    transition: background-color 0.12s ease, border-color 0.12s ease;
}

.wb-nav__logout-btn:hover {
    background-color: var(--wb-surface-alt);
    border-color: var(--wb-ink-muted);
}

.wb-nav__logout-btn:focus-visible,
.wb-nav__toggle:focus-visible {
    outline: 2px solid var(--wb-primary);
    outline-offset: 2px;
}

.wb-main {
    max-width: 1280px;
    width: 100%;
    margin: 0 auto;
    padding: 1.75rem 2rem 3rem;
}

@media (min-width: 992px) {
    .wb-sidebar {
        transform: none;
        box-shadow: none;
    }

    .wb-shell__main {
        margin-left: var(--wb-sidebar-width);
    }

    .wb-nav__toggle {
        display: none;
    }
}

/* ---------- Messages / alerts ---------- */

.wb-messages {
    list-style: none;
    margin: 0 0 1.5rem;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}

.wb-messages__item {
    background-color: var(--wb-surface);
    border: 1px solid var(--wb-border);
    border-left: 4px solid var(--wb-primary);
    border-radius: var(--wb-radius);
    padding: 0.65rem 1rem;
    font-size: 0.9rem;
}

.wb-messages__item--success {
    border-left-color: var(--wb-success);
}

.wb-messages__item--warning {
    border-left-color: var(--wb-warning);
}

.wb-messages__item--error {
    border-left-color: var(--wb-danger);
}

/* ---------- Page heading ---------- */

.wb-dashboard__heading {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 0.5rem;
    border-bottom: 1px solid var(--wb-border);
    padding-bottom: 0.9rem;
    margin-bottom: 1.5rem;
}

.wb-dashboard__heading h2 {
    margin: 0;
    color: var(--wb-ink);
    font-weight: 700;
}

.wb-dashboard__date {
    color: var(--wb-ink-muted);
    font-size: 0.9rem;
}

/* ---------- Detail-page section jump-nav ---------- */

.wb-detail-jumpnav {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    position: sticky;
    top: calc(var(--wb-topbar-height) + 0.75rem);
    z-index: 10;
    background-color: var(--wb-surface-alt);
    padding: 0.5rem 0;
    margin-bottom: 1.25rem;
}

.wb-detail-jumpnav a {
    padding: 0.35rem 0.85rem;
    border-radius: 999px;
    border: 1px solid var(--wb-border-strong);
    background-color: var(--wb-surface);
    color: var(--wb-ink-muted);
    font-size: 0.82rem;
    font-weight: 600;
    text-decoration: none;
    transition: background-color 0.12s ease, color 0.12s ease, border-color 0.12s ease;
}

.wb-detail-jumpnav a:hover {
    border-color: var(--wb-primary);
    color: var(--wb-primary);
}

.wb-detail-jumpnav a:focus-visible {
    outline: 2px solid var(--wb-primary);
    outline-offset: 2px;
}

/* ---------- Workspace tab strip (e.g. Schedules) ---------- */
/* Distinct from .wb-detail-jumpnav (same-page anchor jump) -- these are
   real links between separate routed pages, so the active tab needs a
   stronger, unambiguous treatment: a filled background rather than just
   a border/color change, matching the sidebar's own active-link style. */

.wb-tabs {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem;
    border-bottom: 1px solid var(--wb-border);
    padding-bottom: 0.75rem;
    margin-bottom: 1.5rem;
}

.wb-tabs__link {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    padding: 0.5rem 1rem;
    border-radius: 999px;
    color: var(--wb-ink-muted);
    font-size: 0.88rem;
    font-weight: 600;
    text-decoration: none;
    transition: background-color 0.12s ease, color 0.12s ease;
}

.wb-tabs__link:hover {
    background-color: var(--wb-primary-tint);
    color: var(--wb-primary);
}

.wb-tabs__link--active {
    background-color: var(--wb-primary);
    color: #fff;
}

.wb-tabs__link--active:hover {
    background-color: var(--wb-primary);
    color: #fff;
}

.wb-tabs__link:focus-visible {
    outline: 2px solid var(--wb-primary);
    outline-offset: 2px;
}

.wb-tabs__badge {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 1.3rem;
    height: 1.3rem;
    padding: 0 0.35rem;
    border-radius: 999px;
    background-color: var(--wb-danger);
    color: #fff;
    font-size: 0.7rem;
    font-weight: 700;
}

.wb-tabs__link--active .wb-tabs__badge {
    background-color: #fff;
    color: var(--wb-danger);
}

/* ---------- KPI stat cards ---------- */

.wb-stats {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: 1rem;
    margin-bottom: 2rem;
}

.wb-stat-card {
    background-color: var(--wb-surface);
    border: 1px solid var(--wb-border);
    border-radius: var(--wb-radius);
    box-shadow: var(--wb-shadow);
    padding: 1.1rem 1.25rem;
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
    position: relative;
    cursor: pointer;
    border-top: 3px solid var(--wb-primary);
    transition: transform 0.15s ease, box-shadow 0.15s ease;
}

.wb-stat-card:hover,
.wb-stat-card:focus-within {
    transform: translateY(-2px);
    box-shadow: var(--wb-shadow-raised);
}

.wb-stat-card--success { border-top-color: var(--wb-success); }
.wb-stat-card--warning { border-top-color: var(--wb-warning); }
.wb-stat-card--danger { border-top-color: var(--wb-danger); }
.wb-stat-card--purple { border-top-color: var(--wb-purple); }
.wb-stat-card--teal { border-top-color: var(--wb-teal); }

.wb-stat-card--alert {
    border-top-color: var(--wb-danger);
}

.wb-stat-card--static {
    cursor: default;
}

.wb-stat-card--static:hover,
.wb-stat-card--static:focus-within {
    transform: none;
    box-shadow: var(--wb-shadow);
}

.wb-stretched-link {
    color: inherit;
    text-decoration: none;
}

.wb-stretched-link::after {
    content: "";
    position: absolute;
    inset: 0;
    border-radius: var(--wb-radius);
}

.wb-stretched-link:hover .wb-stat-card__value {
    text-decoration: underline;
    text-decoration-color: var(--wb-border-strong);
}

.wb-stretched-link:focus-visible::after {
    outline: 2px solid var(--wb-primary);
    outline-offset: 2px;
}

.wb-stat-card__header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
}

.wb-stat-card__label {
    font-size: 0.78rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--wb-ink-muted);
}

.wb-stat-card__icon {
    font-size: 1.1rem;
    color: var(--wb-ink-faint);
}

.wb-stat-card__value {
    font-size: 1.85rem;
    font-weight: 700;
    color: var(--wb-ink);
    font-variant-numeric: tabular-nums;
    letter-spacing: -0.01em;
}

.wb-stat-card__sub {
    font-size: 0.8rem;
    color: var(--wb-ink-muted);
}

.wb-stat-card__trend {
    display: inline-flex;
    align-items: center;
    gap: 0.25rem;
    font-size: 0.78rem;
    font-weight: 600;
    width: fit-content;
}

.wb-stat-card__trend--up {
    color: var(--wb-success);
}

.wb-stat-card__trend--down {
    color: var(--wb-danger);
}

.wb-stat-card__trend--flat {
    color: var(--wb-ink-muted);
}

/* ---------- Panels ---------- */

.wb-panels {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(360px, 1fr));
    gap: 1.25rem;
    /* .wb-appt-detail__actions (often the element directly above this
       grid -- see dashboard.html/inventory_overview.html) only carries
       margin-top, not margin-bottom, so without this the action-button
       row and the first panel row would sit flush against each other.
       Ordinary margin collapsing means this has no effect where
       .wb-panels instead follows .wb-stats (margin-bottom: 2rem)
       directly -- the larger of the two collapsed margins still wins. */
    margin-top: 1.5rem;
}

.wb-panel {
    background-color: var(--wb-surface);
    border: 1px solid var(--wb-border);
    border-radius: var(--wb-radius);
    box-shadow: var(--wb-shadow);
    padding: 1.25rem 1.4rem;
}

.wb-panel__title {
    color: var(--wb-ink);
    font-weight: 700;
    font-size: 1rem;
    margin: 0 0 1rem;
    padding-bottom: 0.6rem;
    border-bottom: 1px solid var(--wb-border);
}

/* ---------- Card headers (Winston's card-header design system) ----------
   Opt-in only -- .wb-panel--headed zeroes out .wb-panel's own padding and
   lets .wb-card-header bleed edge-to-edge as a dark-navy band, with
   .wb-panel__body carrying the padding .wb-panel used to provide directly.
   Every other .wb-panel usage (dashboard, list pages, etc.) is completely
   unaffected since it doesn't add this modifier. See
   barbershop/templates/barbershop/_card_header.html for the reusable
   template partial that builds the header markup below, and docs/
   design-system/card-headers.md for the full module colour-map reference. */
.wb-panel--headed {
    padding: 0;
    overflow: hidden;
}

.wb-panel__body {
    padding: 1.25rem 1.4rem;
}

.wb-card-header {
    display: flex;
    align-items: center;
    gap: 0.65rem;
    background: linear-gradient(180deg, var(--wb-card-header-bg-start), var(--wb-card-header-bg-end));
    padding: 1rem 1.35rem;
}

.wb-card-header__icon {
    font-size: 1.35rem;
    line-height: 1;
    color: rgba(255, 255, 255, 0.9);
    flex-shrink: 0;
}

.wb-card-header__title {
    margin: 0;
    color: #fff;
    font-size: 1rem;
    font-weight: 700;
    line-height: 1.2;
}

/* A header nested inside another already-headed card (e.g. Selected
   Appointment inside the Availability aside) -- same colours, smaller
   scale, so two full-size navy bars don't stack directly on top of
   each other. */
.wb-card-header--compact {
    padding: 0.55rem 0.8rem;
}

.wb-card-header--compact .wb-card-header__icon {
    font-size: 0.9rem;
}

.wb-card-header--compact .wb-card-header__title {
    font-size: 0.85rem;
}

/* Module accents -- the *only* accent mechanism used, consistently, for
   every module: a thin left border (the originally-named colour) plus a
   lighter tint of that same hue on the icon, for contrast against the
   dark-navy header. Never a bright/saturated header background -- the
   dark navy above stays dominant everywhere. */
.wb-card-header--appointments { border-left: 3px solid var(--wb-module-appointments-border); }
.wb-card-header--appointments .wb-card-header__icon { color: var(--wb-module-appointments-icon); }

.wb-card-header--pos { border-left: 3px solid var(--wb-module-pos-border); }
.wb-card-header--pos .wb-card-header__icon { color: var(--wb-module-pos-icon); }

.wb-card-header--inventory { border-left: 3px solid var(--wb-module-inventory-border); }
.wb-card-header--inventory .wb-card-header__icon { color: var(--wb-module-inventory-icon); }

.wb-card-header--employees { border-left: 3px solid var(--wb-module-employees-border); }
.wb-card-header--employees .wb-card-header__icon { color: var(--wb-module-employees-icon); }

.wb-card-header--finance { border-left: 3px solid var(--wb-module-finance-border); }
.wb-card-header--finance .wb-card-header__icon { color: var(--wb-module-finance-icon); }

.wb-card-header--reports { border-left: 3px solid var(--wb-module-reports-border); }
.wb-card-header--reports .wb-card-header__icon { color: var(--wb-module-reports-icon); }

.wb-card-header--settings { border-left: 3px solid var(--wb-module-settings-border); }
.wb-card-header--settings .wb-card-header__icon { color: var(--wb-module-settings-icon); }

/* ---------- Tables ---------- */

.wb-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 0.88rem;
}

.wb-table th {
    text-align: left;
    text-transform: uppercase;
    font-size: 0.72rem;
    font-weight: 600;
    letter-spacing: 0.04em;
    color: var(--wb-ink-muted);
    padding: 0.55rem 0.6rem;
    border-bottom: 2px solid var(--wb-border-strong);
    background-color: var(--wb-surface-alt);
}

.wb-table td {
    padding: 0.55rem 0.6rem;
    border-bottom: 1px solid var(--wb-border);
    vertical-align: middle;
}

.wb-table tbody tr:nth-child(even) {
    background-color: var(--wb-surface-alt);
}

.wb-table tbody tr:last-child td {
    border-bottom: none;
}

.wb-table tbody tr:hover {
    background-color: var(--wb-primary-tint);
}

.wb-table-scroll {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
}

.wb-num {
    text-align: right;
    font-variant-numeric: tabular-nums;
}

/* Qualified with the `th` element to match/exceed .wb-table th's
   specificity -- that broader rule (text-align: left, for every other
   header) also matches a <th class="wb-num"> and was winning on
   specificity alone, which is what left numeric column headers
   left-aligned above right-aligned data instead of matching it. */
.wb-table th.wb-num {
    text-align: right;
}

.wb-amount {
    font-weight: 600;
    font-variant-numeric: tabular-nums;
}

.wb-amount--positive {
    color: var(--wb-success);
}

.wb-amount--negative {
    color: var(--wb-danger);
}

.wb-amount--muted {
    color: var(--wb-ink-muted);
    font-weight: 400;
}

.wb-amount--total {
    font-weight: 700;
    font-size: 1.05em;
}

.wb-row-link {
    color: var(--wb-primary);
    font-weight: 600;
    text-decoration: none;
    border-bottom: 1px dashed transparent;
}

.wb-row-link:hover {
    border-bottom-color: var(--wb-primary);
}

.wb-row-link:focus-visible {
    outline: 2px solid var(--wb-primary);
    outline-offset: 2px;
    border-radius: 2px;
}

/* ---------- Badges ---------- */

.wb-badge {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    background-color: var(--wb-ink-faint);
    color: #fff;
    /* BAT-016: several Purchase Order pages nest a badge directly inside
       .wb-appt-form__help/.wb-help-text ("Current status: <span
       class="wb-badge ...">") -- that class is now italic, and without
       this the badge's status text would inherit it. Explicit normal
       keeps status pills reading the same regardless of context. */
    font-style: normal;
    font-size: 0.72rem;
    font-weight: 600;
    padding: 0.2rem 0.55rem;
    border-radius: 999px;
    line-height: 1.4;
}

a.wb-badge:hover {
    opacity: 0.85;
}

a.wb-badge:focus-visible {
    outline: 2px solid var(--wb-ink);
    outline-offset: 2px;
}

.wb-badge--success { background-color: var(--wb-success); }
.wb-badge--warning { background-color: var(--wb-warning); }
.wb-badge--danger { background-color: var(--wb-danger); }
.wb-badge--primary { background-color: var(--wb-primary); }
.wb-badge--purple { background-color: var(--wb-purple); }
.wb-badge--teal { background-color: var(--wb-teal); }
.wb-badge--neutral {
    background-color: var(--wb-surface-alt);
    color: var(--wb-ink-muted);
    border: 1px solid var(--wb-border-strong);
}

/* Purchase Order status badges -- one class per PurchaseOrderStatus.code,
   mapped centrally in barbershop.purchasing.purchase_order_status_badge_class
   (Python) / the po_status_badge_class template filter (templates). Reuses
   the same semantic colour tokens as the generic .wb-badge--* modifiers
   above rather than introducing new hex values, so a status badge always
   reads consistently with the rest of the app's colour language. Every
   variant keeps solid-colour-plus-text (never colour alone) for contrast. */
.wb-badge--draft {
    background-color: var(--wb-surface-alt);
    color: var(--wb-ink-muted);
    border: 1px solid var(--wb-border-strong);
}
.wb-badge--submitted { background-color: var(--wb-primary); }
.wb-badge--partially-received { background-color: var(--wb-warning); }
.wb-badge--received { background-color: var(--wb-success); }
.wb-badge--cancelled { background-color: var(--wb-danger); }
/* Fallback for a status code with no specific mapping yet -- treated as
   still "open"/non-terminal rather than an error/unknown state. */
.wb-badge--open { background-color: var(--wb-primary); }

/* Administrative warning banner -- e.g. a missing Business Settings row
   (see barbershop.purchasing._get_configured_tax_rate's 0%-fallback
   warning on the Purchase Order detail page). Amber, not red: a
   safe-fallback notice, not a blocking error. */
.wb-admin-warning {
    background-color: var(--wb-warning-tint);
    border: 1px solid var(--wb-warning);
    border-radius: var(--wb-radius);
    padding: 0.75rem 1rem;
    margin-bottom: 1.25rem;
    color: var(--wb-ink);
}

/* ---------- Lists ---------- */

.wb-list {
    list-style: none;
    margin: 0;
    padding: 0;
}

.wb-list li {
    padding: 0.5rem 0;
    border-bottom: 1px solid var(--wb-border);
    display: flex;
    justify-content: space-between;
    gap: 0.5rem;
}

.wb-list li:last-child {
    border-bottom: none;
}

.wb-list__meta {
    color: var(--wb-ink-muted);
    font-size: 0.85rem;
}

.wb-empty {
    color: var(--wb-ink-muted);
    font-style: italic;
}

/* ---------- Pagination / search ---------- */

.wb-pagination {
    display: flex;
    align-items: center;
    gap: 1rem;
    margin-top: 1.25rem;
}

.wb-pagination__status {
    font-size: 0.85rem;
    color: var(--wb-ink-muted);
}

.wb-search-bar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.6rem;
    margin-bottom: 1.5rem;
}

.wb-search-bar input[type="text"],
.wb-search-bar input[type="date"],
.wb-search-bar select {
    padding: 0.5rem 0.65rem;
    border: 1px solid var(--wb-border-strong);
    border-radius: 6px;
    font-size: 0.88rem;
    background-color: #fff;
    color: var(--wb-ink);
    font-family: inherit;
}

.wb-search-bar input[type="text"]:focus-visible,
.wb-search-bar input[type="date"]:focus-visible,
.wb-search-bar select:focus-visible {
    outline: 2px solid var(--wb-primary);
    outline-offset: 1px;
    border-color: var(--wb-primary);
}

.wb-search-bar input[type="text"] {
    flex: 1 1 280px;
    min-width: 220px;
}

/* ---------- Buttons ---------- */

.wb-button {
    margin-top: 1rem;
    padding: 0.6rem 1.1rem;
    background-color: var(--wb-primary);
    color: #fff;
    border: none;
    border-radius: 6px;
    font-size: 0.92rem;
    font-weight: 600;
    font-family: inherit;
    text-decoration: none;
    cursor: pointer;
    transition: background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}

.wb-button:hover {
    background-color: var(--wb-primary-hover);
    text-decoration: none;
}

.wb-button:focus-visible {
    outline: 2px solid var(--wb-primary);
    outline-offset: 2px;
}

.wb-button:disabled {
    background-color: var(--wb-ink-faint);
    color: var(--wb-surface-alt);
    cursor: not-allowed;
}

/* A genuinely-disabled <button> paired with an inline explanation --
   e.g. Submit on a Purchase Order with no line items yet (see
   purchase_order_detail.html). Not a styled-to-look-disabled <a>; the
   button really can't be activated. */
.wb-appt-detail__disabled-action {
    display: inline-flex;
    align-items: center;
    gap: 0.6rem;
    flex-wrap: wrap;
}

.wb-appt-detail__disabled-action .wb-appt-form__help {
    margin-top: 0;
}

/* ---------- Auth form (login) ---------- */

.wb-auth {
    display: flex;
    justify-content: center;
    padding: 3rem 0;
}

.wb-auth__panel {
    width: 100%;
    max-width: 380px;
    background-color: var(--wb-surface);
    border: 1px solid var(--wb-border);
    border-radius: var(--wb-radius);
    box-shadow: var(--wb-shadow);
    padding: 2rem;
}

.wb-auth__error {
    color: var(--wb-danger);
    font-weight: 600;
    font-size: 0.9rem;
}

.wb-auth__form {
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
}

.wb-auth__form label {
    font-size: 0.82rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--wb-ink-muted);
    margin-top: 0.6rem;
}

.wb-auth__form input[type="text"],
.wb-auth__form input[type="password"] {
    padding: 0.55rem 0.65rem;
    border: 1px solid var(--wb-border-strong);
    border-radius: 6px;
    font-size: 1rem;
    background-color: #fff;
    color: var(--wb-ink);
    font-family: inherit;
}

.wb-auth__form input[type="text"]:focus-visible,
.wb-auth__form input[type="password"]:focus-visible {
    outline: 2px solid var(--wb-primary);
    outline-offset: 1px;
    border-color: var(--wb-primary);
}

/* ---------- Point of Sale workspace ----------
   Adaptive cashier layout modelled after a retail POS terminal (Square/
   Lightspeed/Clover-style), not a general CRUD/management page.

   Responsive priority (search always wins the most space): search field
   > search results > product/service selection > Current Sale summary
   > Current Sale detail > secondary (quick) actions.

   The DEFAULT (mobile-first-ish, but really "compact desktop and
   below") layout is a single column in exactly that priority order: a
   slim, sticky, always-visible Current Sale SUMMARY (name, status,
   item count, total -- "minimize customer information to only what is
   necessary during checkout"), an expandable Current Sale DETAIL (full
   item list/customer info/totals/pay button, a native <details>
   disclosure -- collapsed by default so it never competes with the
   search workspace for room), the search workspace itself, and finally
   the lowest-priority quick-actions column, now a full-width row.

   Only at a genuinely wide desktop breakpoint (see the min-width query
   below) does the layout switch to a fixed three-column grid with the
   cart permanently occupying the left column and force-expanded --
   because only there is there enough room for that without shrinking
   the search workspace or introducing horizontal scrolling. Reuses the
   app's existing tokens/badges/buttons throughout -- no new colours or
   typography are introduced here. */

/* The POS page needs more breathing room than the app's normal 1280px
   content cap (see .wb-main) to fit three real working columns on a
   1920x1080 monitor -- scoped to only the page that actually contains
   .wb-pos, so every other management page's width is unaffected. */
.wb-main:has(> .wb-pos) {
    max-width: 1600px;
}

.wb-pos-layout {
    display: flex;
    flex-direction: column;
    gap: 1.25rem;
}

/* Current Sale -- sticky so the compact summary (name/status/item
   count/total) never scrolls out of view while searching, at every
   width. Only the full detail below it collapses/expands. */
.wb-pos-cart {
    position: sticky;
    top: calc(var(--wb-topbar-height) + 0.5rem);
    z-index: 5;
}

.wb-pos-cart__summary {
    display: flex;
    flex-direction: column;
    gap: 0.3rem;
}

.wb-pos-cart__summary-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
}

.wb-pos-cart__summary-name {
    font-weight: 700;
    font-size: 1.05rem;
    color: var(--wb-ink);
}

/* JS-free disclosure for everything beyond the always-visible summary,
   built as a "checkbox hack" (a visually hidden, still-focusable
   checkbox + a <label> as the toggle + plain sibling-combinator CSS)
   rather than a native <details>/<summary>. A native <details> was
   tried first, force-opened via a CSS override at the wide-desktop
   breakpoint -- but browsers hide a closed <details>'s non-summary
   children through an internal mechanism that isn't reliably
   overridable by an ordinary author stylesheet rule, and in practice it
   wasn't overridden: the cart appeared to do nothing once an item was
   added (the empty-cart case defaults to open, which is why it looked
   fine until then). The checkbox hack has no such internal mechanism to
   fight -- show/hide is decided entirely by ordinary CSS specificity
   under our own control, so the wide-tier override is guaranteed to
   apply. Collapsed by default (unchecked) so the compact/adaptive
   layout doesn't cost the search workspace any space until the cashier
   actually wants the full cart; force-shown at the wide-desktop
   breakpoint below, where there's room for it to just read as a
   normal, always-open panel. */
.wb-pos-cart-toggle-checkbox {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

/* Styled as an unmistakable button (not just coloured text) -- this is
   the ONLY clickable control for showing/hiding the cart, and needs to
   read as clearly different from the adjacent .wb-badge status pill
   (e.g. "Open," the sale's status, not an action) so the two are never
   confused for each other. */
.wb-pos-cart-detail__toggle {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.4rem;
    cursor: pointer;
    font-weight: 600;
    font-size: 0.85rem;
    color: var(--wb-primary);
    margin-top: 0.5rem;
    padding: 0.5rem;
    border: 1px solid var(--wb-border-strong);
    border-radius: 6px;
    background-color: var(--wb-surface-alt);
}

.wb-pos-cart-detail__toggle:hover {
    background-color: var(--wb-primary-tint);
    border-color: var(--wb-primary);
}

.wb-pos-cart-toggle-checkbox:focus-visible ~ .wb-pos-cart-detail__toggle {
    outline: 2px solid var(--wb-primary);
    outline-offset: 2px;
}

.wb-pos-cart-detail__toggle-label-open {
    display: none;
}

.wb-pos-cart-toggle-checkbox:checked ~ .wb-pos-cart-detail__toggle .wb-pos-cart-detail__toggle-label-closed {
    display: none;
}

.wb-pos-cart-toggle-checkbox:checked ~ .wb-pos-cart-detail__toggle .wb-pos-cart-detail__toggle-label-open {
    display: inline;
}

.wb-pos-cart-detail__toggle-chevron {
    transition: transform 0.15s ease;
}

.wb-pos-cart-toggle-checkbox:checked ~ .wb-pos-cart-detail__toggle .wb-pos-cart-detail__toggle-chevron {
    transform: rotate(180deg);
}

.wb-pos-cart-detail__body {
    display: none;
    margin-top: 0.6rem;
}

.wb-pos-cart-toggle-checkbox:checked ~ .wb-pos-cart-detail__body {
    display: block;
}

.wb-pos-customer {
    margin-bottom: 1rem;
    padding-bottom: 0.85rem;
    border-bottom: 1px solid var(--wb-border);
}

.wb-pos-customer p {
    margin: 0.2rem 0;
}

.wb-pos-customer__meta {
    font-size: 0.82rem;
    color: var(--wb-ink-muted);
}

.wb-pos-customer__actions {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    margin-top: 0.5rem;
    flex-wrap: wrap;
}

/* <details>/<summary> -- a native, JS-free disclosure widget for
   "Change Customer": keyboard-accessible (Enter/Space toggles) with no
   custom script needed. */
.wb-pos-customer-change {
    width: 100%;
}

.wb-pos-customer-change summary {
    cursor: pointer;
    list-style: none;
}

.wb-pos-customer-change summary::-webkit-details-marker {
    display: none;
}

.wb-pos-customer-change[open] {
    margin-top: 0.5rem;
}

.wb-pos-customer-search-bar {
    margin: 0.5rem 0;
}

/* "A fixed-height scrollable list for sale items" -- capped regardless
   of breakpoint, so a long cart never pushes the totals/pay button off
   screen or grows the sticky panel past a sane size. */
.wb-pos-cart__items {
    max-height: 320px;
    overflow-y: auto;
    min-height: 2rem;
    margin-bottom: 0.25rem;
}

.wb-pos-cart-item {
    padding: 0.5rem 0;
    border-bottom: 1px solid var(--wb-border);
}

.wb-pos-cart-item:last-child {
    border-bottom: none;
}

.wb-pos-cart-item__row {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 0.5rem;
}

.wb-pos-cart-item__desc {
    font-weight: 600;
    color: var(--wb-ink);
}

.wb-pos-cart-item__remove {
    color: var(--wb-danger);
    font-size: 1.1rem;
    line-height: 1;
    padding: 0.1rem 0.3rem;
}

.wb-pos-cart-item__meta {
    font-size: 0.78rem;
    color: var(--wb-ink-muted);
    margin-top: 0.2rem;
}

.wb-pos-totals {
    margin-top: 0.75rem;
    padding-top: 0.75rem;
    border-top: 1px solid var(--wb-border);
    flex: 0 0 auto;
}

.wb-pos-totals p {
    display: flex;
    justify-content: space-between;
    gap: 1rem;
    margin: 0.25rem 0;
}

/* Visual hierarchy priority #1 (see the Phase spec) -- the total is the
   single most important number on this screen. */
.wb-pos-totals__grand {
    font-size: 1.2rem;
    font-weight: 700;
    padding-top: 0.4rem;
    border-top: 1px dashed var(--wb-border-strong);
}

/* Visual hierarchy priority #2 -- large, full-width, unmissable. Still
   just .wb-button under the hood (same colour/hover/disabled system),
   just bigger. */
.wb-pos-pay-button {
    display: block;
    width: 100%;
    margin-top: 0.85rem;
    padding: 0.85rem 1.1rem;
    font-size: 1.05rem;
    text-align: center;
}

.wb-pos-cart__note {
    margin-top: 0.5rem;
    font-size: 0.75rem;
    color: var(--wb-ink-faint);
    font-style: italic;
    text-align: center;
}

/* Center: search + tabs + results. */
.wb-pos-workspace {
    min-width: 0;
}

.wb-pos-universal-search {
    margin-bottom: 0.75rem;
}

.wb-pos-universal-search input[type="text"] {
    font-size: 1rem;
    padding: 0.65rem 0.85rem;
}

/* Tighter row padding than the standard .wb-table -- "compact,
   optimized for scanning" per the spec, for the two search-result
   tables specifically (every other .wb-table in the app is unaffected). */
.wb-table--compact th,
.wb-table--compact td {
    padding: 0.4rem 0.55rem;
    font-size: 0.85rem;
}

.wb-pos-employee-select {
    max-width: 9rem;
    padding: 0.35rem 0.5rem;
    border: 1px solid var(--wb-border-strong);
    border-radius: 6px;
    font-size: 0.82rem;
    font-family: inherit;
}

/* Quick actions -- lowest responsive priority (#6, "secondary
   actions"). In the default/compact layout this is a full-width row of
   sections that wraps as needed; only the wide-desktop tier below turns
   it into a single narrow right-hand column. */
.wb-pos-quick {
    display: flex;
    flex-direction: row;
    flex-wrap: wrap;
    gap: 1rem;
    min-width: 0;
}

.wb-pos-quick__section {
    padding: 1rem 1.1rem;
    flex: 1 1 260px;
}

.wb-pos-quick-services {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem;
}

.wb-pos-sale-actions {
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
    align-items: stretch;
}

.wb-pos-sale-actions .wb-btn-outline,
.wb-pos-sale-actions form {
    width: 100%;
}

.wb-pos-sale-actions button {
    width: 100%;
}

/* Wide desktop ONLY: enough real width (aligned with .wb-main's own
   1600px cap for this page) that a permanent three-column grid doesn't
   meaningfully reduce the search workspace, so this is the one tier
   where the Current Sale panel is allowed to occupy a fixed column
   instead of collapsing. Below this, the flex column layout declared
   above (search-first, cart summary + collapsible detail, quick
   actions last) is what applies -- "preserve the full search area as
   long as possible" as width decreases from here. */
@media (min-width: 1600px) {
    .wb-pos-layout {
        display: grid;
        grid-template-columns: 300px minmax(0, 1fr) 280px;
        gap: 1.25rem;
        align-items: start;
    }

    .wb-pos-cart {
        top: calc(var(--wb-topbar-height) + 1rem);
        max-height: calc(100vh - var(--wb-topbar-height) - 2rem);
        overflow-y: auto;
        display: flex;
        flex-direction: column;
    }

    /* Force the detail shown regardless of the checkbox's checked
       state -- at this width there's room for it to just read as a
       normal, always-visible panel (no click-to-expand needed), which
       is why the toggle (and its now-pointless checkbox) are hidden
       too. Ordinary author-rule specificity/source-order, so this
       reliably wins over the unchecked-by-default base rule above --
       no browser-internal visibility mechanism to fight, unlike the
       native <details> approach this replaced. */
    .wb-pos-cart-toggle-checkbox,
    .wb-pos-cart-detail__toggle {
        display: none;
    }

    .wb-pos-cart-detail__body {
        display: block;
    }

    .wb-pos-quick {
        flex-direction: column;
        flex-wrap: nowrap;
    }
}

@media (max-width: 560px) {
    .wb-pos-quick {
        flex-direction: column;
    }
}

/* ---------- Sale Detail (Phase 7) ---------- */

/* The actions row (Download PDF/Print Receipt/View Customer/Issue
   Refund) has no bottom margin of its own -- on every other page that
   uses .wb-appt-detail__actions it's the last thing on the page, so
   nothing was needed. Here it's immediately followed by the Sale
   Summary Card (.wb-stats), which likewise has no top margin (its own
   spacing convention puts the gap on whatever precedes it), so without
   this the two sit flush against each other. Scoped to this exact
   adjacency (not a blanket change to .wb-appt-detail__actions, which
   would affect every other detail page using it) via the sibling
   combinator -- no extra class needed in the template. */
.wb-appt-detail__actions + .wb-stats {
    margin-top: 1.5rem;
}

/* Six panels (Items/Financial Summary/Payments/Refund History/
   Timeline/Inventory) at the normal .wb-panels auto-fit width comfortably
   fit 3 per row on a wide desktop, which is exactly the "3 across"
   layout that risks individual cards (tables especially) getting
   squeezed and needing to scroll horizontally. Fixed at 2 columns (3
   rows of 6) instead, scoped to this page only -- every other page
   still uses .wb-panels' normal auto-fit sizing. minmax(0, ...) keeps
   a wide table from forcing its column past the available track width
   (barbershop.wb-table-scroll's own overflow-x handles it from there),
   the same technique already used for the POS workspace's center
   column. */
.wb-sale-panels {
    grid-template-columns: repeat(2, minmax(0, 1fr));
}

@media (max-width: 768px) {
    .wb-sale-panels {
        grid-template-columns: 1fr;
    }
}

/* The Payment Status summary-card value is text ("Partially Paid"),
   not a number -- .wb-stat-card__value's normal 1.85rem is sized for a
   short numeric figure and wraps awkwardly for a longer word, so this
   one card gets a smaller override. */
.wb-sale-summary__payment-status {
    font-size: 1.2rem;
}

/* Financial Summary panel -- deliberately just .wb-pos-totals (the
   same subtotal/tax/total block already used on the POS workspace and
   here previously inside the Items panel), now its own panel so it's
   visually separate from the line-item table per the Phase 7 spec.
   in a wb-panels grid it can end up narrower than its content wants;
   this keeps the numbers from starting flush against the panel edge. */
.wb-sale-financial-summary .wb-pos-totals {
    margin-top: 0;
}

.wb-sale-timeline li {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 0.5rem;
}

.wb-sale-timeline__label {
    font-weight: 600;
    color: var(--wb-ink);
}

.wb-sale-timeline__detail {
    color: var(--wb-ink-muted);
    font-size: 0.88rem;
}

/* A <button> that should read as an inline text link (e.g. "Select" /
   "Link" / "Unlink" next to a search result) rather than a boxed
   button -- reset the native button chrome, keep .wb-row-link's colour/
   weight/underline-on-hover behaviour. */
.wb-link-button {
    background: none;
    border: none;
    padding: 0;
    font: inherit;
    cursor: pointer;
}

/* A <form> that should sit inline with surrounding text/buttons rather
   than starting on its own line -- forms are block-level by default. */
.wb-inline-form {
    display: inline;
}

/* Same idea as .wb-inline-form, but for a form with more than one
   control (e.g. a quantity input plus its submit button) that still
   needs to read as one compact row, not stack vertically. */
.wb-inline-flex-form {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    flex-wrap: wrap;
}

/* A short numeric input (cart/product quantity) -- doesn't need a
   product form's full input width. */
.wb-input--qty {
    width: 4.5rem;
}

@media (max-width: 768px) {
    .wb-main {
        padding: 1.25rem 1rem 2rem;
    }

    .wb-topbar {
        padding: 0 1rem;
    }

    .wb-panels {
        grid-template-columns: 1fr;
    }
}
