/*
    Auth shell — the split-screen chrome shared by every standalone auth route.

    Imported by: /login (login-page.css) and /register/individual (register-page.css).
    Owns the two-panel grid, the image panel, the font vars, the links, the banner and the motion
    primitives. Fields and the consent checkbox come from the theme, buttons from buttons.css. A
    route's own stylesheet holds ONLY what is genuinely unique to it (login's password/reveal,
    register's sections/phone).

    THESE ROUTES ARE ON-THEME NOW. _AuthLayout loads the Metronic bundle ahead of this file, so
    a form field here is the theme's own field, identical to the internal portal's. This sheet no
    longer carries a field recipe at all; what is left is the shell around the fields, meaning the
    two-panel grid, the image panel, the fonts, the links, the banner and the motion.

    NOTE ON --primary: style.bundle.css declares its own --primary (the theme's blue) on :root,
    so _AuthLayout loads the bundle BEFORE variables.css and the brand purple wins. styles/app.css
    would redefine it again and is deliberately never loaded on these routes.
*/

/*
    ---- Poppins, self-hosted ----
    Declared on the shared shell so every auth route (login + register) has the family available
    without a Google Fonts <link> (CWV/self-host standard) and without duplicating the block per
    route. Declaring a face costs nothing until a route actually applies it via the font vars.
*/
@font-face { font-family: 'Poppins'; font-style: normal; font-weight: 300; font-display: swap; src: url('/fonts/poppins/poppins-300.woff2') format('woff2'); }
@font-face { font-family: 'Poppins'; font-style: normal; font-weight: 400; font-display: swap; src: url('/fonts/poppins/poppins-400.woff2') format('woff2'); }
@font-face { font-family: 'Poppins'; font-style: normal; font-weight: 500; font-display: swap; src: url('/fonts/poppins/poppins-500.woff2') format('woff2'); }
@font-face { font-family: 'Poppins'; font-style: normal; font-weight: 600; font-display: swap; src: url('/fonts/poppins/poppins-600.woff2') format('woff2'); }
@font-face { font-family: 'Poppins'; font-style: normal; font-weight: 700; font-display: swap; src: url('/fonts/poppins/poppins-700.woff2') format('woff2'); }

/* ---- Minimal reset: replaces the global stylesheets these routes intentionally skip ---- */
*,
*::before,
*::after {
    box-sizing: border-box;
}

html,
body {
    margin: 0;
    padding: 0;
}

.auth-page {
    /*
        Josefin is loaded as ONE FAMILY PER WEIGHT (see the @font-face block in
        core/utilities.css), not one family with a weight axis. A real 500 and a real 600 are
        therefore two different families, and `font-weight` alone cannot reach them — it would
        synthesize faux-bold from the Regular face and smear a thin geometric sans. Hence two
        body vars, both reusing the existing variables.css stacks verbatim.
    */
    --page-font-heading: 'Times New Roman', Times, serif;
    --page-font-body: var(--Josefin-medium);           /* real 500 face */
    --page-font-body-strong: var(--Josefin-semiBold);  /* real 600 face */

    --page-ease: cubic-bezier(0.16, 1, 0.3, 1);

    /* Radius scale: input + button 10 / icon 8 / link 4. Nothing above 16. */
    --page-radius-control: 10px;
    --page-radius-icon: 8px;
    --page-radius-link: 4px;

    /* One focus recipe, applied to every focusable control on every auth route. */
    --page-focus-ring: 0 0 0 3px rgba(98, 0, 238, 0.12); /* --primary at 12% */

    font-family: var(--page-font-body);
    color: var(--text-1);
    background-color: var(--white);
}

/* ---- Split screen ---- */
/* dvh, not vh: mobile browser chrome would otherwise push the panel past the viewport. */
.auth-page__grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    min-height: 100dvh;
}

