/* Shared auth layer for login.html and signup.html.
 *
 * These two pages are self-contained — they do not link style.css — so the
 * design tokens, interaction rules, and accessibility handling they need live
 * here rather than being duplicated in each page's <style>.
 *
 * IMPORTANT: link this AFTER the page's own <style> block. It intentionally
 * overrides base rules (.form-input:focus, .submit-btn, .bg-img, .form-panel
 * and others). Loading it earlier silently reverts them.
 */

/* ── Design tokens ─────────────────────────────────────────
   These pages are self-contained (they never link style.css), so
   the site's tokens and accessibility rules have to live here too. */
:root {
    --accent: #0ea5e9;
    --accent-2: #6366f1;
    --accent-3: #8b5cf6;
    --ink: #0f172a;
    --ease: cubic-bezier(0.4, 0, 0.2, 1);
    --dur-fast: 0.15s;
    --dur-mid: 0.25s;
    --dur-slow: 0.4s;

    /* Movement lives as tokens so reduced-motion can zero it in one
       place — see the guard at the end of this sheet. */
    --lift-1: -3px;
    --press: 0.97;
    --nudge-1: 4px;
}

/* ── Numerals ──────────────────────────────────────────── */
input {
    font-variant-numeric: tabular-nums;
}

/* ── Motion ────────────────────────────────────────────── */
@keyframes authRise {
    from { opacity: 0; transform: translateY(16px); }
    to   { opacity: 1; transform: translateY(0); }
}

@keyframes panelDrift {
    0%   { transform: scale(1.05) translate3d(0, 0, 0); }
    50%  { transform: scale(1.11) translate3d(-1.5%, -1.5%, 0); }
    100% { transform: scale(1.05) translate3d(0, 0, 0); }
}

@keyframes logoFloat {
    0%, 100% { transform: translateY(0); }
    50%      { transform: translateY(-6px); }
}

@keyframes meshShift {
    0%, 100% { background-position: 0% 50%, 100% 50%; }
    50%      { background-position: 30% 20%, 70% 80%; }
}

/* The side image is wrapped in <picture> to skip the download on phones and
   offer WebP elsewhere. A picture box is an inline element and would become a
   flex item of .side-panel; display:contents removes it so the absolutely
   positioned .bg-img sits against the panel exactly as before. */
picture {
    display: contents;
}

/* The side image drifts instead of sitting dead still. */
.bg-img {
    animation: panelDrift 30s var(--ease) infinite;
    will-change: transform;
}

.logo-box {
    animation: logoFloat 4.5s var(--ease) infinite;
    transition: background var(--dur-mid) var(--ease),
                transform var(--dur-mid) var(--ease);
}

.logo-box:hover {
    background: rgba(255, 255, 255, 0.22);
}

/* Ambient colour behind the form, so it isn't a flat slate field. */
.form-panel {
    background-color: #f8fafc;
    background-image:
        radial-gradient(38rem 38rem at 8% -10%, rgba(14, 165, 233, 0.16), transparent 60%),
        radial-gradient(32rem 32rem at 100% 105%, rgba(139, 92, 246, 0.14), transparent 62%);
    background-repeat: no-repeat;
    animation: meshShift 18s var(--ease) infinite;
}

/* Form rises in, field by field. */
.form-header,
.form-group,
.submit-btn,
.bottom-link,
.form-error,
.forgot-link {
    animation: authRise 0.55s var(--ease) backwards;
}

.form-header  { animation-delay: 0.05s; }
.form-group:nth-of-type(1) { animation-delay: 0.12s; }
.form-group:nth-of-type(2) { animation-delay: 0.19s; }
.form-group:nth-of-type(3) { animation-delay: 0.26s; }
.form-group:nth-of-type(4) { animation-delay: 0.33s; }
.submit-btn   { animation-delay: 0.40s; }
.bottom-link  { animation-delay: 0.47s; }

.side-content > * {
    animation: authRise 0.7s var(--ease) backwards;
}

.side-content > *:nth-child(1) { animation-delay: 0.1s; }
.side-content > *:nth-child(2) { animation-delay: 0.22s; }
.side-content > *:nth-child(3) { animation-delay: 0.34s; }

