/* ------------------------------------------------------------------
   Avacallix panel — shared element/class styles.

   All colour, blur and radius tokens come from theme.css, which is the
   single source of truth and carries three themes (blue / gold / lilac)
   switched by data-theme on <html>. Nothing here redefines a token: a
   literal colour in this file is a bug, because it would ignore the
   active theme.

   The login page is the visual reference — same glass, same input
   treatment, same radii — so every surface below matches it.
   ------------------------------------------------------------------ */

:root {
    /* Layout constants only — not colours, so they are theme-independent. */
    --sidebar-w: 232px;
    --nav-h: 58px;

    --shadow: 0 18px 50px rgba(0, 0, 0, 0.45);
    --shadow-lift: 0 26px 70px rgba(0, 0, 0, 0.55);

    /* Sunken surfaces (inputs, wells) derived from the theme's own glass, so
       they follow gold and lilac instead of staying navy. */
    --sunken: var(--glass-bg-soft);

    /* --- Aliases onto theme.css ---------------------------------------
       The page-scoped CSS files were written against these names. They are
       aliases, never new values: every one resolves to a theme token, so a
       component styled with --ink or --saffron still follows gold and lilac
       instead of hard-coding navy. New CSS should prefer the theme names.
       ------------------------------------------------------------------ */
    --ink: var(--text-main);
    --ink-muted: var(--text-dim);
    --ink-dim: var(--text-dim);
    --ink-faint: var(--text-faint);

    --accent: var(--text-dim);
    --accent2: var(--text-dim);
    --lajvard: var(--glass-bg);

    /* The highlight the eye hunts for: money, and today's bar. Amber in every
       theme on purpose — it has to out-shout the accent, and in the gold theme
       an accent-coloured highlight would vanish into the chrome. */
    --saffron: #E9A13B;
    --saffron-soft: #F2BE72;

    --glass-edge: var(--glass-border);
    --glass-edge-lit: var(--glass-border);
    --glass-strong: var(--glass-bg);
    --glow-soft: var(--accent-glow-soft);

    --r-sm: var(--radius-md);
    --r: var(--radius-lg);
    --r-xl: var(--radius-xl);

    /* Semantic stays semantic in every theme — a "paid" badge that turns gold
       in the gold theme communicates nothing. */
    --ok: #4ADE80;
    --warn: #FBBF24;
    --crit: #F87171;

    color-scheme: dark;
}

* { box-sizing: border-box; margin: 0; padding: 0; }

html, body { height: 100%; }

body {
    /* Vazirmatn carries Latin as well as Persian, so a later bilingual pass
       needs no font swap — and its Latin is a clean grotesque. */
    font-family: Vazirmatn, "Segoe UI", system-ui, sans-serif;
    background: var(--bg-gradient);
    background-attachment: fixed;
    color: var(--text-main);
    min-height: 100vh;
    overflow-x: hidden;
    -webkit-font-smoothing: antialiased;
}

/* Ambient: the login page's orbs + grid, so every screen shares one world.

   Two layers, not one, because they want opposite things. The grid must stay
   even edge to edge — it is a texture, and a texture that fades in the middle
   reads as a smudge. The orbs must NOT: left raw, the bottom one pools in the
   bottom-left corner and hazes it over. On a short view like the week grid that
   corner is directly behind the content, so it reads as fog rather than depth.

   The panel is not the login page. There a decorative wash sits behind ONE card
   and nothing has to be read through it; here it lies under a working calendar,
   so the wash defers to the content. */

/* The grid: flat, even, everywhere. */
body::before {
    content: "";
    position: fixed;
    inset: 0;
    z-index: 0;
    pointer-events: none;
    background:
        linear-gradient(var(--grid-line) 1px, transparent 1px),
        linear-gradient(90deg, var(--grid-line) 1px, transparent 1px);
    background-size: var(--grid-size) var(--grid-size), var(--grid-size) var(--grid-size);
}

/* The orbs: symmetrical, top-anchored, out of the working area.

   Both the same size and both --orb-1, mirrored across the page. They used to be
   different sizes AND different colours (a bright 520px blue right, a dimmer
   420px purple left) sitting in opposite corners — which is a diagonal wash: the
   page read dark on the left and lit on the right, and the calendar sat in the
   middle of it. Decoration must not imply a gradient across content that has
   none.

   Anchored at the top because that is where the page has no data: the header and
   the topbar. The calendar grows downward into the space below, so that is the
   space the wash stays out of. */
body::after {
    content: "";
    position: fixed;
    inset: 0;
    z-index: 0;
    pointer-events: none;
    background:
        radial-gradient(circle 460px at 100% -5%, var(--orb-1), transparent 68%),
        radial-gradient(circle 460px at 0% -5%, var(--orb-1), transparent 68%);
}

h1, h2, h3, h4 { font-weight: 700; text-wrap: balance; letter-spacing: -0.01em; }
a { color: inherit; text-decoration: none; }

/* Digits that stack in columns — prices, durations, times — must line up. */
.num, td, th,
input[type="number"], input[type="time"], input[type="date"], input[type="datetime-local"] {
    font-variant-numeric: tabular-nums;
}

/* ---------- Glass surfaces: the login card, everywhere ---------- */

.card {
    position: relative;
    background: var(--glass-bg);
    backdrop-filter: blur(var(--glass-blur)) saturate(140%);
    -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(140%);
    border: 1px solid var(--glass-border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow), 0 0 25px var(--accent-glow-soft);
    overflow: hidden;
}

/* The lit top edge — what sells glass as a pane rather than a rectangle. */
.card::before {
    content: "";
    position: absolute;
    inset: 0 0 auto 0;
    height: 1px;
    background: linear-gradient(90deg, transparent, var(--glass-border) 45%, transparent);
    pointer-events: none;
    z-index: 1;
}

.card-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    padding: 13px 18px;
    border-bottom: 1px solid var(--glass-border);
}

