/* /Components/Layout/MainLayout.razor.rz.scp.css */
.portal-shell[b-gxq09b5oau] {
    min-height: 100vh;
    display: flex;
    flex-direction: column;
    background: var(--portal-bg, #050407);
}

.portal-main[b-gxq09b5oau] {
    flex: 1;
}

.portal-footer[b-gxq09b5oau] {
    padding: 32px 24px;
    text-align: center;
    color: var(--portal-text-muted, #98a09b);
    border-top: 1px solid var(--portal-border, #34383c);
}

.portal-footer a[b-gxq09b5oau] {
    color: inherit;
    text-decoration: none;
}

.portal-footer a:hover[b-gxq09b5oau] {
    text-decoration: underline;
}

/* Auto / Light / Dark (9 Sep 2026). Three buttons rather than one that flips, because "follow
   this device" is not the opposite of anything — and the one in force has to be readable at a
   glance or the group is a puzzle. */
.portal-footer .theme-switch[b-gxq09b5oau] {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    margin-left: 0.6rem;
}

.portal-footer .theme-switch-label[b-gxq09b5oau] {
    color: var(--portal-text-faint, #6a726d);
}

.portal-footer .theme-switch-btn[b-gxq09b5oau] {
    background: none;
    border: 1px solid var(--portal-border-card, #34383c);
    border-radius: 999px;
    color: inherit;
    font: inherit;
    font-size: 12px;
    padding: 4px 12px;
    cursor: pointer;
}

.portal-footer .theme-switch-btn:hover[b-gxq09b5oau] {
    color: var(--portal-text, #e3e6e4);
    border-color: var(--portal-text-muted, #98a09b);
}

.portal-footer .theme-switch-btn[aria-current][b-gxq09b5oau] {
    color: var(--portal-accent-text, #80d4c8);
    border-color: var(--portal-accent, #5fcabb);
    font-weight: 700;
}

.portal-footer .brand-mark[b-gxq09b5oau] {
    width: 16px;
    height: 16px;
    vertical-align: -3px;
    margin-right: 0.4rem;
}

#blazor-error-ui[b-gxq09b5oau] {
    background: #fff3cd;
    bottom: 0;
    box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
    display: none;
    left: 0;
    padding: 0.6rem 1.25rem 0.7rem 1.25rem;
    position: fixed;
    width: 100%;
    z-index: 1000;
}

#blazor-error-ui .dismiss[b-gxq09b5oau] {
    cursor: pointer;
    position: absolute;
    right: 0.75rem;
    top: 0.5rem;
}
/* /Components/Layout/ReconnectModal.razor.rz.scp.css */
.components-reconnect-first-attempt-visible[b-9hyg142gkg],
.components-reconnect-repeated-attempt-visible[b-9hyg142gkg],
.components-reconnect-failed-visible[b-9hyg142gkg],
.components-pause-visible[b-9hyg142gkg],
.components-resume-failed-visible[b-9hyg142gkg],
.components-rejoining-animation[b-9hyg142gkg] {
    display: none;
}

#components-reconnect-modal.components-reconnect-show .components-reconnect-first-attempt-visible[b-9hyg142gkg],
#components-reconnect-modal.components-reconnect-show .components-rejoining-animation[b-9hyg142gkg],
#components-reconnect-modal.components-reconnect-paused .components-pause-visible[b-9hyg142gkg],
#components-reconnect-modal.components-reconnect-resume-failed .components-resume-failed-visible[b-9hyg142gkg],
#components-reconnect-modal.components-reconnect-retrying[b-9hyg142gkg],
#components-reconnect-modal.components-reconnect-retrying .components-reconnect-repeated-attempt-visible[b-9hyg142gkg],
#components-reconnect-modal.components-reconnect-retrying .components-rejoining-animation[b-9hyg142gkg],
#components-reconnect-modal.components-reconnect-failed[b-9hyg142gkg],
#components-reconnect-modal.components-reconnect-failed .components-reconnect-failed-visible[b-9hyg142gkg] {
    display: block;
}


#components-reconnect-modal[b-9hyg142gkg] {
    background-color: white;
    width: 20rem;
    margin: 20vh auto;
    padding: 2rem;
    border: 0;
    border-radius: 0.5rem;
    box-shadow: 0 3px 6px 2px rgba(0, 0, 0, 0.3);
    opacity: 0;
    transition: display 0.5s allow-discrete, overlay 0.5s allow-discrete;
    animation: components-reconnect-modal-fadeOutOpacity-b-9hyg142gkg 0.5s both;
    &[open]

{
    animation: components-reconnect-modal-slideUp-b-9hyg142gkg 1.5s cubic-bezier(.05, .89, .25, 1.02) 0.3s, components-reconnect-modal-fadeInOpacity-b-9hyg142gkg 0.5s ease-in-out 0.3s;
    animation-fill-mode: both;
}

}

#components-reconnect-modal[b-9hyg142gkg]::backdrop {
    background-color: rgba(0, 0, 0, 0.4);
    animation: components-reconnect-modal-fadeInOpacity-b-9hyg142gkg 0.5s ease-in-out;
    opacity: 1;
}

@keyframes components-reconnect-modal-slideUp-b-9hyg142gkg {
    0% {
        transform: translateY(30px) scale(0.95);
    }

    100% {
        transform: translateY(0);
    }
}

@keyframes components-reconnect-modal-fadeInOpacity-b-9hyg142gkg {
    0% {
        opacity: 0;
    }

    100% {
        opacity: 1;
    }
}

@keyframes components-reconnect-modal-fadeOutOpacity-b-9hyg142gkg {
    0% {
        opacity: 1;
    }

    100% {
        opacity: 0;
    }
}

.components-reconnect-container[b-9hyg142gkg] {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 1rem;
}

#components-reconnect-modal p[b-9hyg142gkg] {
    margin: 0;
    text-align: center;
}

#components-reconnect-modal button[b-9hyg142gkg] {
    border: 0;
    background-color: #6b9ed2;
    color: white;
    padding: 4px 24px;
    border-radius: 4px;
}

    #components-reconnect-modal button:hover[b-9hyg142gkg] {
        background-color: #3b6ea2;
    }

    #components-reconnect-modal button:active[b-9hyg142gkg] {
        background-color: #6b9ed2;
    }

