/* /Components/Client/LocationPicker.razor.rz.scp.css */
/* Everything the location picker looks like, living next to the component that owns it — nothing about the
   map leaks into the global sheets. custom.css keeps the design TOKENS (it is the only place they live);
   this file only spends them.

   Leaflet builds its own DOM at runtime (tiles, zoom control, attribution, the marker), so those elements
   never receive Blazor's scope attribute. `::deep` is how a scoped sheet reaches them: it drops the scope
   requirement for descendants of an element the component *did* render. Same trick Skeleton.razor.css uses.

   Every colour below is a token, so the light/dark swap (html.theme-light re-points the variables) carries
   the map with it. Nothing here is a literal colour except the pin's outline, which is explained where it
   is used. */

.location-picker[b-igq0nyyyrm] {
    --location-picker-height: 320px;

    /* ---- The map's own light, translated into the theme ----
       OpenStreetMap only ships LIGHT raster tiles — there is no free, key-less dark basemap (CARTO's dark
       style now needs an Enterprise licence, MapTiler's free tier is non-commercial). So the tiles are
       re-lit in the browser instead, as a filter over the whole tile pane.

       Dark: invert + a 180° hue rotation is the one transform that darkens a map WITHOUT wrecking it —
       inverting alone would turn the sea orange; rotating the hue back around the wheel restores it. The
       water stays blue, the parks stay green, and the labels flip to light-on-dark and stay readable. The
       saturation/contrast trim then settles it onto the forest canvas instead of glaring off it.
       Light: a whisper of warmth so the map sits in the cream palette rather than on top of it. */
    --map-tiles: invert(1) hue-rotate(185deg) brightness(.92) contrast(.95) saturate(.75);
}

html.theme-light .location-picker[b-igq0nyyyrm] {
    --map-tiles: saturate(.92) sepia(.06);
}

/* ---- address search: field + button on one line, hits floating under them ---- */
.location-picker__search[b-igq0nyyyrm] { position: relative; display: flex; align-items: center; gap: .5rem; }
.location-picker[b-igq0nyyyrm]  .location-picker__query { flex: 1 1 auto; min-width: 0; }  /* min-width:0 — else the field refuses to shrink */
.location-picker[b-igq0nyyyrm]  .location-picker__go { flex: 0 0 auto; }

/* The hits hang under the search box and OVER the map, so finding an address never reflows the form and
   shoves the save button out from under the merchant's cursor. */
.location-picker[b-igq0nyyyrm]  .location-picker__results {
    position: absolute;
    top: calc(100% + .35rem);
    inset-inline: 0;
    z-index: 5;
    max-height: 210px;
    overflow-y: auto;
    background: var(--surface-2);
    border-radius: var(--radius-sm);
    box-shadow: 0 10px 30px rgba(0, 0, 0, .28);
}
.location-picker[b-igq0nyyyrm]  .location-picker__result {
    justify-content: flex-start;
    text-align: start;
    text-transform: none;
    padding: .5rem .75rem;
    border-radius: 0;
    color: var(--text-primary);
}
.location-picker[b-igq0nyyyrm]  .location-picker__result:first-child { border-radius: var(--radius-sm) var(--radius-sm) 0 0; }
.location-picker[b-igq0nyyyrm]  .location-picker__result:last-child { border-radius: 0 0 var(--radius-sm) var(--radius-sm); }
.location-picker[b-igq0nyyyrm]  .location-picker__result:only-child { border-radius: var(--radius-sm); }
.location-picker[b-igq0nyyyrm]  .location-picker__result:hover { background: var(--surface-3); }
.location-picker[b-igq0nyyyrm]  .location-picker__result + .location-picker__result { border-top: 1px solid var(--outline); }
.location-picker[b-igq0nyyyrm]  .location-picker__result-text { display: flex; flex-direction: column; gap: .1rem; min-width: 0; }
.location-picker[b-igq0nyyyrm]  .location-picker__result-name { font-size: .88rem; font-weight: 600; line-height: 1.3; }
.location-picker[b-igq0nyyyrm]  .location-picker__result-where { font-size: .76rem; color: var(--text-secondary); line-height: 1.3; }

/* ---- the map box: a Bento tile like any other ---- */
.location-picker__map[b-igq0nyyyrm] {
    height: var(--location-picker-height);
    border-radius: var(--radius-sm);
    border: 1px solid var(--outline);
    overflow: hidden;
    background: var(--surface-2);   /* shows through while the tiles are still coming in */
    font: inherit;
    /* Leaflet's panes and controls live at z-index 400–800. Isolating gives them a stacking context of their
       own, so they cannot climb over a dialog's chrome or the search hits floating above. */
    isolation: isolate;
    /* The app flips to RTL in Arabic. Leaflet positions its panes and controls with scripted left/right
       offsets, so an inherited RTL direction lands them on the wrong side and mirrors the attribution. The
       map's internals are a coordinate space, not prose — they stay LTR whatever the UI does. */
    direction: ltr;
}
.location-picker__map:focus-visible[b-igq0nyyyrm] { outline: 2px solid var(--accent); outline-offset: -2px; }

/* Re-light the tiles. Filtering the PANE, not each tile, keeps the seams from showing and is one
   composite instead of twenty. The marker lives in a different pane, so the pin keeps its true colour. */
.location-picker__map[b-igq0nyyyrm]  .leaflet-tile-pane { filter: var(--map-tiles); }

/* ---- zoom control: a Bento box, not Leaflet's white 4px chip ---- */
.location-picker__map[b-igq0nyyyrm]  .leaflet-control-zoom {
    border: 1px solid var(--outline);
    border-radius: var(--radius-sm);
    overflow: hidden;
    box-shadow: 0 4px 14px rgba(0, 0, 0, .18);
}
.location-picker__map[b-igq0nyyyrm]  .leaflet-control-zoom a {
    background: var(--surface);
    color: var(--text-primary);
    border-bottom-color: var(--outline);
    font-weight: 500;
}
.location-picker__map[b-igq0nyyyrm]  .leaflet-control-zoom a:hover { background: var(--surface-3); color: var(--accent); }
.location-picker__map[b-igq0nyyyrm]  .leaflet-control-zoom a.leaflet-disabled { background: var(--surface-2); color: var(--text-disabled); }

/* ---- attribution: the OSM tile policy requires it stay visible, so it stays — just quiet ---- */
.location-picker__map[b-igq0nyyyrm]  .leaflet-control-attribution {
    background: var(--surface-translucent);
    color: var(--text-secondary);
    border-radius: var(--radius-sm) 0 0 0;
    font-size: .68rem;
    padding: .1rem .4rem;
}
.location-picker__map[b-igq0nyyyrm]  .leaflet-control-attribution a { color: var(--text-secondary); text-decoration: underline; }

/* ---- the pin: our accent, drawn as an SVG divIcon so it themes and scales (no PNG) ----
   Its outline is white in BOTH themes on purpose — the pin sits on the map, not on an app surface, so it
   has to contrast with the tiles underneath it rather than with the theme around it. */
.location-picker__map[b-igq0nyyyrm]  .location-pin { cursor: grab; }
.location-picker__map[b-igq0nyyyrm]  .location-pin:active { cursor: grabbing; }
.location-picker__map[b-igq0nyyyrm]  .location-pin svg {
    width: 32px; height: 32px;
    fill: var(--accent);
    stroke: var(--on-accent);
    stroke-width: .8;
    filter: drop-shadow(0 3px 4px rgba(0, 0, 0, .45));
}
.location-picker__map[b-igq0nyyyrm]  .leaflet-marker-draggable:focus-visible .location-pin svg {
    outline: 2px solid var(--accent);
    border-radius: 4px;
}

/* ---- the Ctrl+scroll coach: raised by the wheel gate (see the .js) when a plain wheel lands on the map ---- */
.location-picker__map[b-igq0nyyyrm]  .map-wheel-hint {
    position: absolute;
    inset: 0;
    z-index: 900;              /* above every Leaflet pane (400–800), still inside the map's isolated stack */
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 1rem;
    text-align: center;
    font-size: .95rem;
    font-weight: 500;
    color: var(--text-primary);
    background: var(--surface-translucent);
    opacity: 0;
    transition: opacity .25s ease;
    /* A coach mark, never a wall: the map below keeps every click, drag and wheel. */
    pointer-events: none;
    /* The map's internals are pinned LTR (see above) but this is prose — first-strong bidi lets the
       Arabic hint lay itself out RTL inside the LTR container. */
    unicode-bidi: plaintext;
}
.location-picker__map[b-igq0nyyyrm]  .map-wheel-hint--on { opacity: 1; }