.card-title { font-size: 13.5px; font-weight: 700; color: var(--text-main); }
.card-body { padding: 16px 18px; }

.card-link { font-size: 11.5px; color: var(--text-dim); cursor: pointer; }
.card-link:hover { text-decoration: underline; }

/* ---------- Controls: the login page's inputs ---------- */

.field { display: flex; flex-direction: column; gap: 6px; }

.label { font-size: 12px; font-weight: 600; color: var(--text-dim); }

.input, .select, textarea.input {
    width: 100%;
    padding: 12px;
    font-family: inherit;
    font-size: 14px;
    color: var(--text-main);
    background: var(--sunken);
    border: 1px solid var(--glass-border);
    border-radius: var(--radius-md);
    outline: none;
    transition: border-color 0.25s, box-shadow 0.25s;
}

.input::placeholder { color: var(--text-faint); }

/* The login page's focus, exactly: lit edge + soft accent glow. */
.input:focus, .select:focus, textarea.input:focus {
    border-color: var(--text-dim);
    box-shadow: 0 0 12px var(--accent-glow-soft);
}

/* Keyboard focus stays visible — this keeps the panel usable without a mouse. */
:focus-visible { outline: 2px solid var(--text-dim); outline-offset: 2px; }

.select option { background: #13203A; color: var(--text-main); }

.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    padding: 9px 15px;
    font-family: inherit;
    font-size: 13px;
    font-weight: 600;
    color: var(--text-dim);
    background: var(--glass-bg-soft);
    border: 1px solid var(--glass-border);
    border-radius: var(--radius-md);
    cursor: pointer;
    white-space: nowrap;
    transition: 0.25s;
}

.btn:hover {
    background: var(--accent-glow-soft);
    color: var(--text-main);
}

.btn:disabled { opacity: 0.5; cursor: not-allowed; }

/* The login page's button: accent gradient, lifts on hover. */
.btn-primary {
    color: var(--accent-text-on-fill);
    background: var(--accent-gradient);
    border-color: transparent;
    box-shadow: 0 0 18px var(--accent-glow-soft);
}

.btn-primary:hover {
    color: var(--accent-text-on-fill);
    transform: translateY(-2px);
    box-shadow: 0 0 25px var(--accent-glow);
}

.btn-primary:active { transform: translateY(0); }

.btn-danger {
    color: var(--text-error);
    background: rgba(180, 55, 47, 0.2);
    border-color: rgba(255, 138, 138, 0.4);
}

.btn-danger:hover { background: rgba(180, 55, 47, 0.32); border-color: rgba(255, 138, 138, 0.6); }

.btn-ghost { background: transparent; border-color: transparent; }
.btn-ghost:hover { background: var(--accent-glow-soft); }

.btn-sm { padding: 5px 10px; font-size: 11.5px; }

/* ---------- Badges: state in form, not only colour ---------- */

.badge, .pill {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 3px 9px;
    font-size: 10.5px;
    font-weight: 700;
    border-radius: 20px;
    border: 1px solid transparent;
    white-space: nowrap;
}

/* Semantic colours stay semantic across themes: success is green in all three,
   because a "paid" badge that turns gold in the gold theme means nothing. */