/* ── Interaction ───────────────────────────────────────── */

/* Fields answer the pointer before they're focused, and the label
   picks up the accent while its field is active. */
.form-input {
    transition: border-color var(--dur-mid) var(--ease),
                box-shadow var(--dur-mid) var(--ease),
                background var(--dur-mid) var(--ease),
                transform var(--dur-fast) var(--ease);
}

.form-input:hover:not(:focus) {
    border-color: #cbd5e1;
}

.form-input:focus {
    border-color: var(--accent);
    box-shadow: 0 0 0 3px rgba(14, 165, 233, 0.16);
}

.form-group:focus-within .form-label {
    color: var(--accent);
}

.form-label {
    transition: color var(--dur-mid) var(--ease);
}

/* ── Custom select (select.css) ─────────────────────────
   select.css defaults to the dashboard's larger fields. Re-size the trigger
   to match the inputs on these pages, and map the few palette tokens it
   expects that the auth pages don't define. */
.cs {
    --cs-radius: 6px;
    --cs-pad-y: 10px;
    --cs-pad-x: 14px;
    --cs-font: 0.9rem;

    --border-color: #cbd5e1;
    --border-hover: #94a3b8;
    --field-bg: transparent;   /* .form-input here is transparent */
    --text-main: #1a1a1a;
    --text-muted: #94a3b8;
    --accent-primary: var(--accent);
    --nav-active-text: var(--accent);
    --info-bg: rgba(14, 165, 233, 0.16);
    --bg-surface: #fff;
    --shadow-lg: 0 16px 34px -6px rgba(15, 23, 42, 0.18);
    --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
}

/* The panel is portalled to <body>, so it sits outside .cs and can't inherit
   the tokens above — it needs them here too. */
.cs-panel {
    --text-main: #1a1a1a;
    --text-muted: #94a3b8;
    --accent-primary: var(--accent);
    --nav-active-text: var(--accent);
    --border-color: #e2e8f0;
    --bg-surface: #fff;
    --shadow-lg: 0 16px 34px -6px rgba(15, 23, 42, 0.18);
    --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
}

/* ── Phone field with country flag ─────────────────────── */
.phone-field {
    position: relative;
    display: flex;
    align-items: center;
}

/* Room for the flag so the number never runs under it. */
.phone-field .form-input {
    padding-left: 54px;
}

.phone-flag {
    position: absolute;
    left: 1px;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 4px;
    width: 46px;
    height: calc(100% - 2px);
    border-radius: 10px 0 0 10px;
    border-right: 1px solid #e2e8f0;
    pointer-events: none;
    user-select: none;
    transition: border-color var(--dur-mid) var(--ease);
}

.phone-field:focus-within .phone-flag {
    border-right-color: var(--accent);
}

.phone-flag img {
    display: block;
    width: 22px;
    height: 16px;
    border-radius: 2px;
    object-fit: cover;
    box-shadow: 0 0 0 1px rgba(15, 23, 42, 0.12);
    animation: flagIn var(--dur-mid) var(--ease);
}

/* Shown until a country code is recognised, and if the image fails. */
#signup-flag-code {
    font-size: 0.8rem;
    font-weight: 700;
    color: #94a3b8;
    letter-spacing: 0.02em;
}

@keyframes flagIn {
    from { opacity: 0; transform: scale(0.7); }
    to { opacity: 1; transform: scale(1); }
}

@media (prefers-reduced-motion: reduce) {
    .phone-flag img { animation: none; }
}

/* ── Password visibility toggle ────────────────────────── */
.input-with-toggle {
    position: relative;
    display: flex;
    align-items: center;
}

/* Leave room for the button so long values never run under it. */
.input-with-toggle .form-input {
    padding-right: 46px;
}

.pw-toggle {
    position: absolute;
    right: 6px;
    width: 34px;
    height: 34px;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    border: none;
    border-radius: 7px;
    background: transparent;
    color: #94a3b8;
    cursor: pointer;
    transition: color var(--dur-mid) var(--ease),
                background var(--dur-mid) var(--ease),
                transform var(--dur-fast) var(--ease);
}