.components-rejoining-animation[b-9hyg142gkg] {
    position: relative;
    width: 80px;
    height: 80px;
}

    .components-rejoining-animation div[b-9hyg142gkg] {
        position: absolute;
        border: 3px solid #0087ff;
        opacity: 1;
        border-radius: 50%;
        animation: components-rejoining-animation-b-9hyg142gkg 1.5s cubic-bezier(0, 0.2, 0.8, 1) infinite;
    }

        .components-rejoining-animation div:nth-child(2)[b-9hyg142gkg] {
            animation-delay: -0.5s;
        }

@keyframes components-rejoining-animation-b-9hyg142gkg {
    0% {
        top: 40px;
        left: 40px;
        width: 0;
        height: 0;
        opacity: 0;
    }

    4.9% {
        top: 40px;
        left: 40px;
        width: 0;
        height: 0;
        opacity: 0;
    }

    5% {
        top: 40px;
        left: 40px;
        width: 0;
        height: 0;
        opacity: 1;
    }

    100% {
        top: 0px;
        left: 0px;
        width: 80px;
        height: 80px;
        opacity: 0;
    }
}
/* /Components/Pages/Home.razor.rz.scp.css */
/* Booking home — the one page styled as the platform's own storefront. Salon pages
   (/{slug}) keep the salon's branding; everything here uses the portal tokens.

   .book-header / .book-brand are NOT here: this file is scoped to Home.razor (CSS isolation),
   and /account and /account/recover use the same header markup — with the rules in here they
   rendered the favicon at its natural size, a full-width Mi mark on a phone (found on
   production 18 Sep 2026). They live in app.css. */

.book-nav[b-wm3k2vrlgh] {
    display: flex;
    align-items: center;
    gap: 26px;
}

.book-nav a[b-wm3k2vrlgh] {
    color: var(--portal-text-body);
    text-decoration: none;
    font-weight: 500;
}

.book-nav a:hover[b-wm3k2vrlgh] { color: var(--portal-text); }

.book-nav .btn-book-now[b-wm3k2vrlgh] {
    background: var(--portal-accent);
    color: var(--portal-accent-contrast);
    font-weight: 700;
    padding: 10px 22px;
    border-radius: 12px;
}