.b-green, .pill-ok { color: #86EFAC; background: rgba(74, 222, 128, 0.14); border-color: rgba(74, 222, 128, 0.32); }
.b-yellow, .pill-warn { color: #FDE68A; background: rgba(251, 191, 36, 0.14); border-color: rgba(251, 191, 36, 0.32); }
.b-red, .pill-crit { color: var(--text-error); background: rgba(248, 113, 113, 0.14); border-color: rgba(248, 113, 113, 0.32); }
.b-blue { color: var(--text-dim); background: var(--accent-glow-soft); border-color: var(--glass-border); }
.b-grey, .pill-mute { color: var(--text-faint); background: var(--glass-bg-soft); border-color: var(--glass-border); }

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

.table-wrap { overflow-x: auto; }

.tbl, .table {
    width: 100%;
    border-collapse: collapse;
    font-size: 13px;
}

.tbl th, .table th {
    text-align: left;
    font-size: 10px;
    font-weight: 600;
    letter-spacing: 0.07em;
    text-transform: uppercase;
    color: var(--text-faint);
    padding: 10px 18px;
    border-bottom: 1px solid var(--glass-border);
    white-space: nowrap;
}

.tbl td, .table td {
    padding: 11px 18px;
    border-bottom: 1px solid var(--grid-line);
    color: var(--text-dim);
}

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

.tbl tbody tr, .table tbody tr { transition: background 0.15s; }
.tbl tbody tr:hover, .table tbody tr:hover { background: var(--accent-glow-soft); }

.tbl td:first-child, .table td:first-child { color: var(--text-main); font-weight: 600; }

/* Initials chip — cheaper than an avatar image and never 404s. */
.av {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 26px;
    height: 26px;
    margin-right: 9px;
    border-radius: 50%;
    background: var(--accent-gradient);
    color: var(--accent-text-on-fill);
    font-size: 10px;
    font-weight: 700;
    vertical-align: middle;
    box-shadow: 0 0 10px var(--accent-glow-soft);
}

/* ---------- Feedback ---------- */

.alert {
    padding: 10px 13px;
    border-radius: var(--radius-md);
    font-size: 13px;
    border: 1px solid transparent;
}

.alert-error { color: var(--text-error); background: rgba(180, 55, 47, 0.16); border-color: rgba(255, 138, 138, 0.4); }
.alert-ok { color: #86EFAC; background: rgba(74, 222, 128, 0.14); border-color: rgba(74, 222, 128, 0.32); }
/* Saffron warning — a lost slot race is a nudge, not an error. */
.alert-warn { color: #F5C97B; background: rgba(233, 161, 59, 0.14); border-color: rgba(233, 161, 59, 0.34); }

/* One-tap alternative slots offered after a lost booking race. */
.alt-slots { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 10px; }
.alt-btn { white-space: nowrap; }

/* Call-history pager. */
.pager { display: flex; align-items: center; gap: 14px; justify-content: center; padding: 14px 0 4px; }

/* Row-action cell: keep the confirm/decline buttons together, right-aligned. */
.row-actions-cell { display: flex; gap: 6px; justify-content: flex-end; white-space: nowrap; }

/* A note folded under its request row — quieter than a full row. */
.note-row td { padding-top: 0; border-top: none; font-size: 12px; }

.empty {
    padding: 40px 16px;
    text-align: center;
    color: var(--text-faint);
    font-size: 13px;
}

.muted { color: var(--text-dim); }

/* ------------------------------------------------------------------
   Admin area

   Shared across the admin pages (dashboard, tenants, detail) rather than
   scoped per page: CSS isolation would give each its own copy of these,
   free to drift. The admin rail itself is scoped to AdminLayout; these are
   the content-area classes several pages reuse.
   ------------------------------------------------------------------ */

.admin-head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 12px;
    flex-wrap: wrap;
    margin-bottom: 18px;
}

.admin-title { font-size: 18px; font-weight: 700; color: var(--text-main); }
.admin-sub { font-size: 12px; color: var(--text-dim); margin-top: 3px; }

.stat-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
    gap: 12px;
}

.stat {
    padding: 16px 18px;
    background: var(--glass-bg);
    border: 1px solid var(--glass-border);
    border-radius: var(--radius-lg);
    backdrop-filter: blur(14px) saturate(140%);
    -webkit-backdrop-filter: blur(14px) saturate(140%);
}

.stat-val { font-size: 26px; font-weight: 800; color: var(--text-main); line-height: 1; }
.stat-lbl { font-size: 11px; color: var(--text-dim); margin-top: 6px; }
.stat-note { font-size: 10px; color: var(--text-faint); margin-top: 2px; }

/* The billing red — usage past the plan cap, wherever it shows. */
.over-cap { color: #FCA5A5 !important; font-weight: 700; }

/* A suspended tenant's whole row recedes; the badge still says why. */
.row-suspended { opacity: 0.55; }

/* A whole tenant row is clickable. The pointer is the only affordance that says
   so, so it is not optional — without it the row looks like plain text and the
   name stays the only target anyone finds. */
.row-open { cursor: pointer; }

.t-name { color: var(--text-main); font-weight: 600; text-decoration: none; }
.t-name:hover { text-decoration: underline; }

/* Tenant detail: plan and modules side by side, stacking on narrow screens. */
.detail-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 14px;
}

.usage { margin-top: 12px; font-size: 12.5px; color: var(--text-dim); }

/* ---- Buying a phone number (admin) ----
   Set apart from the rest of the card because every button in here spends real
   money on the platform's Telnyx account. */
.buy-box {
    margin-top: 14px; padding: 12px;
    border-radius: var(--radius-md);
    background: var(--glass-bg-soft);
    border: 1px dashed var(--glass-border);
}
.buy-row { display: flex; gap: 8px; align-items: center; margin-bottom: 10px; }
.buy-ac { flex: 0 0 130px; }
.buy-country { flex: 0 0 140px; }

.num-list { list-style: none; margin: 10px 0 0; padding: 0; display: grid; gap: 6px; }
.num-row {
    display: flex; align-items: center; justify-content: space-between; gap: 10px;
    padding: 9px 11px; border-radius: var(--radius-md);
    background: var(--glass-bg);
    border: 1px solid var(--glass-border);
}
.num-val { font-weight: 700; font-size: 13.5px; font-variant-numeric: tabular-nums; }
.num-place { font-size: 11px; margin-top: 2px; }
.over-tag {
    margin-left: 8px;
    padding: 1px 8px;
    border-radius: 999px;
    font-size: 10px;
    font-weight: 700;
    color: #FCA5A5;
    background: rgba(180, 55, 47, 0.16);
    border: 1px solid rgba(248, 113, 113, 0.32);
}

.mod-list { display: flex; flex-direction: column; gap: 6px; }

.mod {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    padding: 9px 12px;
    border-radius: var(--radius-md);
    border: 1px solid var(--glass-border);
    background: var(--glass-bg-soft);
}

.mod-on { border-color: rgba(74, 222, 128, 0.32); background: rgba(74, 222, 128, 0.06); }
.mod-info { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.mod-name { font-size: 12.5px; font-weight: 600; color: var(--text-main); }
.mod-exp { font-size: 10.5px; }

@media (max-width: 720px) {
    .detail-grid { grid-template-columns: 1fr; }
}
.dim { color: var(--text-dim); }
.faint { color: var(--text-faint); }

.validation-message { color: var(--text-error); font-size: 12px; }

/* Blazor's own strips — restyled so an error doesn't break the visual world. */
#blazor-error-ui {
    display: none;
    position: fixed;
    inset: auto 0 0 0;
    z-index: 1000;
    padding: 10px 18px;
    background: #B4372F;
    color: #fff;
    font-size: 13px;
    box-shadow: 0 -4px 20px rgba(0, 0, 0, 0.4);
}

/* ------------------------------------------------------------------
   Service colours

   Shared rather than page-scoped: the same six classes dress the picker
   on Services, the dots in its table, and the blocks on the Schedule day
   grid. CSS isolation would make a scoped copy per page — three copies
   of one palette, free to drift apart.

   Each class only publishes three variables; what reads them lives with
   the component. That way a swatch, a 6px dot and a full appointment
   block all share one definition of "saffron" without agreeing on
   anything else.
   ------------------------------------------------------------------ */

.sw-lajvard     { --svc: var(--svc-lajvard);     --svc-dim: var(--svc-lajvard-dim);     --svc-lit: var(--svc-lajvard-lit); }
.sw-saffron     { --svc: var(--svc-saffron);     --svc-dim: var(--svc-saffron-dim);     --svc-lit: var(--svc-saffron-lit); }
.sw-pomegranate { --svc: var(--svc-pomegranate); --svc-dim: var(--svc-pomegranate-dim); --svc-lit: var(--svc-pomegranate-lit); }
.sw-pistachio   { --svc: var(--svc-pistachio);   --svc-dim: var(--svc-pistachio-dim);   --svc-lit: var(--svc-pistachio-lit); }
.sw-turquoise   { --svc: var(--svc-turquoise);   --svc-dim: var(--svc-turquoise-dim);   --svc-lit: var(--svc-turquoise-lit); }
.sw-plum        { --svc: var(--svc-plum);        --svc-dim: var(--svc-plum-dim);        --svc-lit: var(--svc-plum-lit); }

#blazor-error-ui .dismiss { cursor: pointer; float: right; font-weight: 700; }

.blazor-error-boundary {
    padding: 14px;
    background: #B4372F;
    color: #fff;
    border-radius: var(--radius-md);
}

.blazor-error-boundary::after { content: "An error has occurred."; }

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

/* ============================================================
   Staff self-service: sign-in, display pairing, and "my day".
   Global rather than scoped because the sign-in and pairing
   pages are two components sharing one look.
   ============================================================ */

.staff-auth {
    min-height: 100vh;
    display: grid;
    place-items: center;
    padding: 24px;
    background: radial-gradient(1200px 600px at 50% -10%, #1d3b70 0%, #0f1830 55%, #0b1020 100%);
}

.sa-card {
    width: 100%;
    max-width: 420px;
    padding: 32px 28px;
    border-radius: 18px;
    background: rgba(255, 255, 255, .04);
    border: 1px solid rgba(255, 255, 255, .09);
    backdrop-filter: blur(14px);
    box-shadow: 0 24px 60px rgba(0, 0, 0, .45);
    color: #eaf0fb;
}

.sa-logo { display: flex; align-items: center; gap: 12px; margin-bottom: 26px; }

.sa-logo-icon {
    width: 38px; height: 38px; border-radius: 11px; flex: 0 0 auto;
    background: linear-gradient(135deg, #23509B, #E9A13B);
}

.sa-logo-title { font-weight: 700; letter-spacing: .2px; }
.sa-logo-sub { font-size: 12px; opacity: .65; }

.sa-card h1 { font-size: 24px; margin: 0 0 8px; }
.sa-note { font-size: 14px; line-height: 1.55; opacity: .82; margin: 0 0 18px; }
.sa-note.faint { opacity: .55; }
.sa-card a { color: #9dc0ff; }

.sa-alt {
    margin-top: 22px; padding-top: 16px;
    border-top: 1px solid rgba(255, 255, 255, .08);
}

.sa-alert {
    padding: 11px 13px; margin-bottom: 16px; border-radius: 10px;
    font-size: 13px; line-height: 1.5; color: #ffd9d4;
    background: rgba(180, 55, 47, .18);
    border: 1px solid rgba(180, 55, 47, .45);
}

.sa-form { display: grid; gap: 12px; }

.sa-form input {
    width: 100%; padding: 13px 14px; font-size: 15px; color: #eaf0fb;
    border-radius: 11px;
    background: rgba(255, 255, 255, .06);
    border: 1px solid rgba(255, 255, 255, .14);
}

.sa-form input:focus {
    outline: none; border-color: #6f9bec;
    box-shadow: 0 0 0 3px rgba(35, 80, 155, .35);
}

/* Typed once, on a TV remote — big, spaced, unambiguous. */
.sa-code {
    text-transform: uppercase; letter-spacing: .38em; text-align: center;
    font-size: 26px !important; font-weight: 700; font-variant-numeric: tabular-nums;
}

.sa-form button {
    padding: 13px 16px; font-size: 15px; font-weight: 600; color: #fff;
    border: 0; border-radius: 11px; cursor: pointer;
    background: linear-gradient(135deg, #23509B, #2f6ac9);
}

.sa-form button:hover { filter: brightness(1.08); }

/* ---------- /my : one person's day ---------- */

.myday { max-width: 640px; margin: 0 auto; padding: 14px 16px 48px; }

/* Pinned while the cards scroll under it. Sticky rather than fixed so it still
   participates in layout — the list needs no magic top padding to clear it. */
.my-head {
    position: sticky; top: 0; z-index: 20;
    background: var(--bg-gradient);
    border-bottom: 1px solid var(--glass-border);
    backdrop-filter: blur(var(--glass-blur)) saturate(140%);
    -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(140%);
}

.my-head-inner {
    max-width: 640px; margin: 0 auto; padding: 12px 16px;
    display: flex; align-items: center; justify-content: space-between; gap: 12px;
}

.my-head-id { min-width: 0; }
.my-hello {
    font-size: 18px; font-weight: 800; line-height: 1.2;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.my-date {
    font-size: 12px; color: var(--text-dim); margin-top: 1px;
    display: flex; align-items: center; gap: 6px;
}
.my-today-tag {
    font-size: 9.5px; font-weight: 800; text-transform: uppercase;
    letter-spacing: .06em; color: var(--ok);
    padding: 1px 5px; border-radius: 4px;
    background: rgba(74, 222, 128, .12);
    border: 1px solid rgba(74, 222, 128, .3);
}
.my-nav { display: flex; gap: 5px; flex: 0 0 auto; }


.my-gear { font-size: 15px; line-height: 1; }

.my-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 12px; }

/* An appointment card. Glass, tinted by the service colour: --svc/--svc-dim/
   --svc-lit all arrive together from the sw-* class, so the whole card follows
   one choice and a staff member's personal colour repaints it wholesale. */
.my-card {
    position: relative;
    display: flex; gap: 14px; align-items: stretch;
    padding: 14px 16px 14px 18px;
    border-radius: var(--radius-lg);
    overflow: hidden;

    /* The sticky header would otherwise cover a card that scrollIntoView
       considers perfectly placed. This reserves its height for SCROLLING only —
       it adds no visual gap. */
    scroll-margin-top: 84px;

    background:
        linear-gradient(140deg, var(--svc-dim), transparent 62%),
        var(--glass-bg);
    border: 1px solid var(--glass-border);
    backdrop-filter: blur(var(--glass-blur)) saturate(140%);
    -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(140%);
    box-shadow: var(--shadow);
    transition: transform .18s ease, box-shadow .18s ease;
}

.my-card:hover { transform: translateY(-1px); }

/* The lit top edge every other surface in the panel has. */
.my-card::before {
    content: "";
    position: absolute; inset: 0 0 auto 0; height: 1px;
    background: linear-gradient(90deg, transparent, var(--glass-edge-lit) 45%, transparent);
    pointer-events: none;
}

/* The service colour as a solid spine down the left edge. */
.my-card-rail {
    position: absolute; left: 0; top: 0; bottom: 0; width: 4px;
    background: var(--svc);
    box-shadow: 0 0 14px var(--svc-dim);
}

.my-card.is-cancelled { opacity: .45; }
.my-card.is-cancelled .my-svc { text-decoration: line-through; }

/* Already finished. Barely receded — every card stays fully usable, because the
   ✓/✕ on a past booking is exactly the control a staff member reaches for at the
   end of a shift. An earlier .62 dimmed the whole afternoon and made the buttons
   look disabled when they are not. Cancelled still fades hard: there is nothing
   to do with it. */
.my-card.is-past { opacity: .88; }
.my-card.is-past.is-cancelled { opacity: .38; }

/* Marking attendance does NOT change the card. The ✓ / ✕ buttons light up and
   that is the whole signal — the card keeps its service colour, its full
   strength and its legibility whichever way it was marked.
   A card that dimmed or struck itself through on a no-show made the day harder
   to read at a glance and buried the customer's name exactly when a staff
   member most wants to phone them.

   Written with .is-past in the selector rather than relying on source order:
   both are one-class-plus-.my-card, so equal specificity would otherwise leave
   "a marked card in the past" decided by which rule comes last in the file. */
.my-card.is-done, .my-card.is-noshow,
.my-card.is-past.is-done, .my-card.is-past.is-noshow { opacity: 1; }

/* ---- Attendance ----
   Top-right of the card, as asked: a green tick for "came in", a small ✕ for
   "did not". Tapping the one already set clears it, so the same control undoes
   a mis-tap — important on a phone held in one hand. */
.att {
    position: absolute; top: 10px; right: 10px;
    display: flex; gap: 5px; z-index: 2;
}
.att-btn {
    width: 26px; height: 26px; border-radius: 50%;
    display: flex; align-items: center; justify-content: center;
    font-size: 12px; line-height: 1; cursor: pointer; padding: 0;
    background: rgba(255, 255, 255, .05);
    border: 1px solid var(--glass-border);
    color: var(--text-faint);
    transition: transform .12s ease, background .12s ease, color .12s ease;
}
.att-btn:hover:not(:disabled) { transform: scale(1.1); color: var(--text-main); }
.att-btn:disabled { opacity: .5; cursor: default; }

.att-yes.is-on {
    background: rgba(74, 222, 128, .22);
    border-color: rgba(74, 222, 128, .6);
    color: #86EFAC;
    box-shadow: 0 0 12px rgba(74, 222, 128, .25);
}
.att-no.is-on {
    background: rgba(248, 113, 113, .2);
    border-color: rgba(248, 113, 113, .55);
    color: #FCA5A5;
    box-shadow: 0 0 12px rgba(248, 113, 113, .22);
}


/* The "now" line. Sits between cards, so the split between done and coming is
   drawn rather than left for the reader to infer from the scroll position. */
.my-now {
    display: flex; align-items: center; gap: 9px;
    margin: 2px 0; padding: 0 2px;
    font-variant-numeric: tabular-nums;
    scroll-margin-top: 84px;
}
.my-now::after {
    content: "";
    flex: 1 1 auto; height: 1px;
    background: linear-gradient(90deg, var(--crit), transparent);
}
.my-now-dot {
    width: 8px; height: 8px; border-radius: 50%;
    background: var(--crit);
    box-shadow: 0 0 10px var(--crit);
    flex: 0 0 auto;
}
.my-now-label {
    font-size: 10.5px; font-weight: 800; letter-spacing: .05em;
    color: var(--crit); flex: 0 0 auto;
}

/* A booking that landed while the page was open. The ring fades on its own so
   the card settles into the list instead of shouting forever. */
.my-card.is-new {
    animation: my-arrive .45s ease-out, my-glow 2.4s ease-out 3;
}
@keyframes my-arrive {
    from { opacity: 0; transform: translateY(-8px) scale(.985); }
}
@keyframes my-glow {
    0%, 100% { box-shadow: var(--shadow); }
    35%      { box-shadow: var(--shadow), 0 0 0 2px var(--svc), 0 0 22px var(--svc-dim); }
}
@media (prefers-reduced-motion: reduce) {
    .my-card.is-new { animation: none; box-shadow: var(--shadow), 0 0 0 2px var(--svc); }
    .my-card:hover { transform: none; }
}

.my-card-time {
    flex: 0 0 66px; display: grid; align-content: start; gap: 1px;
    font-variant-numeric: tabular-nums;
}
.my-t1 { font-size: 18px; font-weight: 800; color: var(--svc-lit); line-height: 1.15; }
.my-t2 { font-size: 12px; color: var(--text-dim); }
.my-dur { font-size: 10.5px; color: var(--text-faint); margin-top: 3px; }

.my-card-body { flex: 1 1 auto; min-width: 0; }
/* padding-right keeps the service name clear of the attendance buttons, which
   are absolutely positioned over the card's top-right corner. */
.my-card-top {
    display: flex; align-items: center; gap: 7px; flex-wrap: wrap;
    padding-right: 62px;
}
.my-svc { font-weight: 700; font-size: 14.5px; color: var(--text-main); }

.my-cust {
    font-size: 13px; margin-top: 4px;
    display: flex; gap: 7px; flex-wrap: wrap; align-items: center;
}
.my-cust-name { color: var(--text-main); }

.my-phone {
    display: inline-block; margin-top: 5px;
    font-size: 12.5px; color: var(--svc-lit); text-decoration: none;
    font-variant-numeric: tabular-nums;
}
.my-phone:hover { text-decoration: underline; }

/* The caller's own words. Given its own panel because it changes how the
   appointment is performed — an allergy, a request, "bringing my daughter". */
.my-note {
    display: flex; gap: 7px; margin-top: 9px;
    padding: 8px 10px; border-radius: var(--radius-md);
    background: var(--glass-bg-soft);
    border: 1px solid var(--glass-border);
    border-left: 2px solid var(--svc);
    font-size: 12.5px; line-height: 1.5; color: var(--text-dim);
}
.my-note-icon { flex: 0 0 auto; opacity: .6; }

/* ---- /my/report : one staff member's own numbers ---- */
.rep-tabs { display: flex; gap: 6px; margin-bottom: 14px; }
.rep-tab {
    flex: 1 1 0; padding: 8px 10px; border-radius: var(--radius-md);
    font-size: 12px; font-weight: 600; cursor: pointer;
    background: var(--glass-bg-soft);
    border: 1px solid var(--glass-border);
    color: var(--text-dim);
}
.rep-tab.is-on {
    background: var(--glass-bg);
    border-color: var(--text-dim);
    color: var(--text-main);
}

.rep-grid {
    display: grid; grid-template-columns: repeat(4, 1fr);
    gap: 8px; margin-bottom: 14px;
}
.rep-card {
    padding: 12px 10px; border-radius: var(--radius-lg);
    border: 1px solid var(--glass-border);
    background: var(--glass-bg);
    text-align: center;
}
.rep-val { font-size: 22px; font-weight: 800; line-height: 1.1; }
.rep-lbl { font-size: 10px; color: var(--text-dim); margin-top: 3px; }

.rep-green { background: linear-gradient(160deg, rgba(74,222,128,.14), var(--glass-bg)); border-color: rgba(74,222,128,.3); }
.rep-green .rep-val { color: #86EFAC; }
.rep-red   { background: linear-gradient(160deg, rgba(248,113,113,.14), var(--glass-bg)); border-color: rgba(248,113,113,.3); }
.rep-red .rep-val { color: #FCA5A5; }
.rep-grey  { background: var(--glass-bg-soft); }
.rep-grey .rep-val { color: var(--text-faint); }
.rep-blue  { background: linear-gradient(160deg, rgba(78,134,224,.14), var(--glass-bg)); border-color: rgba(78,134,224,.3); }

.rep-rate { padding: 16px; margin-bottom: 14px; }
.rep-rate-head { display: flex; align-items: baseline; gap: 8px; margin-bottom: 10px; }
.rep-rate-val { font-size: 30px; font-weight: 800; color: #86EFAC; line-height: 1; }
.rep-rate-lbl { font-size: 13px; color: var(--text-dim); }
.rep-rate-note { font-size: 11.5px; margin-top: 9px; line-height: 1.5; }

.rep-bar {
    display: flex; height: 10px; border-radius: 5px; overflow: hidden;
    background: var(--glass-bg-soft);
}
.rep-bar-yes { background: linear-gradient(90deg, #4ADE80, #86EFAC); }
.rep-bar-no  { background: linear-gradient(90deg, #F87171, #FCA5A5); }

.rep-lost { padding: 14px 16px; margin-bottom: 14px; }
.rep-lost-val { font-size: 22px; font-weight: 800; color: #FCA5A5; line-height: 1; }
.rep-lost-lbl { font-size: 11.5px; color: var(--text-dim); margin-top: 4px; }

.rep-days { padding: 12px 16px 16px; display: grid; gap: 8px; }
.rep-day { display: flex; align-items: center; gap: 10px; font-size: 11.5px; }
.rep-day-name { flex: 0 0 78px; color: var(--text-dim); }
.rep-day-bar {
    flex: 1 1 auto; display: flex; height: 14px; gap: 2px;
    border-radius: 4px; overflow: hidden;
}
.rep-day-n { flex: 0 0 20px; text-align: right; font-variant-numeric: tabular-nums; }
.rd-yes { background: rgba(74,222,128,.75); }
.rd-no  { background: rgba(248,113,113,.75); }
.rd-un  { background: rgba(255,255,255,.14); }

@media (max-width: 420px) {
    .rep-grid { grid-template-columns: repeat(2, 1fr); }
}

/* ---- Settings panel ----
   fade/slidein are defined here rather than borrowed: the identically-named
   keyframes in Calls.razor.css are SCOPED to that component and resolve to
   nothing from here, so the panel would have appeared with no animation. */
@keyframes fade { from { opacity: 0; } }
@keyframes slidein { from { transform: translateX(24px); opacity: 0; } }

.set-scrim {
    position: fixed; inset: 0; z-index: 200;
    background: rgba(0, 0, 0, .5);
    animation: fade .15s ease;
}
.set-panel {
    position: fixed; top: 0; right: 0; bottom: 0; z-index: 201;
    width: min(420px, 94vw);
    display: flex; flex-direction: column;
    background: var(--bg-gradient);
    border-left: 1px solid var(--glass-border);
    box-shadow: -12px 0 40px rgba(0, 0, 0, .45);
    animation: slidein .18s ease;
}
.set-head {
    flex: 0 0 auto;
    display: flex; align-items: center; justify-content: space-between;
    padding: 16px 18px; border-bottom: 1px solid var(--glass-border);
}
.set-title { font-weight: 700; font-size: 15px; }
.set-x {
    appearance: none; border: none; background: transparent;
    color: var(--text-dim); font-size: 16px; cursor: pointer; padding: 4px;
}
.set-x:hover { color: var(--text-main); }
.set-body { flex: 1 1 auto; min-height: 0; overflow-y: auto; padding: 18px; }

.set-sec { margin-bottom: 26px; }
.set-sec-title {
    font-size: 11px; text-transform: uppercase; letter-spacing: .06em;
    font-weight: 700; color: var(--text-faint); margin-bottom: 12px;
}
.set-hint { font-size: 11.5px; margin: -4px 0 12px; line-height: 1.5; }

.clr-row {
    display: flex; align-items: center; justify-content: space-between;
    gap: 12px; padding: 9px 0;
    border-bottom: 1px solid var(--glass-border);
}
.clr-row:last-child { border-bottom: none; }
.clr-name { font-size: 13px; display: flex; align-items: center; gap: 8px; min-width: 0; }

.clr-reset {
    appearance: none; border: none; background: transparent; cursor: pointer;
    color: var(--text-faint); font-size: 10.5px; text-decoration: underline;
    padding: 0;
}
.clr-reset:hover { color: var(--text-dim); }

.clr-swatches { display: flex; gap: 6px; flex: 0 0 auto; }

/* 26px: comfortably tappable on a phone, which is where this is used. */
.clr-dot {
    width: 26px; height: 26px; border-radius: 50%;
    border: 2px solid transparent; cursor: pointer; padding: 0;
    transition: transform .12s ease;
}
.clr-dot:hover { transform: scale(1.12); }
/* A ring in the page colour sits between swatch and border, so the selected
   dot reads as picked rather than merely outlined. */
.clr-dot.is-on {
    border-color: var(--text-main);
    box-shadow: 0 0 0 2px rgba(0, 0, 0, .55) inset;
}

@media (max-width: 480px) {
    .my-card { padding: 12px 13px 12px 16px; }
    .my-card-time { flex-basis: 58px; }
    .clr-dot { width: 30px; height: 30px; }
}

/* ------------------------------------------------------------------
   Full-screen overlays (drawers, modals)

   MainLayout's .main is `position:relative; z-index:1`, which makes it a
   STACKING CONTEXT. Everything rendered by a page lives inside it — including
   `position:fixed` drawers — so such a drawer can set z-index:9999 and STILL
   paint under the topbar (z 90) and sidebar (z 100), because the context it
   sits in is itself at 1. That is what hid the Calls drawer's header.

   A page that opens a full-screen overlay toggles `data-overlay` on <html>
   (see Calls.razor.js). While it is set, .main stops being a stacking context
   and the overlay layers against the real chrome. Global on purpose: scoped
   CSS cannot match <html>, which is the element the flag has to live on.
   ------------------------------------------------------------------ */
html[data-overlay] .main {
    z-index: auto;
}

/* ============================================================
   PUBLIC SIGNUP  (/signup)

   GLOBAL, not scoped, and that is load-bearing: the wizard is a page plus nine
   separate step COMPONENTS, and Blazor's scoped CSS does not cross a component
   boundary. Put these in Signup.razor.css and every step renders unstyled —
   the same trap that made the admin pool page render as raw markup.
   ============================================================ */

.signup-shell {
    min-height: 100vh;
    background: var(--bg-gradient);
    padding: 28px 18px 60px;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 20px;
}

.signup-head {
    display: flex;
    align-items: center;
    gap: 12px;
    width: 100%;
    max-width: 620px;
}

.signup-logo {
    width: 42px;
    height: 42px;
    object-fit: contain;
    filter: drop-shadow(0 0 8px var(--accent-glow));
}

.signup-brand { font-size: 16px; font-weight: 700; color: var(--text-main); }
.signup-tag   { font-size: 12px; color: var(--text-dim); margin-top: 2px; }

/* The rail. Horizontal and scrollable rather than wrapped: nine wrapped chips
   on a phone take three lines and push the actual question below the fold. */
.signup-rail {
    display: flex;
    gap: 6px;
    width: 100%;
    max-width: 620px;
    overflow-x: auto;
    padding-bottom: 4px;
    scrollbar-width: none;
}
.signup-rail::-webkit-scrollbar { display: none; }

.rail-step {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 5px 10px;
    border-radius: 20px;
    border: 1px solid var(--glass-border);
    background: var(--glass-bg-soft);
    font-size: 11px;
    color: var(--text-faint);
    white-space: nowrap;
    flex-shrink: 0;
}

.rail-step.done { color: var(--text-dim); }

.rail-step.here {
    color: var(--text-main);
    border-color: var(--accent-glow);
    box-shadow: 0 0 12px var(--accent-glow-soft);
}

.rail-dot {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 17px;
    height: 17px;
    border-radius: 50%;
    background: var(--glass-bg);
    border: 1px solid var(--glass-border);
    font-size: 10px;
    font-weight: 700;
}

.rail-step.here .rail-dot,
.rail-step.done .rail-dot { background: var(--accent-gradient); color: var(--accent-text-on-fill); }

.signup-card {
    width: 100%;
    max-width: 620px;
    background: var(--glass-bg);
    backdrop-filter: blur(var(--glass-blur)) saturate(140%);
    -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(140%);
    border: 1px solid var(--glass-border);
    border-radius: 16px;
    padding: 26px 24px;
}

/* Back, at the top of the card where somebody correcting a mistake looks.
   Quiet by default so it never competes with Continue — going forward is the
   common act — but a real button-sized target, not a text link. */
.signup-back {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    margin: -6px 0 14px;
    padding: 6px 12px 6px 8px;
    font: inherit;
    font-size: 13px;
    color: var(--text-dim);
    background: transparent;
    border: 1px solid transparent;
    border-radius: 8px;
    cursor: pointer;
    transition: background .15s, color .15s, border-color .15s;
}

.signup-back:hover,
.signup-back:focus-visible {
    color: var(--text-main);
    background: rgba(255, 255, 255, 0.06);
    border-color: var(--glass-border);
}

/* The arrow leads the label, so it reads as one control rather than a stray
   glyph beside a word. Nudged down a hair: the arrow's optical centre sits
   above the text baseline in most faces. */
.signup-back span { transform: translateY(0.5px); }

.signup-card h1 { font-size: 22px; margin: 0 0 8px; color: var(--text-main); }

.lede { color: var(--text-dim); font-size: 13.5px; line-height: 1.7; margin: 0 0 18px; }
.hint { color: var(--text-faint); font-size: 11.5px; margin-top: 5px; line-height: 1.6; }

/* A button that reads as a link — for the secondary way out of a step, which
   must never compete with the primary action. */
.linkish {
    background: none;
    border: none;
    padding: 0;
    font: inherit;
    font-size: 12.5px;
    color: var(--text-dim);
    text-decoration: underline;
    cursor: pointer;
}
.linkish:hover:not(:disabled) { color: var(--text-main); }
.linkish:disabled { opacity: 0.5; cursor: default; }

.btn-lg { padding: 11px 22px; font-size: 14px; width: 100%; justify-content: center; }

.signup-alt { display: flex; align-items: center; gap: 8px; margin-top: 14px; }
.signup-actions { display: flex; align-items: center; gap: 14px; margin-top: 18px; }
.signup-foot { font-size: 11.5px; color: var(--text-faint); }
.dot { color: var(--text-faint); }

/* A one-time code is read digit by digit off a screen and typed back. Wide
   tracking and a monospace face make a transposed pair visible. */
.code-input {
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 24px;
    letter-spacing: 10px;
    text-align: center;
}

/* ---- business type ---- */

.type-grid { display: grid; gap: 8px; grid-template-columns: 1fr; }

.type-card {
    display: flex;
    flex-direction: column;
    gap: 3px;
    text-align: left;
    padding: 12px 14px;
    border-radius: 12px;
    border: 1px solid var(--glass-border);
    background: var(--glass-bg-soft);
    color: var(--text-dim);
    cursor: pointer;
    font: inherit;
    transition: 0.15s;
}

.type-card:hover { border-color: var(--accent-glow); }

.type-card.picked {
    border-color: var(--accent-glow);
    box-shadow: 0 0 14px var(--accent-glow-soft);
    color: var(--text-main);
}

.type-name { font-weight: 600; font-size: 13.5px; }
.type-desc { font-size: 11.5px; color: var(--text-faint); line-height: 1.5; }

/* ---- hours ---- */

.day-row { display: flex; gap: 6px; flex-wrap: wrap; }

.day-chip {
    padding: 7px 11px;
    border-radius: 10px;
    border: 1px solid var(--glass-border);
    background: var(--glass-bg-soft);
    color: var(--text-faint);
    font: inherit;
    font-size: 12px;
    cursor: pointer;
}

.day-chip.on {
    background: var(--accent-gradient);
    color: var(--accent-text-on-fill);
    font-weight: 700;
    border-color: transparent;
}

.time-row { display: flex; gap: 12px; }
.time-row .field { flex: 1; }

/* The three figures that make up the free trial, side by side — they are one
   offer, and reading them apart is how a longer trial quietly becomes a much
   more generous one. Collapses to a single column on narrow screens rather
   than squeezing three number inputs to nothing. */
.trial-grid {
    display: grid;
    grid-template-columns: repeat(3, minmax(90px, 1fr));
    gap: 10px;
    max-width: 420px;
}

.trial-grid .hint { display: block; margin-top: 2px; }

@media (max-width: 480px) {
    .trial-grid { grid-template-columns: 1fr; }
}

/* ---- services / staff ---- */

.svc-list, .staff-list { display: flex; flex-direction: column; gap: 8px; margin-bottom: 12px; }

.svc-row, .staff-row { display: flex; align-items: center; gap: 6px; }

.svc-name { flex: 1 1 auto; min-width: 0; }
.svc-min, .svc-price { width: 74px; flex: 0 0 auto; }
.svc-unit { font-size: 11px; color: var(--text-faint); }
.staff-row .input { flex: 1; }

.svc-del { flex: 0 0 auto; }
.svc-del:disabled { opacity: 0.3; }

/* Column headings for the service rows.
   Deliberately reuses .svc-name / .svc-min / .svc-price so the headings inherit
   the SAME widths as the inputs they label — a heading row with its own sizes
   drifts out of line the moment either is touched, and a "Price" sitting over
   the minutes box is worse than no heading at all.
   The trailing padding stands in for each row's unit suffix ("min", "$") and
   the ✕ button, which have no counterpart up here. */
.svc-head {
    display: flex;
    align-items: center;
    gap: 6px;
    margin-bottom: 6px;
    padding-inline-end: 40px;
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.02em;
    text-transform: uppercase;
    color: var(--text-faint);
}

/* Each heading gets its input's width PLUS that column's unit suffix, so
   "How long" sits over the minutes box rather than creeping left of it. */
.svc-head .svc-min,
.svc-head .svc-price { width: calc(74px + 6px + 1.6em); }

/* ---- number step / summary ---- */

.fact-list { margin: 0 0 20px; padding-left: 18px; line-height: 1.9; color: var(--text-dim); font-size: 13px; }
.fact-list strong { color: var(--text-main); }

.summary { margin: 0 0 20px; display: flex; flex-direction: column; gap: 9px; }
.summary > div { display: flex; gap: 12px; font-size: 13px; }
.summary dt { flex: 0 0 88px; color: var(--text-faint); }
.summary dd { margin: 0; color: var(--text-main); min-width: 0; overflow-wrap: anywhere; }

.signup-done { text-align: center; }

.done-tick {
    width: 54px;
    height: 54px;
    margin: 0 auto 14px;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 26px;
    background: var(--color-success);
    color: #04231a;
}

@media (min-width: 560px) {
    .type-grid { grid-template-columns: 1fr 1fr; }
    .btn-lg { width: auto; }
}