.pw-toggle:hover {
    color: var(--accent);
    background: rgba(14, 165, 233, 0.1);
}

.pw-toggle:active {
    transform: scale(var(--press));
    transition-duration: 0.06s;
}

.pw-toggle:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 1px;
}

/* Catch-all so any button added later presses in like the rest of the site.
   The named rules above still win where they set their own transform. */
button {
    transition: transform var(--dur-fast) var(--ease),
                background var(--dur-mid) var(--ease),
                color var(--dur-mid) var(--ease),
                border-color var(--dur-mid) var(--ease);
}

button:active:not(:disabled) {
    transform: scale(var(--press));
    transition-duration: 0.06s;
}

/* Show the eye by default; swap to the struck-through eye once the
   password is visible. State lives on aria-pressed so the button
   stays accessible and the CSS has a single source of truth. */
.pw-toggle .pw-icon-hide { display: none; }
.pw-toggle[aria-pressed="true"] .pw-icon-show { display: none; }
.pw-toggle[aria-pressed="true"] .pw-icon-hide { display: block; }
.pw-toggle[aria-pressed="true"] { color: var(--accent); }

/* Submit lifts, presses, and sweeps its gradient. */
.submit-btn {
    position: relative;
    overflow: hidden;
    background: linear-gradient(135deg, #0f172a 0%, #1e293b 50%, #0f172a 100%);
    background-size: 200% 100%;
    transition: transform var(--dur-fast) var(--ease),
                box-shadow var(--dur-mid) var(--ease),
                background-position var(--dur-slow) var(--ease),
                opacity var(--dur-mid) var(--ease);
}

.submit-btn:hover:not(:disabled) {
    transform: translateY(var(--lift-1));
    box-shadow: 0 12px 26px -8px rgba(15, 23, 42, 0.55);
    background-position: 100% 0;
}

.submit-btn:active:not(:disabled) {
    transform: translateY(0) scale(var(--press));
    transition-duration: 0.06s;
}

.submit-btn:disabled {
    opacity: 0.6;
    cursor: not-allowed;
    transform: none !important;
}

/* Links: sliding underline rather than a bare colour change. */
.bottom-link a,
.forgot-link {
    position: relative;
    display: inline-block;
    transition: color var(--dur-mid) var(--ease);
}

.bottom-link a::after,
.forgot-link::after {
    content: '';
    position: absolute;
    left: 0;
    bottom: -2px;
    width: 100%;
    height: 1.5px;
    background: currentColor;
    transform: scaleX(0);
    transform-origin: right;
    transition: transform var(--dur-mid) var(--ease);
}

.bottom-link a:hover::after,
.forgot-link:hover::after {
    transform: scaleX(1);
    transform-origin: left;
}

/* ── Focus ─────────────────────────────────────────────────
   :focus-visible only fires for keyboard/AT users. */
:where(a, button, input, select, textarea, [tabindex]):focus {
    outline: none;
}

:where(a, button, [tabindex]):focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 3px;
    border-radius: 6px;
}

.form-input:focus-visible {
    outline: none;
}

/* ── Reduced motion ────────────────────────────────────────
   Zeroing the movement tokens neutralises every rule that uses them
   at once, so rules added later stay covered. Infinite loops are
   stopped outright rather than run at 0.01ms. */
@media (prefers-reduced-motion: reduce) {

    *,
    *::before,
    *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
        scroll-behavior: auto !important;
    }

    :root {
        --lift-1: 0px;
        --press: 1;
        --nudge-1: 0px;
    }

    /* Keep the scale, or the backdrop pops back and letterboxes. */
    .bg-img {
        animation: none !important;
        transform: scale(1.05);
    }

    .logo-box,
    .form-panel {
        animation: none !important;
    }

    .bottom-link a:hover::after,
    .forgot-link:hover::after {
        transform: scaleX(1);
    }
}

/* ── Touch ─────────────────────────────────────────────────
   Both pages are forms, so how they behave under a thumb is most of how they
   behave. This block is at the foot of the file, after the rules it adjusts. */

html {
    /* iOS paints its own grey-blue box over anything tappable, which lands on
       top of the control's own :active styling and reads as a rendering fault.
       A faint neutral of our own keeps the "you hit it" feedback. */
    -webkit-tap-highlight-color: rgba(15, 23, 42, 0.08);
}