.book-nav .btn-book-now:hover[b-wm3k2vrlgh] { background: var(--portal-accent-deep); color: var(--portal-accent-contrast); }

/* 1700px of content, and FIVE cards per row at the most (William, 25 Sep 2026: "base on the width
   of the screen, the website can shows 1, 2, 3, 4 or 5").
   The number is not arbitrary. With a 320px floor and a 22px gap, five cards need
   5x320 + 4x22 = 1688px and a sixth needs 2030px, so a content box between those two figures
   holds the row at five however big the monitor is. Only a very large monitor reaches the cap at
   all; everything narrower runs edge to edge.
   Widening the card from 250px to 320px moved this cap with it (1600 -> 1700) and cost a column
   on a laptop: five cards now want a 1744px WINDOW, so a 1512px screen shows four. */
.book-container[b-wm3k2vrlgh] {
    max-width: 1756px;   /* 1700 content + the 28px gutters */
    margin: 0 auto;
    padding: 0 28px 48px;
}

.book-hero[b-wm3k2vrlgh] { padding: 72px 0 40px; }

.hero-eyebrow[b-wm3k2vrlgh] {
    color: var(--portal-accent-text);
    font-size: 0.8rem;
    font-weight: 700;
    letter-spacing: 0.22em;
    text-transform: uppercase;
    margin: 0 0 18px;
}

.book-hero h1[b-wm3k2vrlgh] {
    max-width: 18ch;
    font-size: clamp(2.4rem, 6vw, 4.5rem);
    font-weight: 800;
    letter-spacing: -0.02em;
    margin: 0 0 18px;
    color: var(--portal-text);
}

.hero-sub[b-wm3k2vrlgh] {
    color: var(--portal-text-muted);
    font-size: 1.15rem;
    line-height: 1.6;
    max-width: 620px;
    margin: 0;
}

/* ── Salon cards ─────────────────────────────────────────────────────────── */

/* As many cards per row as the WINDOW can hold, from one on a phone to five at the cap:

     390px  1      1024px  2      1512px  4
     768px  2      1280px  3      1744px  5

   Two details here are load-bearing, and both are easy to get wrong.

   auto-FILL, not auto-fit. auto-fit collapses the tracks nothing sits in, and the surviving
   tracks then absorb that space through `1fr` — so three salons on a wide window would stretch
   into three enormous cards. auto-fill keeps the empty tracks, so a small group sits at ordinary
   size under the heading with room to its right, which is the honest picture.

   `1fr` as the maximum, not `400px`. This is the one that actually bit (25 Sep 2026, William:
   "why 3 card on 1 line, there are empty space on left and right"). The repetition count for
   auto-fill/auto-fit uses a track's MAX sizing function whenever that is a definite length — so
   `minmax(250px, 400px)` counts in 400px steps, not 250px, and 1600px of content produced THREE
   tracks rather than five. A flexible max is not definite, so the count falls back to the 250px
   minimum, which is what the numbers above assume. The card's size is then bounded by the
   container cap instead. */
.salon-grid[b-wm3k2vrlgh] {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 320px), 1fr));
    justify-items: start;
    gap: 22px;
    scroll-margin-top: 24px;
}

/* The 350px ceiling lives on the CARD, not on the track (William, 25 Sep 2026: "min-width 320px
   and max-width 350px"). Putting it in the track's minmax would make the column count divide by
   350 rather than 320 — the defect fixed one commit ago — and would cost a column at most widths:
   a 1512px window would drop from four cards to three. So the tracks stay flexible and the card
   simply stops growing at 350px, with justify-items: start keeping the first one flush under the
   heading. Between breakpoints this leaves slack at the end of a row, which is the price of the
   card never becoming a slab. */
.salon-card[b-wm3k2vrlgh] {
    max-width: 350px;
    width: 100%;
    /* ONE height for every card on the page (William, 25 Sep 2026: "The shop card height is
       fix"). Grid already levelled the cards within a row; this levels them between rows too, so
       a salon with one category and a salon with nine draw the same rectangle. Everything that
       could disagree about height is pinned below: the title and the address are clamped to two
       lines each, the category strip is a fixed window, and the status row keeps margin-top:auto
       so the slack collects above it and the button stays on the floor. */
    height: 470px;
}