/*
    position:relative is load-bearing, not decoration. It makes the panel the containing block
    for its absolutely-positioned descendants — above all .sr-only, which has auto offsets.
    Without a positioned ancestor those resolve against the INITIAL containing block, so each
    one is painted at its static position deep inside the scrolled form yet counts toward the
    DOCUMENT's scrollable overflow. Twelve of them added ~219px of phantom page scroll on
    /register/individual and put a second scrollbar beside the panel's own.
*/
.auth-page__panel--form {
    position: relative;
    background-color: var(--white);
}

.auth-page__form-col {
    width: 100%;
}

/* ---- Image panel: decorative only, full bleed, never a white void ---- */
/*
    The primary fill sits under the image, so a failed/slow webp shows brand colour rather
    than white-on-white against the form panel.
*/
.auth-page__panel--image {
    position: relative;
    background-color: var(--primary);
    background-image: url('/images/tecnology-services-bg.webp');
    background-size: cover;
    background-position: center;
    background-repeat: no-repeat;
}

/* Scrim: stops the panel competing with the form for attention. */
.auth-page__panel--image::after {
    content: "";
    position: absolute;
    inset: 0;
    background: linear-gradient(180deg,
                rgba(7, 20, 55, 0) 0%,       /* --heading at 0% */
                rgba(7, 20, 55, 0.12) 100%); /* --heading at 12% */
}

/* ---- Brand ---- */
/* Left-aligned: this is a page, not a modal. */
.auth-page__logo {
    display: inline-block;
    margin-bottom: 40px;
}

.auth-page__logo img {
    display: block;
    height: 32px;
    width: auto;
}

/* ---- Header ---- */
.auth-page__title {
    font-family: var(--page-font-heading);
    font-size: 24px;
    font-weight: var(--fw-600);
    letter-spacing: -0.01em;
    color: var(--heading);
    margin: 0 0 10px;
}

/* The one word that carries the brand. Same size, same weight — colour is the only change. */
.auth-page__title-accent {
    color: var(--primary);
}

/* Josefin's x-height is short, so 1.6 rather than the usual 1.5. */
.auth-page__subtitle {
    font-family: var(--page-font-body);
    font-size: 14px;
    font-weight: 500; /* no --fw-500 token exists; the Medium face carries the weight */
    line-height: 1.6;
    color: var(--text-3);
    max-width: 340px;
    margin: 0 0 36px;
}

/* ---- Form-level error: a submit-level fact, never a per-field one ---- */
/*
    Not reserved — it animates open instead. grid-template-rows 0fr -> 1fr is the height
    transition that works on auto-height content.
*/
.auth-page__banner {
    display: grid;
    grid-template-rows: 0fr;
    transition: grid-template-rows 200ms ease, margin-bottom 200ms ease;
    margin-bottom: 0;
}

.auth-page__banner > * {
    overflow: hidden;
}

.auth-page__banner--shown {
    grid-template-rows: 1fr;
    margin-bottom: 24px;
}

.auth-page__banner-inner {
    border: 1px solid rgba(232, 38, 70, 0.2); /* --error-active at 20% */
    border-radius: var(--page-radius-control);
    background-color: var(--error-10);
    padding: 12px 14px;
    font-family: var(--page-font-body);
    font-size: 14px;
    font-weight: 500;
    line-height: 1.6;
    color: var(--error-active);
    margin: 0;
}

/* A collapsed banner must not keep its padding/border visible during the transition. */
.auth-page__banner:not(.auth-page__banner--shown) .auth-page__banner-inner {
    border-width: 0;
    padding-top: 0;
    padding-bottom: 0;
}

/* ---- Fields ---- */
.auth-field {
    display: flex;
    flex-direction: column;
    min-width: 0; /* lets a field shrink inside a grid row instead of overflowing it */
}

/* 600, not 500: Josefin's mid weights read light at label size. */
.auth-field__label {
    font-family: var(--page-font-body-strong);
    font-size: 14px;
    font-weight: var(--fw-600);
    color: var(--text-2);
    margin: 0 0 4px;
}