@media (max-width: 900px) {
    /* Under 16px, iOS zooms the page in when a field takes focus and does not
       zoom back out when it loses it. Signup's fields were all 0.9rem, so
       registering meant the page zooming on the first tap and staying that way
       for the remaining six. Set on the element rather than per-page so a field
       added later inherits the floor. */
    .form-input,
    input,
    select,
    textarea {
        font-size: 16px;
    }

    /* 34px square is under the ~44px a thumb hits reliably, and this one sits
       inside the field it belongs to, so a near miss puts the cursor in the
       password instead of revealing it.

       Size only — no top/transform. .input-with-toggle is a centring flex
       container, which already places this absolute child on the vertical
       centre, and .pw-toggle:active sets its own transform for the press:
       centring with translateY here would be dropped the moment it was
       tapped, and the button would jump. */
    .pw-toggle {
        width: 44px;
        height: 44px;
        right: 2px;
    }

    /* Keeps a long password clear of the wider button. */
    .input-with-toggle .form-input {
        padding-right: 52px;
    }

    /* "Sign in" / "Sign up" — the way across to the other page, and a 16px-tall
       target sitting in a line of ordinary text. inline-block so the padding
       becomes height rather than being ignored. */
    .bottom-link a,
    .forgot-link {
        display: inline-block;
        padding: 12px 8px;
    }

    /* The sliding underline is anchored to the box (bottom:-2px, left:0, full
       width), so the padding above would leave it floating ~14px under the
       text and running wider than it. Pulled back onto the text. */
    .bottom-link a::after,
    .forgot-link::after {
        bottom: 10px;
        left: 8px;
        width: calc(100% - 16px);
    }
}

/* ── Scrollbars ───────────────────────────────────────────────────────
   The platform default is a wide grey trough that takes no notice of the page
   it sits in and changes character between Windows, macOS and Linux. A faint
   slate pill, inset from the edge so it rests in the gutter rather than
   cutting a channel into the layout. Same values as the dashboard and the
   admin panel, so the whole site scrolls alike. */
:root {
    --scrollbar-thumb: rgba(100, 116, 139, 0.38);
    --scrollbar-thumb-hover: rgba(100, 116, 139, 0.62);
}

/* Firefox has only ever had these, and Chrome takes them from 121; where a
   platform uses overlay scrollbars it keeps that behaviour, which is the
   polite outcome on a trackpad. */
* {
    scrollbar-width: thin;
    scrollbar-color: var(--scrollbar-thumb) transparent;
}

/* The page's own scrollbar gets a real colour rather than a transparent one.
   Its gutter sits outside the area the body's background paints, so
   "transparent" there is not the page showing through — it is whatever the
   browser puts behind the document, which is white. Panels inside the page
   keep the transparent track from the rule above, where it does sit on the
   surface behind it. Colour is the form panel's colour; the auth pages have no body background of their own. */
html {
    scrollbar-color: var(--scrollbar-thumb) #f8fafc;
}

html::-webkit-scrollbar-track {
    background: #f8fafc;
}

/* The same thing spelled for older Chrome and Safari. */
::-webkit-scrollbar {
    width: 12px;
    height: 12px;
}

::-webkit-scrollbar-track {
    background: transparent;
}

::-webkit-scrollbar-thumb {
    background-color: var(--scrollbar-thumb);
    border-radius: 999px;
    /* A transparent border clipped to the content box is what insets the pill.
       Without it the thumb fills all 12px and reads as a bar again. */
    border: 3px solid transparent;
    background-clip: content-box;
    transition: background-color 0.25s ease;
}

::-webkit-scrollbar-thumb:hover {
    background-color: var(--scrollbar-thumb-hover);
}

::-webkit-scrollbar-corner {
    background: transparent;
}

/* Chrome on Windows puts a stepper arrow at each end the moment the scrollbar
   is styled at all — they do not appear on the unstyled default, so leaving
   this out trades a plain scrollbar for a slim one wearing two grey triangles. */
::-webkit-scrollbar-button {
    display: none;
}
