﻿/* The --brand-* tokens are declared once in brand.css and driven by the brand's Theme
   document; they are NOT redefined here. Only page-local tokens live below. */
:root {
    /* Chained through the brand tokens — same values --brand-text / --brand-border default to, so
       this is pixel-identical until a brand sets TextColor / BorderColor. See menu.css. */
    --text: var(--brand-text, #1a1a1a);
    --muted: #6b6b6b;
    --border: var(--brand-border, #E5E7EB);
}

* { box-sizing: border-box; }

html, body {
    margin: 0;
    padding: 0;
    height: 100%;
    font-family: 'Roboto', 'Segoe UI', system-ui, -apple-system, 'Helvetica Neue', Arial, sans-serif;
    color: var(--text);
    background: #fff;
}

.auth-shell {
    min-height: 100vh;
    width: 100%;
    margin: 0;
    padding: 0;
}

.auth-card {
    width: 100%;
    min-height: 100vh;
    background: #fff;
    display: grid;
    grid-template-columns: 1fr 1fr;
    border-radius: 0;
    box-shadow: none;
    overflow: hidden;
}

/* The auth-page side panel. By default it is painted in the brand's primary colour — NOT a
   hardcoded photo — so every brand gets an on-brand auth screen out of the box. A brand that sets
   Theme.AuthBanner gets that image instead: _AuthLayout emits a scoped override that sets
   background-image (see there). Keeping the default here (rather than in the layout) means the
   panel is still brand-correct even if that override is ever absent. */
.auth-image {
    background-color: var(--brand-primary, #5e2a2a);
    background-image: none;
    background-size: cover;
    background-position: center;
    background-repeat: no-repeat;
    min-height: 100vh;
}

.auth-form {
    padding: 40px 56px;
    display: flex;
    flex-direction: column;
    justify-content: center;
    max-width: 460px;
    margin: 0 auto;
    width: 100%;
    min-height: 100vh;
}

.auth-logo {
    display: flex;
    justify-content: center;
    margin-bottom: 24px;
}

/* Theme.FooterLogoHeight IS the auth logo's height — each merchant sizes it for its own aspect
   ratio, and it's honoured at every breakpoint (the form column has room / scrolls, so a tall logo
   keeps its height on phones too). width:auto + max-width + object-fit:contain keep the aspect
   ratio and never crop or stretch; centred by object-position. Unset, it falls back to 38px, so an
   unconfigured brand renders exactly as before.

   The FOOTER token, not the header one. This panel is not compact chrome: the logo sits alone above
   the form with the whole column to itself, so it reads as a brand statement rather than a bar
   item, and the header figure leaves it looking undersized. GNS renders at its 108px rather than
   62px. That is the reverse of an earlier call here, which sized it from the header token for
   consistency with the site chrome — the panel is different enough that it gets its own answer.
   Both tokens are brand-authored, so a merchant that wants a smaller login logo tunes the footer
   height it already controls. */
.auth-logo img {
    height: var(--brand-footer-logo-height, 38px);
    width: auto;
    max-width: 100%;
    object-fit: contain;
    object-position: center;
    display: block;
}

.auth-logo-fallback {
    font-size: 1.625rem;
    font-weight: 700;
    color: var(--brand-red);
    letter-spacing: -0.5px;
    font-style: italic;
}

.auth-title {
    font-size: 1.375rem;
    font-weight: 700;
    text-align: center;
    margin: 0 0 8px 0;
}

.auth-subtitle {
    text-align: center;
    color: var(--muted);
    font-size: 0.875rem;
    margin: 0 0 28px 0;
    line-height: 1.5;
}

.auth-fields {
    display: flex;
    flex-direction: column;
    gap: 16px;
}

/* Inline form error — used by Login/SignUp/Otp pages for Firebase / network failures. */
.auth-error {
    margin: 4px 0 0;
    padding: 8px 10px;
    border-radius: 6px;
    /* Tint + border derived from the same token as the text, so the whole pill rebrands together
       instead of danger-red text sitting in a brand-red box. Literals first as the fallback. */
    background: rgba(226, 27, 34, 0.08);
    background: color-mix(in srgb, var(--brand-danger) 8%, transparent);
    border: 1px solid rgba(226, 27, 34, 0.25);
    border: 1px solid color-mix(in srgb, var(--brand-danger) 25%, transparent);
    color: var(--brand-danger, #b91c1c);
    font-size: 0.8125rem;
    line-height: 1.4;
}

/* Inline redirect link rendered alongside the error text (e.g. "Phone no. is not register. Sign Up"). */
.auth-error-link {
    color: var(--brand-danger, #b91c1c);
    font-weight: 600;
    text-decoration: underline;
}

.auth-error-link:hover,
.auth-error-link:focus {
    text-decoration: none;
}

/* Terms & conditions consent. Wrapped in a <label> so the whole line is the hit target — the box
   itself is a 16px tap area, which fails WCAG's 24px minimum on touch. align-items:flex-start
   keeps the box level with the FIRST line when the text wraps to two or three. */
.auth-terms {
    display: flex;
    align-items: flex-start;
    gap: 8px;
    margin: 2px 0 0;
    font-size: 0.8125rem;
    line-height: 1.45;
    color: var(--muted, #6b7280);
    cursor: pointer;
}

.auth-terms input[type="checkbox"] {
    /* flex-shrink:0 stops the box being squeezed to a sliver by the long label beside it. The
       small top margin optically centres it against the first line's cap height. */
    flex: 0 0 auto;
    width: 16px;
    height: 16px;
    margin: 2px 0 0;
    accent-color: var(--brand-primary, #e21b22);
    cursor: pointer;
}

.auth-terms a {
    color: var(--brand-primary, #e21b22);
    font-weight: 600;
    text-decoration: none;
}

.auth-terms a:hover,
.auth-terms a:focus {
    text-decoration: underline;
}

.field {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.field label {
    font-size: 0.8125rem;
    font-weight: 500;
    color: var(--text);
}

.field input,
.select-wrap select {
    width: 100%;
    height: 44px;
    padding: 0 14px;
    border: 1px solid var(--border);
    border-radius: 8px;
    font-size: 0.875rem;
    color: var(--text);
    background: #fff;
    outline: none;
    transition: border-color 0.15s ease, box-shadow 0.15s ease;
    font-family: inherit;
}

.field input::placeholder {
    color: #bdbdbd;
}

.field input:focus,
.select-wrap select:focus {
    border-color: var(--brand-red);
    /* Focus ring derives from the same token as the border, so it can't stay red under a brand
       that themes its primary. Literal first for engines without color-mix(). */
    box-shadow: 0 0 0 3px rgba(226, 27, 34, 0.12);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--brand-red) 12%, transparent);
}

/* ── Combined dial-code + number control (Login) ──────────────────────────────────────────
   One row under a single "Phone no." label: a compact bordered pill for the dial code and the
   number field beside it, each its own box with its own radius and focus ring.

   Sizing, radius and focus ring are taken from .field input above rather than the reference's
   own values, so the control reads as native to this site instead of transplanted.

   NOT used by SignUp, which keeps .select-wrap — do not merge the two rule sets. */
.phone-combo {
    display: flex;
    align-items: stretch;
    gap: 10px;
    height: 44px;
}

.phone-cc-wrap {
    position: relative;
    display: inline-flex;
    align-items: center;
    flex: 0 0 auto;
    border: 1px solid var(--border);
    border-radius: 8px;
    background: #fff;
    transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

/* The real <select>, stretched invisibly across the pill. INVISIBLE, NOT display:none — this
   deployment serves brands in several countries (GNS is India, +91), so the picker must stay
   operable. Transparent TEXT rather than opacity:0: the browser paints the OPEN dropdown as part
   of the select, and a zero-opacity select renders a ghosted, unreadable popup. The closed state
   is hidden by the transparent text (the face draws the code instead) while the popup stays
   opaque — but the options must restate their colours, or they inherit transparent-on-transparent
   in the open list. A native select also auto-sizes to its widest option (+971), which is why the
   face, not the select, decides the pill's width. */
.phone-combo .phone-cc {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    margin: 0;
    padding: 0;
    border: 0;
    background: transparent;
    color: transparent;
    appearance: none;
    -webkit-appearance: none;
    font-family: inherit;
    font-size: 0.875rem;
    cursor: pointer;
    outline: none;
}

.phone-combo .phone-cc option {
    color: var(--text);
    background: #fff;
}

/* What the customer actually sees. pointer-events:none so taps fall through to the select. */
.phone-cc-face {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    padding: 0 9px 0 13px;
    font-family: inherit;
    font-size: 0.875rem;
    line-height: 1;
    color: var(--text);
    white-space: nowrap;
    pointer-events: none;
}

.phone-cc-caret {
    flex: 0 0 auto;
    width: 0;
    height: 0;
    border-left: 4px solid transparent;
    border-right: 4px solid transparent;
    border-top: 5px solid #6b6b6b;
}

.phone-combo .phone-num {
    flex: 1 1 auto;
    min-width: 0;
    width: auto;
    height: 100%;
}

/* Keyboard users focus the select itself, so the ring has to live on the wrapper. :focus-within
   rather than :focus — the focused element is the transparent select inside it. */
.phone-cc-wrap:focus-within {
    border-color: var(--brand-red);
    /* Same token as the border. Literal first for engines without color-mix(). */
    box-shadow: 0 0 0 3px rgba(226, 27, 34, 0.12);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--brand-red) 12%, transparent);
}

/* Invalid: the typed digits and the dial code turn red alongside the message below. The code is
   drawn by the face, not the transparent select, so it is the face that gets recoloured. */
.phone-combo.is-invalid .phone-cc-face,
.phone-combo.is-invalid .phone-num {
    color: var(--brand-danger, #b91c1c);
}

.phone-combo.is-invalid .phone-cc-caret {
    border-top-color: var(--brand-danger, #b91c1c);
}
/* ── One dial code: a label, not a control ─────────────────────────────────────────────────────
   Login.cshtml renders no <select> at all when a brand offers a single code, so there is nothing
   to open, focus or tap. The pill keeps its size and border so the row does not shift; it loses
   the caret (no longer rendered) and the pointer, and its padding is balanced now that nothing
   sits on the right. */
.phone-cc-wrap--fixed {
    cursor: default;
}

.phone-cc-wrap--fixed .phone-cc-face {
    padding: 0 13px;
}

/* ── More than one: a real picker ──────────────────────────────────────────────────────────────
   The select used to open the browser's native list, which Chromium sizes to the SELECT — here a
   ~60px pill — so the options came out squashed under a hard OS highlight bar, overlapping the
   terms line below. Customizable select (appearance: base-select) turns that list into a styled
   panel anchored under the pill.

   Scoped twice, on purpose:
     • @supports — an engine without it keeps the native list, untouched.
     • (hover: hover) and (pointer: fine) — DESKTOP only. On a phone the OS picker (the iOS wheel,
       the Android dialog) is the better control for this, full-width and thumb-sized, so touch
       devices are left on it rather than handed a small in-page panel.

   Both the select AND ::picker(select) need the appearance, or the panel does not activate. */
@supports (appearance: base-select) {
    @media (hover: hover) and (pointer: fine) {
        .phone-combo .phone-cc,
        .phone-combo .phone-cc::picker(select) {
            appearance: base-select;
        }

        /* The face already draws the caret; base-select would add a second one inside the pill. */
        .phone-combo .phone-cc::picker-icon {
            display: none;
        }

        .phone-combo .phone-cc::picker(select) {
            margin-top: 6px;
            min-width: 168px;
            padding: 6px;
            border: 1px solid var(--border);
            border-radius: 10px;
            background: #fff;
            box-shadow: 0 12px 28px rgba(0, 0, 0, 0.14);
        }

        /* The select's own text is transparent (the face draws the closed state), and options
           inherit it — so the colour is restated here, exactly as the native rule above does. */
        .phone-combo .phone-cc option {
            display: flex;
            align-items: center;
            gap: 10px;
            min-height: 40px;
            padding: 0 12px;
            border-radius: 6px;
            color: var(--text);
            background: transparent;
            font-size: 0.9375rem;
            cursor: pointer;
        }

        .phone-combo .phone-cc option:hover,
        .phone-combo .phone-cc option:focus-visible {
            background: #f4f5f7;
            outline: none;
        }

        .phone-combo .phone-cc option:checked {
            font-weight: 600;
        }

        /* The tick for the current code, moved to the trailing edge and brand-coloured. */
        .phone-combo .phone-cc option::checkmark {
            order: 1;
            margin-left: auto;
            color: var(--brand-red);
        }
    }
}

/* Login's validation message is plain red text directly under the combined control — a tinted,
   bordered callout there reads as a third input. Every other auth page keeps the .auth-error pill. */
.auth-error.auth-error-plain {
    margin-top: 6px;
    padding: 0;
    background: none;
    border: 0;
}

.select-wrap {
    position: relative;
}

.select-wrap select {
    appearance: none;
    -webkit-appearance: none;
    padding-right: 36px;
    cursor: pointer;
}

.select-wrap .chev {
    position: absolute;
    right: 14px;
    top: 50%;
    width: 10px;
    height: 10px;
    border-right: 2px solid #6b6b6b;
    border-bottom: 2px solid #6b6b6b;
    transform: translateY(-75%) rotate(45deg);
    pointer-events: none;
}

.btn-primary {
    margin-top: 8px;
    width: 100%;
    height: 46px;
    border: 0;
    border-radius: 8px;
    background: var(--brand-button, var(--brand-red));
    color: var(--brand-secondary, #fff);
    font-size: 0.9375rem;
    font-weight: 600;
    cursor: pointer;
    transition: background 0.15s ease, transform 0.05s ease;
    font-family: inherit;
}

.btn-primary:hover { background: var(--brand-red-hover); }
.btn-primary:active { transform: translateY(1px); }

/* Busy state for the auth buttons — the circular ring the rest of the app already uses for an
   in-button wait (.loc-locate.is-loading in stores.css), brought to auth.css because this
   stylesheet had no spinner of its own and the OTP page only swapped the label to "Verifying…".

   :disabled is what actually blocks a second press; this class is only the appearance, so the two
   are always set together and a browser that ignores ::after still gets a dead button. */
.btn-primary.is-loading {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 10px;
    cursor: default;
}

.btn-primary.is-loading::after {
    content: '';
    flex: 0 0 auto;
    width: 16px;
    height: 16px;
    border: 2px solid rgba(255, 255, 255, 0.4);
    /* currentColor, so the ring follows --brand-secondary rather than assuming white ink. */
    border-top-color: currentColor;
    border-radius: 50%;
    animation: auth-btn-spin 0.7s linear infinite;
}

.btn-primary:disabled { opacity: 0.85; cursor: default; }

@keyframes auth-btn-spin { to { transform: rotate(360deg); } }

/* Respect the OS setting, as .chk-verify-spinner does: still reads as busy, without rotating. */
@media (prefers-reduced-motion: reduce) {
    .btn-primary.is-loading::after {
        animation: auth-btn-pulse 1.4s ease-in-out infinite;
    }
    @keyframes auth-btn-pulse { 50% { opacity: 0.35; } }
}

.auth-alt-link {
    display: block;
    text-align: center;
    margin-top: 18px;
    font-size: 0.875rem;
    font-weight: 600;
    color: var(--text);
    text-decoration: none;
}

.auth-alt-link:hover { text-decoration: underline; }

/* OTP — fluid row that fits any phone width.
   Each box uses flex:1 so the row always fills the available space,
   capped at 56 px so on tablets the boxes don't grow huge. The gap
   shrinks with the viewport via clamp() so all 6 boxes always fit. */
.otp-row {
    display: flex;
    gap: clamp(6px, 2vw, 14px);
    justify-content: center;
    margin: 8px 0 6px;
    width: 100%;
}

.otp-box {
    flex: 1 1 0;
    min-width: 0;
    max-width: 56px;
    aspect-ratio: 1 / 1;
    width: auto;
    height: auto;
    border: 1px solid var(--border);
    border-radius: 8px;
    text-align: center;
    font-size: clamp(16px, 4.6vw, 22px);
    font-weight: 600;
    color: var(--text);
    outline: none;
    background: #fff;
    transition: border-color 0.15s ease, box-shadow 0.15s ease;
    font-family: inherit;
    padding: 0;
    box-sizing: border-box;
}

.otp-box:focus {
    border-color: var(--brand-red);
    /* Same token as the border. Literal first for engines without color-mix(). */
    box-shadow: 0 0 0 3px rgba(226, 27, 34, 0.12);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--brand-red) 12%, transparent);
}

.resend {
    text-align: center;
    margin: 16px 0 0;
    font-size: 0.8125rem;
    color: var(--muted);
}

/* ---------------------------------------------------------
   Responsive breakpoints
   --------------------------------------------------------- */

/* Large laptop / small desktop (<= 1280px): tighten form padding */
@media (max-width: 1280px) {
    .auth-form {
        padding: 32px 48px;
        max-width: 440px;
    }
}

/* Tablet landscape (<= 1024px): still split, more compact */
@media (max-width: 1024px) {
    .auth-form {
        padding: 28px 36px;
        max-width: 400px;
    }
    .auth-title { font-size: 1.25rem; }
    /* .otp-box sizing is now fluid via flex + clamp() above — no override. */
}

/* Tablet portrait & large phones (<= 820px): stack vertically */
@media (max-width: 820px) {
    .auth-shell {
        display: flex;
    }
    .auth-card {
        /* minmax(0, 1fr), NOT 1fr: a bare 1fr is minmax(AUTO, 1fr), and the auto minimum will not
           shrink below the content's min-content width. The OTP row is six boxes plus gaps plus
           the form's padding — 328px — so on a 320px phone the card clipped 8px of itself. The
           boxes themselves are already flex:1 1 0 with min-width:0, so they shrink to fit as soon
           as the track stops holding the form open. */
        grid-template-columns: minmax(0, 1fr);
        min-height: auto;
    }
    /* The same auto-minimum one level down — a grid ITEM defaults to min-width:auto too. */
    .auth-form {
        min-width: 0;
    }
    .auth-image {
        /*        min-height: 240px;
        height: 32vh;
        max-height: 320px;*/
        display: none;
    }
    .auth-form {
        min-height: auto;
        padding: 36px 32px 48px;
        max-width: 520px;
    }
    .auth-logo { margin-bottom: 20px; }
}

/* Mobile (<= 560px) */
@media (max-width: 560px) {
    .auth-image {
        min-height: 200px;
        height: 28vh;
        max-height: 260px;
    }
    .auth-form {
        padding: 28px 20px 40px;
    }
    .auth-logo { margin-bottom: 18px; }
    .auth-title { font-size: 1.1875rem; }
    .auth-subtitle { font-size: 0.8125rem; margin-bottom: 22px; }
    .field input,
    .select-wrap select { height: 44px; }
    .btn-primary { height: 46px; font-size: 0.9375rem; }
    /* .otp-row gap and .otp-box sizing flow from the fluid defaults above. */
}

/* Small phones (<= 380px) */
@media (max-width: 380px) {
    .auth-image {
        min-height: 160px;
        height: 24vh;
        max-height: 200px;
    }
    .auth-form { padding: 24px 16px 32px; }
    /* .otp-row gap and .otp-box sizing flow from the fluid defaults above. */
    .otp-box {
        max-width: 44px;
    }
}

/* Short, wide viewports.

   TWO DIFFERENT THINGS LAND HERE, and only one of them is a landscape phone. `orientation` is the
   VIEWPORT's aspect ratio, not the device's — so a portrait iPhone whose viewport has been
   shortened by the on-screen keyboard (375x310) reads as landscape just like a rotated one does.
   Both want the same treatment: content packed towards the top, so the focused field is reachable
   in whatever height is left. */
@media (orientation: landscape) and (max-height: 520px) and (max-width: 900px) {
    .auth-form {
        padding: 20px 28px;
        justify-content: flex-start;
    }
    .auth-logo { margin-bottom: 12px; }
    .auth-subtitle { margin-bottom: 16px; }
    .auth-fields { gap: 10px; }
}

/* The split hero — but ONLY at the widths where the hero still exists.

   Below 821px the stacking rule above sets .auth-image to display:none, and a hidden element is
   not a grid item. Restoring `1fr 1fr` there therefore reserved half the width for a track with
   nothing in it and squeezed the form into the other half: on a keyboard-open iPhone the form
   went from 375px to 188px, the number field from 267px to 55px, and the six OTP boxes to 16px
   each. That reads as the page having zoomed — which is how it was reported — when the page is
   in fact still at scale 1 and simply a third as wide as it should be. The rule predates the
   image being hidden (its fossil sits commented out in the 820px block above).

   The two height rules stay with the hero they size: 100vh on a column that isn't painted is
   meaningless, and on .auth-form it made the form a nested viewport-height scroller, so the page
   itself could not scroll to reveal Verify / Resend once the keyboard covered them. */
@media (orientation: landscape) and (max-height: 520px) and (min-width: 821px) and (max-width: 900px) {
    .auth-card { grid-template-columns: 1fr 1fr; }
    .auth-image {
        min-height: 100vh;
        height: 100vh;
        max-height: none;
    }
    .auth-form {
        min-height: 100vh;
        overflow-y: auto;
    }
}

/* Touch-input refinements: prevent iOS auto-zoom on focused inputs.

   max(16px, 1rem), NOT 1rem. iOS zooms the page when a focused field's text measures under 16
   CSS px, so this threshold is an ABSOLUTE one — but rem is the single unit on this site that
   isn't absolute: a11y.css anchors the root at `calc(16px * var(--a11y-scale))` for the
   accessibility text-size control, and its "Smaller" level (0.875) resolved 1rem to 14px. The
   guard against zoom was written in the one unit the zoom-relevant setting rescales, so it
   silently stopped guarding for the customers most likely to be relying on it.

   max() keeps both halves: never below iOS's threshold, and still scaling up with Larger /
   Larger 2 (18.4px / 21.6px) so the text-size control still does something to these fields. */
@media (hover: none) and (pointer: coarse) {
    .field input,
    .select-wrap select,
    .otp-box {
        font-size: max(16px, 1rem);
    }
    /* The combo's own children need naming: .phone-combo .phone-cc / .phone-cc-face set their
       own font-size and out-specify the generic .field input rule above, so without this iOS
       still auto-zooms when the dial-code picker takes focus. (.phone-num sets no font-size of
       its own, so it is already covered by .field input.) */
    .phone-combo .phone-cc,
    .phone-cc-face {
        font-size: max(16px, 1rem);
    }
}