/* ---- narrow screens: a shorter map and a tighter search button ---- */
@media (max-width: 600px) {
    .location-picker[b-igq0nyyyrm] { --location-picker-height: 240px; }
    .location-picker[b-igq0nyyyrm]  .location-picker__go { padding-inline: .6rem; }
    .location-picker[b-igq0nyyyrm]  .location-picker__results { max-height: 160px; }
}
/* /Components/Client/Management/FormSaveLoyaltyCard.razor.rz.scp.css */
/* Card-builder page — component-scoped CSS (.razor.css). Tokens only (custom.css). */

/* Two columns on wide screens: the form on the left, the Apple + Google previews stacked in a
   STICKY right column (the Google pass-builder behaviour) — they scroll with the page, then pin
   below the floating app bar and stay in view. No inner scrollbar, no fixed overlay. Narrower
   screens keep the previews in normal flow above the form. */
.card-builder__preview[b-ukjj110gzf] {
    margin-bottom: 1.5rem;
}

@media (min-width: 1280px) {
    .card-builder__columns[b-ukjj110gzf] {
        display: flex;
        gap: 1.5rem;
        align-items: flex-start;
    }

    .card-builder__form[b-ukjj110gzf] {
        order: 1;
        flex: 1 1 auto;
        min-width: 0;
    }

    .card-builder__preview[b-ukjj110gzf] {
        order: 2;
        flex: 0 0 var(--builder-preview-width);
        margin-bottom: 0;
    }
}

/* Pin the column only when the whole panel fits the viewport, scaling the two stacked device mocks
   to the available height — both cards stay whole while pinned, no inner scrollbar, nothing clipped.
   Shorter screens keep the natural size and scroll normally. */
@media (min-width: 1280px) and (min-height: 900px) {
    .card-builder__preview[b-ukjj110gzf] {
        position: sticky;
        top: calc(var(--mud-appbar-height, 64px) + var(--chrome-gap) * 2);
    }

    .card-builder__preview[b-ukjj110gzf]  .wallet-stage { zoom: 0.63; }
}

@media (min-width: 1280px) and (min-height: 1050px) {
    .card-builder__preview[b-ukjj110gzf]  .wallet-stage { zoom: 0.78; }
}

@media (min-width: 1280px) and (min-height: 1200px) {
    .card-builder__preview[b-ukjj110gzf]  .wallet-stage { zoom: 0.9; }
}

@media (min-width: 1280px) and (min-height: 1360px) {
    .card-builder__preview[b-ukjj110gzf]  .wallet-stage { zoom: 1; }
}

/* Reserves space for the inset percentage so the slider doesn't shift as the number changes width. */
[b-ukjj110gzf] .stamp-inset-value {
    min-width: 3ch;
}

/* Same reservation for the stamp-size percentage ("100%" is one character wider). */
[b-ukjj110gzf] .stamp-size-value {
    min-width: 4ch;
}

/* White frame around the enrollment QR preview so the code stays scannable on any card colour. */
[b-ukjj110gzf] .qr-frame {
    background: var(--on-accent);
    width: fit-content;
    margin-inline: auto;
    border: 1px solid var(--mud-palette-lines-default);
}
/* /Components/Client/Management/PlanPickerCards.razor.rz.scp.css */
.pick-card--locked[b-wavpht2t5d] {
    opacity: .55;
    cursor: not-allowed;
}

/* What separates the plans, on the tile where the choice is actually made. */
.pick-card__list[b-wavpht2t5d] {
    list-style: none;
    margin: .6rem 0 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: .3rem;
    font-size: .8rem;
    line-height: 1.3;
}

.pick-card__list li[b-wavpht2t5d] {
    display: flex;
    align-items: flex-start;
    gap: .35rem;
    color: var(--text-primary);
}

.pick-card__list[b-wavpht2t5d]  .mud-icon-root {
    font-size: .95rem;
    flex: none;
    margin-top: .1rem;
    color: var(--accent);
}

/* "Everything in Starter" and "+N more included" are context, not selling points. */
.pick-card__inherit[b-wavpht2t5d],
.pick-card__more[b-wavpht2t5d] {
    color: var(--text-secondary);
}

.pick-card__inherit[b-wavpht2t5d] {
    font-weight: 600;
}
/* /Components/Client/Management/PublishToggleButton.razor.rz.scp.css */
/* Publish "go live" CTA — one pill, two gradients. --card: grounded forest→terracotta (Starter tier),
   white ink, a diagonal light band glints on hover. --stamps: luminous terracotta→butter (Growth tier),
   soft text shadow for legibility over the butter end, the band sweeps continuously. MudButton is a
   child component, so its rendered element is reached with ::deep from the scoped .publish wrapper. */
.publish[b-oac1jy98dn]  .publish__cta.mud-button-filled {
    position: relative;
    overflow: hidden;
    border-radius: var(--radius-pill);
    color: var(--on-accent);
    box-shadow: none;
    padding: .55rem 1.6rem;
    font-weight: 600;
    transition: filter .2s ease, transform .2s ease, box-shadow .2s ease;
}

.publish[b-oac1jy98dn]  .publish__cta--card.mud-button-filled {
    background: linear-gradient(120deg, var(--grad-from) 0%, var(--accent) 116%);
}

.publish[b-oac1jy98dn]  .publish__cta--stamps.mud-button-filled {
    background: linear-gradient(120deg, var(--accent) 0%, var(--spotlight) 132%);
    text-shadow: 0 1px 2px rgba(0, 0, 0, .22);
}

.publish[b-oac1jy98dn]  .publish__cta .mud-button-label { position: relative; z-index: 1; }

.publish[b-oac1jy98dn]  .publish__cta::after {
    content: "";
    position: absolute;
    inset: 0;
    z-index: 0;
    pointer-events: none;
    background: linear-gradient(105deg, transparent 34%, rgba(255, 255, 255, .5) 50%, transparent 66%);
    transform: translateX(-130%);
}

.publish[b-oac1jy98dn]  .publish__cta--stamps::after {
    background: linear-gradient(105deg, transparent 34%, rgba(255, 255, 255, .55) 50%, transparent 66%);
    animation: publish-shine-b-oac1jy98dn 3.4s ease-in-out infinite;
}

.publish[b-oac1jy98dn]  .publish__cta:hover {
    filter: brightness(1.06);
    transform: translateY(-1px);
    box-shadow: 0 6px 18px rgba(0, 0, 0, .22);
}
.publish[b-oac1jy98dn]  .publish__cta--stamps:hover { box-shadow: 0 6px 20px rgba(0, 0, 0, .26); }
.publish[b-oac1jy98dn]  .publish__cta--card:hover::after { animation: publish-shine-b-oac1jy98dn 1.1s ease-out; }
.publish[b-oac1jy98dn]  .publish__cta:active { transform: translateY(0); filter: brightness(.98); }
.publish[b-oac1jy98dn]  .publish__cta.mud-disabled { filter: grayscale(.3) opacity(.7); box-shadow: none; transform: none; }

@keyframes publish-shine-b-oac1jy98dn {
    0%        { transform: translateX(-130%); }
    60%, 100% { transform: translateX(130%); }
}

/* Live state — calm success pill + quiet unpublish. */
.publish__live-row[b-oac1jy98dn] { display: flex; align-items: center; gap: .75rem; flex-wrap: wrap; }
.publish__live[b-oac1jy98dn] {
    display: inline-flex;
    align-items: center;
    gap: .4rem;
    padding: .3rem .8rem;
    border-radius: var(--radius-pill);
    background: var(--success-soft);
    color: var(--success);
    font-weight: 600;
    font-size: .875rem;
    line-height: 1;
}
.publish__live[b-oac1jy98dn]  .mud-icon-root { font-size: 1.05rem; color: var(--success); }