/*
    Red, not brand: an asterisk is a warning about the field, not a piece of branding.
    The adjacent .sr-only "required" carries the meaning — a bare "*" announces as "star".
*/
.auth-field__req {
    color: var(--error-active);
    margin-left: 4px;
    font-size: 14px;
}

.auth-field__control {
    position: relative;
    display: flex;
}/*
    Reserved slot: 6px gap + 18px min-height, held whether or not an error is showing, so
    validation fires into space that was always there and nothing jumps.
*/
.auth-field__error {
    display: block;
    min-height: 18px;
    margin: 6px 0 0;
    font-family: var(--page-font-body);
    font-size: 12px;
    font-weight: 500;
    letter-spacing: 0.01em;
    line-height: 18px;
    color: var(--error-active);
}

/* ---- Links ---- */
.auth-link {
    font-family: var(--page-font-body-strong);
    color: var(--primary);
    text-decoration: none;
    border-radius: var(--page-radius-link);
}

.auth-link:hover {
    color: var(--primary);
    text-decoration: underline;
    text-underline-offset: 2px;
}

.auth-link:focus {
    outline: none;
}

.auth-link:focus-visible {
    box-shadow: var(--page-focus-ring);
    outline: 2px solid transparent; /* keeps a ring in forced-colors mode */
    outline-offset: 2px;
}

/*
    Legal footer, not a call to action: it reads as body text and only signals its linkness on
    hover/focus, so it never competes with the primary action.
*/


/* ---- Submit ----
   The button itself is `.btn.btn-primary.btn-lg` from the shared components/buttons.css, the same
   classes the dashboard uses. Only the loading spinner's size, colour and duration stay here; its
   shape and keyframe are shared. */
.auth-submit__spinner {
    flex: none; /* a flex sibling of the label, not an overlay — sits before the text */
    width: 16px;
    height: 16px;
    /* Open-ring "loader" look (buttons.css's shared spinner technique): a real gap on three
       sides, not a dimmed continuation. border-top-color lives HERE, not in buttons.css — this
       file loads after it, so a border-top-color declared only there would be clobbered by this
       same rule's own `border` shorthand (see buttons.css's comment on the shared block). */
    border: 2px solid transparent;
    border-top-color: var(--white);
    animation-duration: 600ms;
}

.btn[aria-busy="true"] .auth-submit__spinner {
    display: block;
}

/* ---- Motion primitives: routes bind their own targets + delays ---- */
@keyframes auth-rise {
    from { opacity: 0; transform: translateY(8px); }
    to   { opacity: 1; transform: none; }
}

@keyframes auth-fade {
    from { opacity: 0; }
    to   { opacity: 1; }
}

/* The image sets a mood; it fades, it does not move. */
.auth-page__panel--image {
    animation: auth-fade 400ms ease backwards;
}

/* ---- Accessibility ---- */
/*
    Visually hidden but announced. Used for the "required" beside each asterisk and for the
    <legend> of each section (the eyebrow carries the same words visually).
*/
.sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
}

/* ---- Responsive ---- */
/* The form needs the room more than the image does. */
@media (max-width: 1023px) {
    .auth-page__grid {
        grid-template-columns: 1fr 0.7fr;
    }
}

/*
    Below 768px the image is removed, not stacked: a decorative panel that pushes the form
    below the fold is a real cost with no benefit.
*/
@media (max-width: 767px) {
    .auth-page__grid {
        grid-template-columns: 1fr;
    }

    .auth-page__panel--image {
        display: none;
    }
}

/* ---- Motion is dropped; the states themselves stay ---- */
@media (prefers-reduced-motion: reduce) {
    .auth-page__banner {
        transition: none;
    }

    .auth-submit__spinner {
        animation-duration: 1800ms;
    }
}