.salon-card[b-wm3k2vrlgh] {
    background: var(--portal-panel);
    border: 1px solid var(--portal-border-card);
    border-radius: 14px;
    overflow: hidden;               /* the logo panel hugs the rounded top */
    display: flex;
    flex-direction: column;
}

/* The logo panel. A deliberately LIGHT surface in both themes — brand marks are drawn for
   pale stationery, and a dark card eats the dark half of most of them. Fixed 16:9-ish box so
   a row of cards keeps one shoulder line whatever shape the logos are. */
.salon-figure[b-wm3k2vrlgh] {
    position: relative;
    aspect-ratio: 4 / 1;
    overflow: hidden;
    background: #fbfaf7;
    border-bottom: 1px solid var(--portal-border-card);
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 18px 20px;
}

/* Sized at LAST. Until 25 Sep 2026 there was no rule at all here, so the booking site drew every
   brand mark at its natural size — 512x512 for both of production's — as a block wider than the
   card's content box, clipped by the card's own overflow.

   multiply is what lets the mark sit on the panel instead of in a box on it. Both of production's
   logos are opaque near-white (#fefcfd) rather than transparent, so on a warm panel they would
   otherwise show as a slightly-wrong-white rectangle with a visible seam; multiplied, their ground
   becomes the panel exactly and only the ink remains. A logo that really is transparent is
   unaffected, so this costs nothing to the brands that upload one.

   Sized by WIDTH, not height, and the panel clips what hangs out. Both of production's logos are
   SQUARE canvases holding a wide, short mark with blank bands above and below it; fitting the whole
   square inside a 4:1 panel would shrink the mark to the panel's height and leave it tiny. Sizing
   by width and letting the blank bands overflow spends the panel on the mark instead. A logo whose
   art really does fill its canvas is cropped rather than shrunk, which is why max-height bounds it
   — and a wide logo file never reaches the bound at all. */
.salon-logo[b-wm3k2vrlgh] {
    width: 78%;
    max-height: 260%;
    object-fit: contain;
    mix-blend-mode: multiply;
}

/* Shown when the brand has no logo yet. Ink on the light panel, never the theme's text colour —
   this panel does not flip with the theme. */
.salon-wordmark[b-wm3k2vrlgh] {
    color: #1a1d1f;
    font-size: 1.15rem;
    font-weight: 700;
    letter-spacing: -0.01em;
    text-align: center;
}

/* Half the size it was (William, 25 Sep 2026). It is a state, not a headline — the salon's name
   and the Book button are what the card is for, and at full size the pill competed with the logo
   it sits beside. 0.62rem is the floor for a bold uppercase-height badge before it stops being
   readable at arm's length on a tablet. */
.salon-open[b-wm3k2vrlgh] {
    position: absolute;
    top: 7px;
    right: 7px;
    display: inline-flex;
    align-items: center;
    gap: 4px;
    border-radius: 999px;
    padding: 3px 8px;
    font-size: 0.62rem;
    font-weight: 700;
    background: #14171a;
    color: #e3e6e4;
}

.salon-open .dot[b-wm3k2vrlgh] {
    width: 5px;
    height: 5px;
    border-radius: 50%;
    flex: none;
}