@media (prefers-reduced-motion: reduce) {
    .publish[b-oac1jy98dn]  .publish__cta::after { animation: none; display: none; }
    .publish[b-oac1jy98dn]  .publish__cta:hover { transform: none; }
}
/* /Components/Client/Management/SubscriptionApplicationsManager.razor.rz.scp.css */
.motivation-cell[b-r3v6r4v2eu] {
    display: inline-block;
    max-width: 22ch;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
/* /Components/Client/Management/WalletPreviews/Apple/InteractiveAppleWalletCard.razor.rz.scp.css */
/* ============================================================
   Apple Wallet store card — 1:1 port of the open-source pkvd.app
   (passkit-visual-designer) renderer, the canonical pixel-perfect web
   replica of Apple Wallet. Values are pkvd's own (box model in px, type in
   pt → px at 96dpi), with two corrections the skeptic pass flagged as the
   common clone mistakes:
     • primary value rendered in a LIGHT weight (~300), not regular/bold;
     • logo kept small (max-height 15px) and corner radius small (7px).

   Per-card colours are injected as the --pass-bg / --pass-ink / --pass-ink-dim
   custom properties (backgroundColor / foregroundColor / labelColor — the
   CSS-var-injection exception); never hard-code black/white text here.

   Component-scoped: these styles only ever apply to this component, so they
   live here (not in the global stylesheet). `.device__label` and the
   `.wallet-stage*` base remain global (shared with the Google card). Rendered
   bare (no phone frame); the compact tier scales the whole pixel-exact card as
   one unit via `zoom`, exactly like the Google preview.
   ============================================================ */

/* bare-card column: the iOS-style top bar, then the floating pass.
   Three INDEPENDENT size knobs:
     • zoom (here)                          — overall CONTENT scale (fonts/padding/icons);
     • .awallet-scene / .awallet-topbar width — the card's WIDTH;
     • .awallet-flipper height                — the card's HEIGHT.
   zoom is tuned so the rendered card height (348px × 1.16 ≈ 404px) matches the side-by-side
   Google card (≈405px) — without touching it. Base width is set so the WIDTH is unchanged
   (297 × 1.16 ≈ 344). The compact tier scales via its own zoom. */
.awallet[b-km67syvjup] { display: flex; flex-direction: column; align-items: center; gap: .5rem; zoom: 1.16; }
.wallet-stage--compact .awallet[b-km67syvjup] { gap: .3rem; zoom: .52; }
.wallet-stage--compact .awallet .device__label[b-km67syvjup] { display: none; }
.wallet-stage--compact .awallet-topbar[b-km67syvjup] { display: none; }

/* Off-screen probe: a CSS background-image never fires onerror, so the banner is loaded once
   through a real <img> whose failure flips BannerFailed. Never visible. */
.awallet-probe[b-km67syvjup] { display: none; }

/* ---- iOS-style top bar: OUTSIDE the card, on the app surface (app-theme tokens).
   Caption is centred; Done overlays the left and share/••• overlay the right, so the
   card below never shifts position when the pass flips. ---- */
.awallet-topbar[b-km67syvjup] { position: relative; width: 297px; max-width: 100%; min-height: 24px; display: flex; align-items: center; justify-content: center; }
.awallet-topbar__done[b-km67syvjup] {
    position: absolute; left: 0; top: 50%; transform: translateY(-50%);
    background: none; border: none; padding: 2px 4px; cursor: pointer;
    color: var(--accent); font: inherit; font-size: 14px; font-weight: 600;
}
.awallet-topbar__actions[b-km67syvjup] { position: absolute; right: 0; top: 50%; transform: translateY(-50%); display: inline-flex; align-items: center; gap: 6px; }
.awallet-topbar__btn[b-km67syvjup] {
    width: 22px; height: 22px; padding: 0; border-radius: 50%;
    border: 1px solid var(--outline); background: var(--surface-2); color: var(--text-secondary);
    display: grid; place-items: center; cursor: pointer;
}
.awallet-topbar__btn--ghost[b-km67syvjup] { cursor: default; }
.awallet-topbar__btn[b-km67syvjup]  .mud-icon-root { font-size: 13px; }

/* ---- flip scene: front ⇄ back on the Y axis ---- */
.awallet-scene[b-km67syvjup] { perspective: 1100px; width: 297px; max-width: 100%; } /* ← card WIDTH knob (height lives on .awallet-flipper) */
.awallet-flipper[b-km67syvjup] {
    position: relative; width: 100%; height: 348px; /* ← card HEIGHT knob */
    transition: transform .6s cubic-bezier(.4, 0, .2, 1);
    transform-style: preserve-3d;
}
.awallet-flipper.flipped[b-km67syvjup] { transform: rotateY(180deg); }
.awallet-face[b-km67syvjup] {
    position: absolute; inset: 0;
    -webkit-backface-visibility: hidden; backface-visibility: hidden;
}
.awallet-face--back[b-km67syvjup] { transform: rotateY(180deg); }

/* ---- pass shell ---- */
.awallet-card[b-km67syvjup] {
    width: 100%; height: 100%;
    border-radius: 7px; overflow: hidden;
    /* fallback = the plain white card an uncoloured pass really is (passes take one flat colour) */
    background: var(--pass-bg, #FFFFFF);
    color: var(--pass-ink);
    font-family: -apple-system, BlinkMacSystemFont, "SF Pro Display", "SF Pro Text",
                 "Helvetica Neue", "Inter", system-ui, sans-serif;
    -webkit-font-smoothing: antialiased;
}
.awallet-content[b-km67syvjup] { display: flex; flex-direction: column; height: 100%; box-sizing: border-box; padding: 10px; }

/* ---- generic field: small uppercase label above its value ---- */
.awallet-field[b-km67syvjup] { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.awallet-label[b-km67syvjup] {
    font-size: 9.33px; font-weight: 600; letter-spacing: .045em;
    text-transform: uppercase; color: var(--pass-ink-dim);
    line-height: 1.25; white-space: nowrap;
}
.awallet-value[b-km67syvjup] {
    font-size: 10.67px; font-weight: 500; color: var(--pass-ink);
    line-height: 1.2; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.awallet-value--wrap[b-km67syvjup] {
    white-space: normal; overflow: hidden;
    display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
}

/* ---- header row: logo + logoText … store name (no label) ---- */
.awallet-header[b-km67syvjup] { display: flex; align-items: center; gap: 7px; min-height: 24px; margin-bottom: 14px; }
.awallet-logo[b-km67syvjup] { flex: none; display: inline-flex; align-items: center; }
/* the logo (a MudImage) and its fallback glyph (a MudIcon) are emitted by child
   components, so reach into them with ::deep from this component's scoped element */
.awallet-logo[b-km67syvjup]  .awallet-logo-img { max-height: 22px; width: auto; max-width: 64px; object-fit: contain; display: block; }
.awallet-logo-fallback[b-km67syvjup] {
    width: 22px; height: 22px; border-radius: 6px; flex: none;
    display: grid; place-items: center;
    background: var(--wallet-fallback-fill); color: var(--pass-ink-dim);
}
.awallet-logo-fallback[b-km67syvjup]  .mud-icon-root { font-size: .95rem; }
.awallet-logo-text[b-km67syvjup] {
    flex: 1 1 auto; min-width: 0;
    font-size: 13px; font-weight: 600; letter-spacing: .01em; color: var(--pass-ink);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* store name — a label-less, right-aligned header value (regular weight), like a real pass */
/* Both names show in full whenever the row can fit them (the common case → no "…").
   When it can't, the store name yields space FIRST (high flex-shrink) and truncates, so the
   bold card name on the left — the primary identifier — stays readable, like a real pass.
   No tight max-width cap (which would clip the name even when there's room beside a short title). */
.awallet-store[b-km67syvjup] {
    flex: 0 100 auto; min-width: 0; max-width: 80%;
    text-align: right; font-size: 11.5px; font-weight: 350; color: var(--pass-ink);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

/* ---- strip image (full-bleed) with the single primary field overlaid ---- */
.awallet-strip[b-km67syvjup] {
    position: relative; display: flex; align-items: flex-start;
    height: 90px; width: calc(100% + 20px); margin: 0 -10px;
    padding: 14px 12px; box-sizing: border-box;
    background-size: cover; background-position: center; overflow: hidden;
}
/* darken the TOP of the strip — where the primary (points) field overlays it — so the
   white value/label stay legible over any artwork (real iOS does this; pkvd omits it) */
.awallet-strip:not(.awallet-strip--empty)[b-km67syvjup] {
    background-image: linear-gradient(to bottom, rgba(0, 0, 0, .55) 0%, rgba(0, 0, 0, .15) 45%, rgba(0, 0, 0, 0) 72%),
                      var(--pass-banner);
}
.awallet-strip--empty[b-km67syvjup] { background: var(--wallet-fallback-fill); }
.awallet-strip__icon[b-km67syvjup] { position: absolute; top: 8px; left: 50%; transform: translateX(-50%); display: inline-flex; color: var(--pass-ink-dim); }
.awallet-strip__icon[b-km67syvjup]  .mud-icon-root { font-size: 1.4rem; }

/* Stamp system: the shared stamp grid (a child component's iframe) fills the strip, alone. There is no scrim
   and no primary field over it — the pass drops primaryFields in stamp mode, so anything drawn here would be
   preview-only fiction (and would dim the stamps for nothing). */

/* primary = big value on TOP, small uppercase label directly UNDER it (matches real iOS) */
.awallet-field--primary[b-km67syvjup] { gap: 0; min-width: 0; max-width: 100%; position: relative; z-index: 2; }
.awallet-field--primary .awallet-value[b-km67syvjup] {
    font-size: 38.67px; font-weight: 300; line-height: 1; letter-spacing: -.01em;
    font-variant-numeric: tabular-nums; overflow: visible;
}
.awallet-field--primary .awallet-label[b-km67syvjup] { font-size: 12px; letter-spacing: .02em; margin-top: 3px; }
/* over a banner the primary always reads white; the empty placeholder uses themed ink */
.awallet-strip:not(.awallet-strip--empty) .awallet-field--primary .awallet-value[b-km67syvjup] { color: var(--wallet-ink-light); }
.awallet-strip:not(.awallet-strip--empty) .awallet-field--primary .awallet-label[b-km67syvjup] { color: var(--wallet-ink-light-dim); }

/* ---- secondary field row (reward) on the solid background ---- */
.awallet-fields[b-km67syvjup] { display: flex; flex-direction: row; gap: 10px; margin-top: 10px; min-width: 0; }
.awallet-fields .awallet-field[b-km67syvjup] { flex: 1 1 0; }

/* ---- barcode pinned to the bottom on a pure-white quiet-zone plate ---- */
.awallet-footer[b-km67syvjup] { margin-top: auto; padding-top: 12px; display: flex; justify-content: center; }
.awallet-barcode[b-km67syvjup] {
    background: #fff; border-radius: 5px; padding: 9px 9px 7px;
    display: flex; flex-direction: column; align-items: center; gap: 6px; max-width: 100%;
}
/* the QR/PDF417 placeholder glyphs are MudIcons (child components) → reach in with ::deep;
   the real codes are plain <img> in this component's render, so they scope normally.
   colour set on the scoped parent so the inherited glyph stays dark on the white plate. */
.awallet-qr[b-km67syvjup] { display: grid; place-items: center; color: #0b0b0c; }
.awallet-qr img[b-km67syvjup] { width: 92px; height: 92px; display: block; }
.awallet-qr[b-km67syvjup]  .mud-icon-root { width: 92px; height: 92px; font-size: 92px; }
/* PDF417 symbology: a wide strip instead of the square QR */
.awallet-qr--pdf417[b-km67syvjup] { width: 170px; max-width: 100%; }
.awallet-qr--pdf417 img[b-km67syvjup] { width: 100%; height: 46px; object-fit: contain; }
.awallet-qr--pdf417[b-km67syvjup]  .mud-icon-root { width: 100%; height: 46px; font-size: 46px; }
.awallet-code[b-km67syvjup] {
    font-family: ui-monospace, "SF Mono", Menlo, monospace;
    font-size: 11px; letter-spacing: .12em; color: #1a1a1a; text-transform: uppercase; line-height: 1;
}

/* ---- back of card: dimmed sheet, grouped rows, iOS controls ---- */
.awallet-back[b-km67syvjup] {
    position: absolute; inset: 0; display: flex; flex-direction: column;
    background: rgba(0, 0, 0, .5); color: var(--wallet-ink-light);
}
.awallet-back__body[b-km67syvjup] { flex: 1; overflow-y: auto; padding: 16px 12px 14px; display: flex; flex-direction: column; gap: 12px; }
.awallet-back__group[b-km67syvjup] { background: rgba(255, 255, 255, .10); border-radius: 11px; overflow: hidden; }
.awallet-back__row[b-km67syvjup] { padding: 9px 13px; display: flex; flex-direction: column; gap: 2px; }
.awallet-back__label[b-km67syvjup] { font-size: 10px; text-transform: uppercase; letter-spacing: .05em; color: rgba(255, 255, 255, .6); }
.awallet-back__link[b-km67syvjup] { font-size: 13px; color: var(--pass-link); text-decoration: none; word-break: break-word; }
.awallet-back__value[b-km67syvjup] { font-size: 13px; color: rgba(255, 255, 255, .95); word-break: break-word; }
.awallet-back__toggle[b-km67syvjup] { display: flex; align-items: center; justify-content: space-between; padding: 5px 13px; }
.awallet-back__toggle + .awallet-back__toggle[b-km67syvjup] { border-top: 1px solid rgba(255, 255, 255, .07); }
.awallet-back__toggle-label[b-km67syvjup] { font-size: 13.5px; color: var(--wallet-ink-light); }
.awallet-back__remove[b-km67syvjup] {
    margin-top: auto; text-align: center; padding: 11px; border-radius: 11px;
    background: rgba(255, 255, 255, .08); color: var(--pass-danger);
    font-size: 14px; font-weight: 500; cursor: pointer; transition: background .15s ease;
}
.awallet-back__remove:hover[b-km67syvjup] { background: var(--pass-danger-tint); }

/* Responsive: above ~420px the full-size card fits (the builder preview column, or the
   form stacked on mobile, is wide enough). Below that, scale the whole column down as one
   unit so the card always fits its container — no clipping, no overflow. The card box also
   carries max-width:100% as a final safety. */
@media (max-width: 420px) { .awallet[b-km67syvjup] { zoom: 1.1; } }
@media (max-width: 360px) { .awallet[b-km67syvjup] { zoom: .95; } }
@media (max-width: 320px) { .awallet[b-km67syvjup] { zoom: .82; } }
/* /Components/Client/Management/WalletPreviews/Google/InteractiveGoogleWalletCard.razor.rz.scp.css */
/* ============================================================
   Google Wallet loyalty card — 1:1 port of Google's pass-preview.css
   (the loyalty subset), kept at Google's EXACT pixel values. The QR is
   generated by us and the CSS is self-hosted, so there is NO runtime
   dependency on Google's assets — safe for production.

   Google's own layout reads --passview-background-color / --passview-font-color,
   which we inject per card (the CSS-var-injection exception). Compact tier
   tiles scale the whole pixel-exact card as one unit via `zoom`.

   Component-scoped: these styles only ever apply to this component, so they
   live here (not in the global stylesheet). `.device__label` and the
   `.wallet-stage*` base remain global (shared with the Apple card).
   ============================================================ */

/* bare-card column: a small platform caption above the floating card */
.gwallet[b-3i2lmbgust] { display: flex; flex-direction: column; align-items: center; gap: .65rem; }
.wallet-stage--compact .gwallet[b-3i2lmbgust] { gap: .35rem; }
.wallet-stage--compact .gwallet .device__label[b-3i2lmbgust] { display: none; }
/* compact tiles render the pixel-exact card scaled down as a single unit */
.wallet-stage--compact .pass-view-group[b-3i2lmbgust] { zoom: .7; }

.pass-view-group[b-3i2lmbgust] {
    position: relative;
    margin: 0;
    color: var(--passview-font-color, white);
    width: 270px;
    max-width: 100%;
    border-radius: 24px;
    overflow: hidden;
    box-shadow: 0 4px 7px 1px rgb(0 0 0 / 14%),
                0 3px 9px 2px rgb(0 0 0 / 12%),
                0 4px 4px -3px rgb(0 0 0 / 20%);
    font-family: 'Google Sans', Roboto, Arial, sans-serif;
    font-size: 13px;
    line-height: normal;
    -webkit-font-smoothing: antialiased;
}
.pass-view-group *[b-3i2lmbgust] { position: relative; }

.pass-view-group .pass-overlay[b-3i2lmbgust] {
    width: 100%; height: 100%;
    position: absolute; pointer-events: none; z-index: 1;
}

.pass-view[b-3i2lmbgust] {
    display: flex; flex-direction: column;
    border-radius: 24px 24px 0 0;
    box-shadow: inset 0 0 0 1px #ffffff33;
    /* fallback = the plain white card an uncoloured pass really is (passes take one flat colour) */
    background: var(--passview-background-color, #FFFFFF);
    cursor: default;
}

/* head: logo + issuer, divider, then the program header */
.pass-view .head[b-3i2lmbgust] {
    font-weight: 500; text-align: left; margin-top: 3px;
    border-radius: 24px 24px 6px 6px;
}
.pass-view .title-bar[b-3i2lmbgust] {
    display: flex; flex-direction: row; align-items: center;
    border-radius: 24px 24px 6px 6px;
}
.pass-view .logo-wrapper[b-3i2lmbgust] { padding: 6px; margin: 6px 0 6px 6px; border-radius: 100%; }
.pass-view .logo[b-3i2lmbgust] {
    height: 24px; width: 24px; flex-grow: 0; flex-shrink: 0;
    background-color: #ffffffdd; overflow: hidden; border-radius: 100%;
}
.pass-view .logo p[b-3i2lmbgust] {
    margin: 0; color: #5f6368; font-size: 14px; font-weight: 500;
    line-height: 24px; text-align: center;
}
.pass-view .logo-image[b-3i2lmbgust] { object-fit: cover; border: 0; height: 100%; max-width: 100%; }
.pass-view .card-title[b-3i2lmbgust] {
    flex: auto; padding: 6px; margin-right: 12px;
    font-size: 14px; letter-spacing: 0.015em;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap; border-radius: 6px;
}
.pass-view .dim-divider[b-3i2lmbgust] { height: 1px; background-color: #ffffff15; }
.pass-view .main-header[b-3i2lmbgust] {
    font-size: 20px; padding: 1px 12px; letter-spacing: 0;
    font-weight: normal; line-height: 30px; word-break: break-word;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* Google's exact vertical spacers, replicated as classes (no inline styles) */
.pass-view .pv-gap-6[b-3i2lmbgust]  { height: 6px; }
.pass-view .pv-gap-10[b-3i2lmbgust] { height: 10px; }

/* points / reward row */
.pass-view .row[b-3i2lmbgust] { display: flex; flex-direction: row; }
.pass-view .row-item[b-3i2lmbgust] {
    font-weight: 500; display: inline-flex; flex-direction: column;
    overflow: hidden; border-radius: 6px;
}
.pass-view .start-item[b-3i2lmbgust] { flex: 1 1 0; align-items: flex-start; text-align: left; }
.pass-view .end-item[b-3i2lmbgust]   { flex: 1 1 0; align-items: flex-end;   text-align: right; }
.pass-view .row-label[b-3i2lmbgust] {
    width: 100%; flex: 1 0 50%; padding: 6px 12px 0 12px;
    font-size: 11px; letter-spacing: 0; white-space: nowrap; overflow: hidden;
}
.pass-view .row-label-value[b-3i2lmbgust] {
    width: 100%; flex: 1 0 50%; padding: 0 12px 6px 12px;
    font-size: 14px; letter-spacing: 0; font-variant-numeric: tabular-nums;
    text-overflow: ellipsis; white-space: nowrap; overflow: hidden;
}

/* Google's exact rule: keep a minimum height for empty required fields */
.pass-view .card-title[b-3i2lmbgust]:after,
.pass-view .main-header[b-3i2lmbgust]:after,
.pass-view .row-label[b-3i2lmbgust]:after,
.pass-view .row-label-value[b-3i2lmbgust]:after {
    display: inline-block;
    content: '';
}

/* barcode — our own QR/PDF417 dropped into Google's white rounded plate */
.pass-view .barcode[b-3i2lmbgust] {
    display: flex; flex-direction: column; align-items: center;
    padding: 5px 0; overflow: hidden;
}
.pass-view .barcode-wrapper[b-3i2lmbgust] {
    margin: 0 30px; background-color: white; border-radius: 12px; display: inline-flex;
}
.pass-view .barcode-img[b-3i2lmbgust] { display: block; margin: 14px; }
.pass-view .barcode-img.qr[b-3i2lmbgust]  { width: 110px; height: 110px; }
.pass-view .barcode-img.bar[b-3i2lmbgust] { width: 160px; }
.pass-view .barcode-img.pdf[b-3i2lmbgust] { width: 190px; }
.pass-view .barcode-img.text[b-3i2lmbgust] {
    margin: 20px; color: #212121; font-size: 15px; font-weight: 300; text-align: center;
}
.pass-view .barcode-alternate-text[b-3i2lmbgust] {
    text-align: center; padding: 4px 25px; font-size: 14px;
    text-overflow: ellipsis; white-space: nowrap; overflow: hidden;
}

/* hero / banner image at the bottom (Google's exact 270 x 87.9) */
.pass-view .hero-image[b-3i2lmbgust] {
    width: 270px; height: 87.9px; object-fit: cover;
    margin-top: -1px; border-radius: 0 0 24px 24px; display: block;
}
.pass-view .hero-image--empty[b-3i2lmbgust] {
    box-sizing: border-box;
    display: grid; place-items: center;
    background: #ffffff14; color: #ffffff8c;
}
/* stamp system: the shared stamp grid (a child component's iframe) absolutely fills the hero box and is
   clipped to its rounded bottom corners */
.pass-view .hero-image--stamps[b-3i2lmbgust] { position: relative; overflow: hidden; }

/* Responsive: scale the card down as a single unit on smaller screens 
   to match the Apple card's responsive scaling and keep heights equal. */
@media (max-width: 420px) { .gwallet[b-3i2lmbgust] { zoom: .85; } }
@media (max-width: 360px) { .gwallet[b-3i2lmbgust] { zoom: .73; } }
@media (max-width: 320px) { .gwallet[b-3i2lmbgust] { zoom: .63; } }

/* Links module */
.pass-view .links-module[b-3i2lmbgust] {
    padding: 0 20px;
    margin-bottom: 6px;
}
.pass-view .link-btn[b-3i2lmbgust] {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 14px 16px;
    background-color: #ffffff14;
    border-radius: 12px;
    color: inherit;
    text-decoration: none;
    font-size: 14px;
    font-weight: 500;
}
.pass-view .link-btn:hover[b-3i2lmbgust] {
    background-color: #ffffff24;
}
/* /Components/Client/Management/WalletPreviews/StampGridPreview.razor.rz.scp.css */
/* The stamp-card banner iframe fills its positioned parent (the Apple strip / Google hero) and is purely
   visual — pointer-events:none so the card behind it stays clickable. The banner content (grid, logos, fade)
   is the shared StampGridHtml rendered inside the iframe; nothing else is styled here. */

.stamp-grid[b-ppranknc58] {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    border: 0;
    display: block;
    pointer-events: none;
}
/* /Components/Client/Skeleton.razor.rz.scp.css */
/* Skeleton.razor — content-shaped loading overlay.
   The wrapper is layout-transparent (display:contents) so it never disturbs the bento-grid / flex
   spans of the children it wraps. While .is-loading, every descendant's real ink is hidden and each
   LEAF element (text runs, values, chips) becomes a shimmering bar via ::deep — so the skeleton
   matches the real DOM automatically, with no per-surface placeholder markup to maintain.
   Colours are the --skeleton-* tokens, which flip with the light/dark theme. */

.skeleton[b-czvjtm7u1m] {
    display: contents;
}

/* Freeze interaction + hide the real ink of every descendant while loading. Backgrounds & borders of
   CONTAINERS are intentionally left alone, so card frames (surface-card / MudPaper) stay visible and
   the skeleton reads as real cards with loading content inside. */
.skeleton.is-loading[b-czvjtm7u1m]  * {
    color: transparent !important;
    text-shadow: none !important;
    pointer-events: none !important;
    -webkit-user-select: none !important;
    user-select: none !important;
}

/* Leaf elements (no element children) = the actual content → shimmer bars. */
.skeleton.is-loading[b-czvjtm7u1m]  *:not(:has(*)) {
    background-image: linear-gradient(100deg,
        var(--skeleton-base) 30%,
        var(--skeleton-shine) 50%,
        var(--skeleton-base) 70%) !important;
    background-size: 200% 100% !important;
    background-repeat: no-repeat !important;
    border-radius: var(--radius-sm) !important;
    animation: skeleton-shimmer-b-czvjtm7u1m 1.4s ease-in-out infinite !important;
}

/* Icons / images: hide the glyph/bitmap so it doesn't bleed through the shimmer. */
.skeleton.is-loading[b-czvjtm7u1m]  svg {
    fill: transparent !important;
    stroke: transparent !important;
}
.skeleton.is-loading[b-czvjtm7u1m]  img {
    visibility: hidden !important;
}

@keyframes skeleton-shimmer-b-czvjtm7u1m {
    from { background-position: 200% 0; }
    to   { background-position: -200% 0; }
}

/* Accessibility: keep the placeholder tint, drop the motion. */
@media (prefers-reduced-motion: reduce) {
    .skeleton.is-loading[b-czvjtm7u1m]  *:not(:has(*)) {
        animation: none !important;
    }
}
/* /Components/Public/PasswordInput.razor.rz.scp.css */
/* Scoped styles for PasswordInput (acc-input with an overlaid show/hide eye button). The scoped bundle
   (EVibeLoyalty.styles.css) is linked globally in App.razor, so these rules apply on the static-SSR
   Identity pages exactly as in interactive WASM. The input keeps every .acc-input style; we only reserve
   room on the right and place the button there. The show/hide is wired by the collocated
   PasswordInput.razor.js. */
.pwd[b-gbqbcv0uwx] { position: relative; display: block; width: 100%; }

/* The <input> is rendered by the InputText COMPONENT, so it never receives this file's [b-hash] scope
   attribute (only plain HTML elements authored here do) — reach it via ::deep off the scoped wrapper.
   The extra specificity also beats .acc-input's own padding regardless of stylesheet order. */
.pwd[b-gbqbcv0uwx]  .pwd__input { padding-right: 2.9rem; }

/* Button sits over the input's right edge, vertically centred. currentColor drives the MudIcon fill. */
.pwd__toggle[b-gbqbcv0uwx] {
    position: absolute; top: 0; right: 0; height: 100%; width: 2.9rem;
    display: inline-flex; align-items: center; justify-content: center;
    padding: 0; border: none; background: transparent; color: var(--text-secondary);
    cursor: pointer; border-radius: 0 var(--radius-input) 0 0; transition: color .18s ease;
}
.pwd__toggle:hover[b-gbqbcv0uwx] { color: var(--text-primary); }
.pwd__toggle:focus-visible[b-gbqbcv0uwx] { outline: 2px solid var(--accent); outline-offset: -2px; }
.pwd__icon[b-gbqbcv0uwx] { display: inline-flex; align-items: center; justify-content: center; line-height: 0; }

/* Hint under the field (mirrors the MudBlazor helper-text look). */
.pwd__help[b-gbqbcv0uwx] { margin: 0; font-size: .82rem; color: var(--text-secondary); }
/* /Components/Public/PhoneNumberInput.razor.rz.scp.css */
/* Scoped styles for PhoneNumberInput (country picker fused with the national number into one control).
   The scoped bundle (EVibeLoyalty.styles.css) is linked globally in App.razor, so these rules apply on the
   static-SSR Join page exactly as in the interactive admin dialogs. Behaviour lives in the collocated
   PhoneNumberInput.razor.js.

   ::deep note — the Razor compiler stamps this file's [b-hash] scope attribute on plain HTML elements
   authored in the .razor only. Three targets need ::deep (anchored on a scoped ancestor):
     .phone-combo__native  → rendered by the InputSelect COMPONENT
     .phone-input__number  → rendered by the InputText COMPONENT
     .phone-combo__empty   → created at runtime by the JS (never compiled, so never stamped) */
.phone-input[b-khoi2o9obe] {
    display: flex; align-items: stretch; width: 100%; box-sizing: border-box;
    background: var(--field-fill); border: none;
    border-radius: var(--radius-input) var(--radius-input) 0 0;
    box-shadow: inset 0 -1px 0 0 var(--outline-strong);
    transition: background .18s ease, box-shadow .18s ease;
}
.phone-input:hover[b-khoi2o9obe] { background: var(--field-fill-hover); box-shadow: inset 0 -1px 0 0 var(--text-secondary); }
.phone-input:focus-within[b-khoi2o9obe] {
    background: var(--field-fill);
    box-shadow: inset 0 -2px 0 0 var(--accent);
}
/* Country picker (progressive enhancement). The combo wrapper is the segment; it holds the no-JS native
   <select>, plus the JS-revealed flag trigger and the search popover. */
.phone-combo[b-khoi2o9obe] { position: relative; flex: 0 0 auto; display: flex; align-items: stretch; border-right: 1px solid var(--outline); }
.phone-input:focus-within .phone-combo[b-khoi2o9obe] { border-right-color: var(--outline-strong); }
.phone-input__flag[b-khoi2o9obe] { font-size: 1.2rem; line-height: 1; }
.phone-input__chev[b-khoi2o9obe] { color: var(--text-secondary); font-size: .65rem; }

/* No-JS fallback: the native select styled as a compact segment. */
.phone-combo[b-khoi2o9obe]  .phone-combo__native {
    border: none; outline: none; background: transparent; color: var(--text-primary);
    font-family: inherit; font-size: 1rem; /* >=16px: no iOS zoom */ font-weight: 600;
    padding-inline: .95rem .7rem; max-width: 9.5rem; cursor: pointer;
}
.phone-combo[b-khoi2o9obe]  .phone-combo__native option { color: var(--text-primary); background: var(--surface); }

/* JS-enhanced trigger: just the flag + chevron. */
.phone-combo__trigger[b-khoi2o9obe] {
    display: inline-flex; align-items: center; gap: .4rem; cursor: pointer;
    border: none; background: transparent; padding-inline: .95rem .8rem; height: 100%;
}
.phone-combo__trigger:focus-visible[b-khoi2o9obe] { outline: none; box-shadow: 0 0 0 3px var(--accent-soft); border-radius: var(--radius-sm); }

/* Search popover: floats under the trigger; search box pinned, list scrolls. */
.phone-combo__panel[b-khoi2o9obe] {
    position: absolute; top: calc(100% + .4rem); inset-inline-start: 0; z-index: 40;
    width: max-content; min-width: 16rem; max-width: min(22rem, 86vw);
    background: var(--surface); border: 1px solid var(--outline-strong); border-radius: var(--radius-sm);
    padding: .5rem; display: flex; flex-direction: column; gap: .4rem;
}
.phone-combo__search[b-khoi2o9obe] {
    width: 100%; box-sizing: border-box; font-family: inherit; font-size: 1rem;
    color: var(--text-primary); background: var(--bg);
    border: 1px solid var(--outline); border-radius: var(--radius-pill); padding: .55rem .9rem;
}
.phone-combo__search:focus[b-khoi2o9obe] { outline: none; border-color: var(--accent-line); box-shadow: 0 0 0 3px var(--accent-soft); }
.phone-combo__search[b-khoi2o9obe]::placeholder { color: var(--text-disabled); }
.phone-combo__list[b-khoi2o9obe] { list-style: none; margin: 0; padding: 0; overflow-y: auto; max-height: 15rem; }
.phone-combo__option[b-khoi2o9obe] {
    display: flex; align-items: center; gap: .6rem; cursor: pointer;
    padding: .5rem .6rem; border-radius: var(--radius-sm); font-size: .92rem; color: var(--text-primary);
}
.phone-combo__option:hover[b-khoi2o9obe], .phone-combo__option.is-active[b-khoi2o9obe] { background: var(--accent-soft); color: var(--accent); }
.phone-combo__option[hidden][b-khoi2o9obe] { display: none; }
.phone-combo__opt-flag[b-khoi2o9obe] { font-size: 1.1rem; line-height: 1; }
.phone-combo__opt-name[b-khoi2o9obe] { flex: 1 1 auto; min-width: 0; }
.phone-combo__opt-code[b-khoi2o9obe] { color: var(--text-secondary); font-variant-numeric: tabular-nums; }
.phone-combo__list[b-khoi2o9obe]  .phone-combo__empty { padding: .6rem; color: var(--text-secondary); font-size: .9rem; text-align: center; }

/* National number: frameless — the group owns the frame, divider and focus ring. The vertical rhythm
   (clamp middle term in vh) is the SAME the Join card used — now the field default so the control is
   identical on every form and still scales down on short viewports. */
.phone-input[b-khoi2o9obe]  .phone-input__number {
    flex: 1 1 auto; min-width: 0;
    border: none; outline: none; background: transparent; color: var(--text-primary);
    font-family: inherit; font-size: .95rem; padding: clamp(.5rem, 1.5vh, .8rem) .95rem;
}
.phone-input[b-khoi2o9obe]  .phone-input__number::placeholder { color: var(--text-disabled); }
@media (max-width: 360px) {
    .phone-combo[b-khoi2o9obe]  .phone-combo__native, .phone-combo__trigger[b-khoi2o9obe] { padding-inline: .7rem .6rem; }
}
/* /Layout/AppFooter.razor.rz.scp.css */
/* Shared app footer — brand row on the public shell, single discreet line inside the portal.
   Rendered full-width by the layouts; the inner wrapper carries the content column and the hairline. */

.app-foot__inner[b-2oq4vl1ztl] {
    max-width: 1140px;
    margin: 0 auto;
    padding: 2rem var(--chrome-gap) 2.5rem;
    border-top: 1px solid var(--outline);
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: .75rem;
}

.app-foot__brand[b-2oq4vl1ztl] { margin-bottom: .5rem; }
.app-foot__note[b-2oq4vl1ztl] { color: var(--text-secondary); font-size: .85rem; }
.app-foot__links[b-2oq4vl1ztl] { display: flex; gap: 1rem; }
.app-foot__links a[b-2oq4vl1ztl] { color: var(--text-secondary); font-size: .85rem; text-decoration: underline; }
.app-foot__links a:hover[b-2oq4vl1ztl] { color: var(--accent); }
.app-foot__version[b-2oq4vl1ztl] { color: var(--text-secondary); font-size: .75rem; opacity: .7; margin-top: .25rem; }

/* ---------- compact (portal, launch, onboarding) ---------- */
.app-foot--compact .app-foot__inner[b-2oq4vl1ztl] {
    padding: 1.5rem var(--chrome-gap) 1rem;
    justify-content: center;
    gap: .5rem;
}

.app-foot--compact .app-foot__name[b-2oq4vl1ztl] { color: var(--text-secondary); font-size: .8rem; }
.app-foot--compact .app-foot__links[b-2oq4vl1ztl] { gap: .5rem; }
.app-foot--compact .app-foot__links a[b-2oq4vl1ztl] { font-size: .8rem; text-decoration: none; }
.app-foot--compact .app-foot__links a:hover[b-2oq4vl1ztl] { text-decoration: underline; }
.app-foot--compact .app-foot__version[b-2oq4vl1ztl] { margin-top: 0; }

.app-foot--compact .app-foot__inner > * + *[b-2oq4vl1ztl]::before,
.app-foot--compact .app-foot__links a + a[b-2oq4vl1ztl]::before {
    content: "·";
    margin-inline-end: .5rem;
    opacity: .55;
}
/* /Layout/MainLayout.razor.rz.scp.css */
/* Sticky footer for the static shell: .portal-canvas only sets min-height (and is shared with the
   portal MudLayout, which must not become a flex column), so the column lives on this class. */
.shell-canvas[b-xbz1mq6hbn] { display: flex; flex-direction: column; }
.shell-body[b-xbz1mq6hbn] { flex: 1 0 auto; }

#blazor-error-ui[b-xbz1mq6hbn] {
    color-scheme: light only;
    background: lightyellow;
    bottom: 0;
    box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
    box-sizing: border-box;
    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-xbz1mq6hbn] {
        cursor: pointer;
        position: absolute;
        right: 0.75rem;
        top: 0.5rem;
    }
/* /Pages/Portals/Merchant/Dashboard/Sections/PlanSummarySection.razor.rz.scp.css */
/* Plan spotlight feature rows — tokens only, no hard-coded colour. */

.plan-feature[b-ftl9nxa0ol] {
    display: flex;
    align-items: flex-start;
    gap: .5rem;
    padding: .2rem 0;
}

.plan-feature[b-ftl9nxa0ol]  .mud-icon-root {
    flex: none;
    margin-top: .15rem;
}

.plan-feature__lead[b-ftl9nxa0ol] { font-weight: 600; }
.plan-feature__detail[b-ftl9nxa0ol] { color: var(--text-secondary); }

/* What the Growth plan itself buys, kept visible to the owner paying for it. */
.plan-feature--exclusive .plan-feature__lead[b-ftl9nxa0ol] { color: var(--accent); }
/* /Pages/Portals/Scan/Tabs/ScanRewardTab.razor.rz.scp.css */
/* Scan & reward — component-scoped CSS (.razor.css). Tokens only (custom.css).
   ::deep reaches the MudIcon root (child-component output) for the result icons. */

/* Scan result panel — border colour flips by outcome via a state class. */
.scan-result[b-i9s1mtlme0] {
    border: 1px solid var(--outline);
    border-radius: var(--radius);
    padding: 1.1rem 1.2rem;
    background: var(--surface-2);
}
.scan-result--ok[b-i9s1mtlme0] { border-color: var(--accent-line); }
.scan-result--err[b-i9s1mtlme0] { border-color: var(--error); }

/* Big gradient points delta. */
.scan-points[b-i9s1mtlme0] { font-size: 1.6rem; }

/* Outcome icons (size + colour) — MudIcon renders its own root, so reach it with ::deep. */
.scan-result[b-i9s1mtlme0]  .scan-ico-ok { color: var(--success); font-size: 2.4rem; }
.scan-result[b-i9s1mtlme0]  .scan-ico-err { color: var(--error); font-size: 2rem; }

/* Camera scanner — the third-party BlazorBarcodeScanner <BarcodeReader> renders its own
   video + source <select> + Start/Stop/Torch buttons. Give those library-rendered controls
   the Bento look via ::deep, without touching the component itself. */
.scan-cam[b-i9s1mtlme0] { display: flex; flex-direction: column; align-items: center; gap: 1rem; text-align: center; }
.scan-cam[b-i9s1mtlme0]  video {
    width: 100%; max-width: 360px; height: auto;
    border-radius: var(--radius-sm); border: 1px solid var(--outline); background: var(--bg);
}
.scan-cam[b-i9s1mtlme0]  select {
    width: 100%; max-width: 360px; box-sizing: border-box;
    background-color: var(--field-fill); color: var(--text-primary);
    border: none; border-radius: var(--radius-input) var(--radius-input) 0 0;
    box-shadow: inset 0 -1px 0 0 var(--outline-strong);
    padding: .65rem .9rem; font-family: inherit; font-size: .95rem;
}
.scan-cam[b-i9s1mtlme0]  button {
    display: inline-flex; align-items: center; justify-content: center; gap: .4rem;
    margin: .15rem .3rem; padding: .55rem 1.1rem;
    border-radius: var(--radius-pill); border: 1px solid var(--outline-strong);
    background: transparent; color: var(--text-primary);
    font-family: inherit; font-weight: 600; font-size: .88rem; cursor: pointer;
    transition: background .15s ease, border-color .15s ease, color .15s ease;
}
.scan-cam[b-i9s1mtlme0]  button:hover { background: var(--surface-2); border-color: var(--accent-line); color: var(--accent); }
/* /Pages/Public/Join/JoinPage.razor.rz.scp.css */
/* ============================================================
   Join (customer enrollment) — component-scoped CSS (.razor.css).
   Public static-SSR page. Tokens only (defined in wwwroot/css/custom.css).
   Mobile-first & viewport-aware: the card is meant to be filled in
   WITHOUT scrolling on phones/tablets, so vertical rhythm scales with
   the viewport HEIGHT (clamp middle term in vh) on top of width-based
   fluid sizing. ::deep reaches into child-component / framework-input
   output (the acc-* inputs, PhoneNumberInput, native radios).
   ============================================================ */

.join-wrap[b-088qro0ocd] {
    width: 100%; max-width: 460px; margin-inline: auto; box-sizing: border-box;
    /* Even gap on all four sides so the card floats evenly framed, even on the narrowest phone. */
    padding: clamp(.85rem, 4.5vmin, 1.6rem);
    /* Centre vertically; 'safe' falls back to top-aligned + scrollable when the form is taller than
       the screen, so the top never clips. */
    min-height: 100dvh; display: flex; flex-direction: column; justify-content: safe center;
}

/* Card that holds the hero + body: clip the banner to the card radius. */
.join-card[b-088qro0ocd] { overflow: hidden; padding: 0; }

/* Hero banner — background comes from the injected --join-hero-bg custom property
   (per-card colour / gradient, or banner image under the shared scrim). */
.join-hero[b-088qro0ocd] {
    background: var(--join-hero-bg, var(--ai-gradient));
    background-size: cover; background-position: center;
    padding: clamp(.85rem, 2.4vh, 1.7rem) clamp(1.1rem, 4vw, 1.5rem);
    color: var(--on-accent);
}
.join-hero__row[b-088qro0ocd] { display: flex; align-items: center; gap: .8rem; flex-wrap: wrap; }
.join-hero__logo[b-088qro0ocd] { max-height: clamp(30px, 5vh, 40px); max-width: 110px; height: auto; object-fit: contain; }
.join-hero__titles[b-088qro0ocd] { min-width: 0; }
.join-hero__biz[b-088qro0ocd] { font-family: "Outfit", sans-serif; font-weight: 600; font-size: clamp(1rem, 3.5vw, 1.15rem); line-height: 1.2; }
.join-hero__card[b-088qro0ocd] { font-size: .82rem; opacity: .9; }
.join-hero__reward[b-088qro0ocd] { margin-top: clamp(.45rem, 1.6vh, .9rem); font-size: clamp(.82rem, 3vw, .92rem); opacity: .95; }

.join-body[b-088qro0ocd] { padding: clamp(.95rem, 2.6vh, 1.6rem) clamp(1.2rem, 5vw, 1.6rem); }

/* Message cards (not found / success) — coloured icon via ::deep into MudIcon. */
.join-msg-ico[b-088qro0ocd]  .mud-icon-root { color: var(--text-secondary); }
.join-msg-ico--ok[b-088qro0ocd]  .mud-icon-root { color: var(--success); }

/* Intro block: margins collapse on short screens so the form rises into view. */
.join-intro[b-088qro0ocd] { margin-bottom: clamp(.7rem, 2.2vh, 1rem); }
.join-intro .eyebrow[b-088qro0ocd] { margin-bottom: .15rem; }
.join-intro__title[b-088qro0ocd] { margin-bottom: .15rem; }
.join-intro__lede[b-088qro0ocd] { margin-bottom: 0; line-height: 1.35; }

/* Form rhythm overrides — shrink field gaps / input padding with viewport height. */
.join-body[b-088qro0ocd]  .acc-form { gap: clamp(.55rem, 1.8vh, 1.1rem); }
.join-body .acc-row[b-088qro0ocd] { gap: clamp(.6rem, 2.5vw, 1.1rem); }
.join-body .acc-field[b-088qro0ocd] { gap: clamp(.25rem, .9vh, .45rem); }
.join-body[b-088qro0ocd]  .acc-input { padding: clamp(.5rem, 1.5vh, .8rem) .95rem; }
/* The phone number field carries this same vh rhythm as its own default (.phone-input__number in
   wwwroot/css/custom.css), so no Join-side override is needed here. */
.join-body .acc-btn[b-088qro0ocd] { padding: clamp(.6rem, 1.8vh, .8rem) 1.4rem; }

/* Wallet picker: a native radio segmented control (no JS) — the two options share the width evenly. */
.join-wallet[b-088qro0ocd] { display: flex; gap: .6rem; }
.join-wallet__opt[b-088qro0ocd] {
    flex: 1 1 0; display: flex; align-items: center; justify-content: center; gap: .5rem;
    border: 1px solid var(--outline); border-radius: var(--radius-pill);
    padding: clamp(.5rem, 1.5vh, .7rem) 1rem; cursor: pointer; font-weight: 600; font-size: .9rem; color: var(--text-secondary);
    transition: border-color .18s ease, background .18s ease, color .18s ease;
}
.join-wallet__opt:hover[b-088qro0ocd] { border-color: var(--outline-strong); }
.join-wallet__opt:has(input:checked)[b-088qro0ocd] { border-color: var(--accent-line); background: var(--accent-soft); color: var(--accent); }
.join-wallet[b-088qro0ocd]  input[type="radio"] { accent-color: var(--accent); }

/* Consent block (Law 09-08): native checkboxes, no JS — required privacy consent + optional
   marketing opt-in. Same quiet tone as helper copy so the form stays scannable. */
.join-consent[b-088qro0ocd] { display: flex; flex-direction: column; gap: clamp(.35rem, 1.2vh, .6rem); }
.join-consent__opt[b-088qro0ocd] {
    display: flex; align-items: flex-start; gap: .55rem; cursor: pointer;
    font-size: .82rem; line-height: 1.35; color: var(--text-secondary);
}
.join-consent__opt[b-088qro0ocd]  input[type="checkbox"] {
    accent-color: var(--accent); margin-top: .15rem; flex-shrink: 0;
}
.join-consent__opt a[b-088qro0ocd] { color: var(--accent); text-decoration: underline; }
.join-consent__cndp[b-088qro0ocd] { margin: 0; font-size: .72rem; color: var(--text-secondary); opacity: .8; }

/* Detected-platform confirmation pill (read-only — no choice to make). */
.join-wallet-detected[b-088qro0ocd] {
    display: flex; align-items: center; gap: .5rem;
    border: 1px solid var(--outline); border-radius: var(--radius-pill);
    padding: clamp(.5rem, 1.5vh, .7rem) 1rem; font-weight: 600; font-size: .9rem; color: var(--text-secondary);
}
/* Keeps the pre-selected platform in the POST without showing the chooser. */
.join-wallet-hidden[b-088qro0ocd] { display: none; }

@media (max-width: 380px) {
    .join-hero__logo[b-088qro0ocd] { max-height: 34px; }
}

/* Very short viewports (landscape phones, small tablets in split view): drop the optional helper copy
   and tighten the hero so the required fields + CTA still fit on one screen. */
@media (max-height: 560px) {
    .join-intro__lede[b-088qro0ocd] { display: none; }
    .join-hero__reward[b-088qro0ocd] { display: none; }
}

/* ---------- Finish pass (pure CSS — the page stays fully static SSR) ----------
   Resting look unchanged: motion only on load, focus ring only on keyboard focus,
   dip only on press. Honours prefers-reduced-motion. */
.join-wrap .card[b-088qro0ocd] { animation: join-rise-b-088qro0ocd .5s cubic-bezier(.22, 1, .36, 1) both; }

@keyframes join-rise-b-088qro0ocd {
    from { opacity: 0; transform: translateY(14px); }
    to   { opacity: 1; transform: translateY(0); }
}

/* Keyboard focus mirrors the .acc-input focus ring (same accent tokens). */
.join-body .acc-btn:focus-visible[b-088qro0ocd],
.join-wallet__opt:has(:focus-visible)[b-088qro0ocd] {
    outline: none; border-color: var(--accent-line);
    box-shadow: 0 0 0 3px var(--accent-soft);
}

/* A 1px dip confirms the tap with no layout shift. */
.join-body .acc-btn--primary:active[b-088qro0ocd],
.join-wallet__opt:active[b-088qro0ocd] { transform: translateY(1px); }

@media (prefers-reduced-motion: reduce) {
    .join-wrap .card[b-088qro0ocd] { animation: none; }
    .join-body .acc-btn--primary:active[b-088qro0ocd],
    .join-wallet__opt:active[b-088qro0ocd] { transform: none; }
}