.salon-open.is-open .dot[b-wm3k2vrlgh] { background: var(--portal-accent); }
.salon-open.is-open[b-wm3k2vrlgh] { color: var(--portal-accent); }
.salon-open.is-shut .dot[b-wm3k2vrlgh] { background: #8b9196; }
.salon-open.is-shut[b-wm3k2vrlgh] { color: #b9bfc3; }

.salon-body[b-wm3k2vrlgh] {
    padding: 22px 22px 20px;
    display: flex;
    flex-direction: column;
    flex: 1;                        /* buttons align across cards of unequal height */
}

/* The spring lives on .salon-status when there is one; this keeps the button on the floor for
   a card whose snapshot said nothing at all. */
.salon-body > .btn-book:not(:first-child)[b-wm3k2vrlgh] { margin-top: auto; }

.salon-eyebrow[b-wm3k2vrlgh] {
    color: var(--portal-text-faint);
    font-size: 0.72rem;
    font-weight: 700;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    margin: 0 0 10px;
}

.salon-body h2[b-wm3k2vrlgh] {
    font-size: 1.45rem;
    font-weight: 700;
    color: var(--portal-text);
    margin: 0 0 8px;
    /* Two lines is enough for "Rouse Hill Town Center", the longest name on production. */
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    overflow: hidden;
}

.salon-address[b-wm3k2vrlgh] {
    color: var(--portal-text-muted);
    line-height: 1.5;
    margin: 0 0 16px;
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    overflow: hidden;
}

/* A fixed window, two rows tall, with the categories drifting behind it when there are more than
   fit (William, 25 Sep 2026: "if the categories is too many, can you make them scroll up and down
   automatically?"). Fixed, because a card of one height cannot have a part of it that grows.
   --chips-h is named rather than inlined because the animation has to do arithmetic with it. */
.salon-chips[b-wm3k2vrlgh] {
    --chips-h: 58px;
    height: var(--chips-h);
    overflow: hidden;
    margin-bottom: 16px;
}

.salon-chips-run[b-wm3k2vrlgh] {
    display: flex;
    flex-wrap: wrap;
    gap: 7px;
    /* The whole trick is min(): 100% is the RUN's own height, so when the categories fit, the
       second operand is positive, min() picks 0px, and nothing moves. No script, no measuring, and
       a one-category salon sits perfectly still. */
    animation: chip-drift-b-wm3k2vrlgh 14s ease-in-out infinite alternate;
}

@keyframes chip-drift-b-wm3k2vrlgh {
    0%, 18%   { transform: translateY(0); }
    82%, 100% { transform: translateY(min(0px, calc(var(--chips-h) - 100%))); }
}

/* Anyone who has asked for less movement gets a strip they scroll themselves instead. */
@media (prefers-reduced-motion: reduce) {
    .salon-chips[b-wm3k2vrlgh] { overflow-y: auto; }
    .salon-chips-run[b-wm3k2vrlgh] { animation: none; }
}

.chip[b-wm3k2vrlgh] {
    border: 1px solid var(--portal-border-card);
    color: var(--portal-text-body);
    border-radius: 999px;
    padding: 4px 11px;
    font-size: 0.68rem;
    white-space: nowrap;
}

/* A rule, then the two answers to "can I walk in now?" on one line: what the queue is doing
   on the left, when the door shuts on the right. Pushed to the bottom of the body so the rule
   sits just above the button on every card, however many chips the salon has. */
.salon-status[b-wm3k2vrlgh] {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 14px;
    margin-top: auto;
    padding-top: 16px;
    border-top: 1px solid var(--portal-border);
    margin-bottom: 18px;
}

.status-live[b-wm3k2vrlgh] {
    color: var(--portal-accent-text);
    font-weight: 600;
    margin: 0;
}

.status-open[b-wm3k2vrlgh] {
    color: var(--portal-text-muted);
    margin: 0;
    white-space: nowrap;
}

.btn-book[b-wm3k2vrlgh] {
    background: var(--portal-accent);
    color: var(--portal-accent-contrast);
    border-radius: 12px;
    padding: 15px 18px;
    text-align: center;
    font-weight: 600;
    text-decoration: none;
}

.btn-book strong[b-wm3k2vrlgh] { font-weight: 800; }

.btn-book:hover[b-wm3k2vrlgh] { background: var(--portal-accent-deep); }

/* ── Feature strip ───────────────────────────────────────────────────────── */

.book-features[b-wm3k2vrlgh] {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(240px, 400px));
    gap: 28px;
    border-top: 1px solid var(--portal-border);
    margin-top: 56px;
    padding-top: 36px;
}

.book-features h3[b-wm3k2vrlgh] {
    font-size: 1rem;
    font-weight: 700;
    color: var(--portal-text);
    margin: 0 0 8px;
}

.book-features p[b-wm3k2vrlgh] {
    color: var(--portal-text-muted);
    line-height: 1.55;
    margin: 0;
    max-width: 46ch;      /* the container is full-bleed now; prose is not */
}

@media (max-width: 640px) {
    .book-container[b-wm3k2vrlgh] { padding: 0 18px 40px; }
    .book-hero[b-wm3k2vrlgh] { padding: 44px 0 28px; }
}
