/*
 * The sign-in page (/login), on the WhyData palette.
 *
 * Every colour here is a `--wd-*` token from assets/styles/whydata-tokens.css, which
 * transcribes the pack's own config/ui_tokens.json. No literal colour belongs in this
 * file -- add a token instead, so this page, the three dashboard pages, the chat page and
 * /admin/agent cannot disagree about what "panel" or "risk" means. The only non-token
 * values below are `transparent`, `color-mix(..., transparent)` percentages and geometry
 * (radii, spacing, blur), none of which name a colour.
 *
 * THIS FILE CHANGES NO BEHAVIOUR. The form keeps its action, its method, its `_username`
 * / `_password` field names, its `email` / `password` ids, its `_csrf_token` hidden input
 * and its single submit button. What changed is the palette: the page was stock Bootstrap
 * -- white ground, `btn btn-primary` blue, an unstyled `<div>` for the authentication
 * error -- while every other page in the application has been on this palette since
 * commit 9a94a04. It is the first page a user sees, and it was the last one that still
 * looked like a framework default.
 *
 * WHY A SEPARATE FILE RATHER THAN THE INLINE <style> IT REPLACES.
 * The rules used to live in a `<style>` block inside `{% block body %}`. A file is
 * cacheable, is reachable from the asset map, and carries no inline styling for a future
 * CSP to have to allow. The precedent is assets/styles/dashboard.css, chat-dark.css and
 * agent-config.css, each linked from its own template's `{% block stylesheets %}`. Same
 * wiring here.
 *
 * SCOPED TO `body.login-body`, for the same reason those three are scoped: app.css sets
 * `body { background-color: white }` and the importmap loads it *after* this file, so one
 * class of specificity is what makes load order irrelevant. That same one class also puts
 * these rules above Bootstrap's own (0,1,x) selectors -- bootstrap.min.css is likewise
 * loaded by the importmap, i.e. after this file -- which is why nothing below needs
 * `!important`.
 *
 * The template's `{% block bodyClasses %}` keeps the layout utilities it already carried
 * (`d-flex align-items-center py-4`); `login-body` is added alongside them, not instead
 * of them.
 *
 * LIGHT AND DARK. There is no light mode to support: the application declares one
 * palette. `data-bs-theme` appears nowhere in the project's own stylesheets or templates,
 * and there is no `prefers-color-scheme` rule anywhere in assets/styles/ except vendored
 * Bootstrap. This page therefore commits to the dark palette the rest of the site
 * renders. Where a `--bs-*` variable is repointed below it is declared on both
 * `body.login-body` and `body.login-body [data-bs-theme]`: `[data-bs-theme=dark]`
 * re-declares the whole `--bs-*` set on the element carrying it, and a custom property
 * resolves from the *nearest declaring ancestor* rather than by specificity, so a
 * declaration on `body` alone would silently lose inside any descendant that ever
 * acquired the attribute. This template sets no such attribute today; the second selector
 * costs nothing and stops that from becoming a regression.
 */

body.login-body {
    background-color: var(--wd-background);
    color: var(--wd-text-primary);
    /* ui_tokens.json `typography.font_family`. Sizes stay where Bootstrap puts them;
       naming the family here changes the face and nothing else. */
    font-family: var(--wd-font-family);
    /*
     * Replaces the inline `body { height: 80vh }` this file absorbed. A fixed 80vh left a
     * fifth of the viewport painted by <html> rather than by <body>, which was invisible
     * while the body was white and would have been a pale band under a dark palette.
     * `min-height` also lets the card grow past the fold rather than overflow it -- the
     * error state is one line taller than the resting state, and at 390px wide it wraps.
     * The centring itself is the template's `d-flex align-items-center`, unchanged.
     */
    min-height: 100vh;
}

/*
 * Bootstrap's own custom properties, repointed at the palette rather than fought with
 * `!important`. This is the idiom templates/_partial/main_nav.html.twig already uses for
 * `--bs-navbar-*`, chat-dark.css for `--dt-*` and agent-config.css for these same names.
 *
 * `--bs-body-bg` matters more here than it looks: Bootstrap's floating label paints a
 * strip behind itself with `background-color: var(--bs-body-bg)` so the raised text does
 * not collide with the field's top border. Pointing it at the field fill is what keeps
 * that strip invisible. See `.form-floating > label::after` below, which states it again
 * explicitly rather than relying on this.
 */
body.login-body,
body.login-body [data-bs-theme] {
    --bs-body-bg: var(--wd-panel-deep);
    --bs-body-color: var(--wd-text-primary);
    --bs-body-color-rgb: var(--wd-text-primary-rgb);
    --bs-emphasis-color: var(--wd-text-primary);
    --bs-secondary-color: var(--wd-text-muted);
    --bs-border-color: var(--wd-divider);
    --bs-heading-color: var(--wd-text-primary);
    --bs-link-color: var(--wd-primary-cyan);
    --bs-link-hover-color: var(--wd-text-primary);
}

/* ------------------------------------------------------------------------- the card */

/* Widened from 330px. The card now carries a logo and, in the error state, a wrapped
   message; 330px broke "Invalid credentials." onto a second line beside its icon. At
   390px wide the `w-100` and app.css's `main { margin: 1em }` cap it well below this, so
   the number only takes effect on a screen that has room for it. */
body.login-body .signin-form {
    max-width: 380px;
}

/*
 * The panel idiom the dashboards already use for `.oi-kpi` and `.oi-panel`: the
 * `--wd-panel` -> `--wd-panel-deep` gradient, a 55%-strength divider edge, a 10-12px
 * radius. Reused verbatim rather than invented so that a user arriving at /login and then
 * landing on the Overview page sees the same object twice.
 *
 * CONTRAST NOTE, because a gradient has two grounds and only the darker one is flattering.
 * Everything placed on this card is `--wd-text-primary` (12.3:1 against the light end
 * `--wd-panel`, 16.0:1 against `--wd-panel-deep`) or `--wd-text-muted` (8.5:1 / 11.0:1).
 * `--wd-text-secondary` is deliberately NOT used on the card: against `--wd-panel` it
 * measures 4.35:1, under the 4.5:1 body text needs. It appears in exactly one place in
 * this file -- the field border -- where it sits on `--wd-panel-deep` and is a boundary
 * rather than text.
 *
 * The shadow is the only thing separating card from page at the dark end of the gradient
 * (`--wd-panel-deep` on `--wd-background` is 1.03:1), and it is drawn in
 * `--wd-background-deep`, i.e. the palette's own darkest value rather than a black.
 */
body.login-body .login-card {
    background: linear-gradient(160deg, var(--wd-panel), var(--wd-panel-deep));
    border: 1px solid color-mix(in srgb, var(--wd-divider) 55%, transparent);
    border-radius: 12px;
    padding: 1.75rem 1.5rem 1.6rem;
    box-shadow: 0 18px 44px rgba(var(--wd-background-deep-rgb), 0.55);
}

/* --------------------------------------------------------------------- the brand */

/* One child, the logo, which centres itself with `margin: 0 auto` below -- so this rule
   is spacing only. It previously also carried `text-align: center` for a "NETOPS"
   wordmark that sat under the logo behind a divider rule; both were removed on
   2026-08-09 at the owner's request, and the `text-align` and the
   `.login-brand__app` block went with them rather than being left orphaned. The
   product name still appears in the page <title>, which follows the site-wide
   "<page> | NetOps | WhyData" pattern and is deliberately unchanged. */
body.login-body .login-brand {
    margin-bottom: 1.5rem;
}

/* `whydata-logo-light.svg` is the file templates/_partial/main_nav.html.twig already
   serves in the navbar, chosen over the other four images in public/ for that reason:
   the `-no-tagline` variant, `logo.png`, `logo_old.png` and `whydata-logo.png` are
   referenced by nothing and are pending a delete decision, so referencing one here would
   have quietly settled that decision. `-light` in its name means light-on-dark: its
   wordmark is white with an orange accent, so it needs a dark ground and gets one. It
   carries its own colours and takes nothing from this palette. */
body.login-body .login-brand__logo {
    display: block;
    width: 100%;
    max-width: 190px;
    height: auto;
    margin: 0 auto;
}

body.login-body .login-title {
    color: var(--wd-text-primary);
    text-align: center;
}

/* --------------------------------------------------------------- the error state */

/*
 * The authentication error, which was a bare `<div>` inheriting body text on a white
 * ground -- no border, no tone, no icon, and indistinguishable from the heading beneath
 * it.
 *
 * Built on the application's existing "bordered note whose tone is carried by one edge"
 * idiom (`.oi-notice`, `.chat-status`, and the `.alert` treatment in agent-config.css),
 * with the tint level borrowed from dashboard.css's risk row.
 *
 * The MESSAGE TEXT is `--wd-text-primary`, not `--wd-risk-red`. On this tinted ground red
 * body copy measures 4.83:1 -- over the 4.5:1 line but with almost nothing to spare, and
 * this is the one string on the page a blocked user has to read. `--wd-text-primary` is
 * 14.4:1 there. The tone is carried instead by three signals that are all non-text and so
 * only need 3:1: the left edge, the tint, and the icon, which is `--wd-risk-red` at
 * 4.83:1 against the same ground.
 *
 * `role="alert"` on the element is in the template, not here: it is announced, not
 * painted. What is produced and how it is translated is untouched -- the Twig expression
 * `error.messageKey|trans(error.messageData, 'security')` is byte-identical to before.
 */
body.login-body .login-alert {
    display: flex;
    align-items: flex-start;
    gap: 0.6rem;
    background: color-mix(in srgb, var(--wd-risk-red) 12%, var(--wd-panel-deep));
    border: 1px solid color-mix(in srgb, var(--wd-risk-red) 45%, transparent);
    border-left: 3px solid var(--wd-risk-red);
    border-radius: 6px;
    color: var(--wd-text-primary);
    padding: 0.65rem 0.8rem;
    margin-bottom: 1.1rem;
    font-size: 0.92rem;
    line-height: 1.4;
}

body.login-body .login-alert__icon {
    color: var(--wd-risk-red);
    /* Optical alignment with the first line of the message, which is 0.92rem at 1.4. */
    line-height: 1.4;
    flex: 0 0 auto;
}

/* ------------------------------------------------------------------- the fields */

/* Was `margin-top: 1em; margin-bottom: 1em` in the inline block, which doubled up between
   adjacent fields. One gap, stated once. */
body.login-body .form-floating + .form-floating {
    margin-top: 0.75rem;
}

body.login-body .form-floating:last-of-type {
    margin-bottom: 1.25rem;
}

/*
 * The field idiom `.ev-filter input` already establishes: a well sunk below its panel,
 * filled `--wd-panel-deep`, with the text at `--wd-text-primary` (16.0:1 on that fill).
 *
 * THE BORDER IS `--wd-text-secondary`, NOT `--wd-divider`. A divider-coloured 1px edge on
 * `--wd-panel-deep` measures 2.28:1, under the 3:1 WCAG 1.4.11 asks of a control's
 * boundary, and on a floating-label field the border is the entire affordance -- there is
 * no separate label outside it and, inside `.form-floating`, Bootstrap makes the
 * placeholder transparent, so an invisible border is an invisible input. This is 5.66:1.
 * Same reasoning, same token, as the radio ring in agent-config.css. The card and brand
 * rules above keep `--wd-divider`, because a container edge is decoration.
 */
body.login-body .form-control {
    background-color: var(--wd-panel-deep);
    border-color: var(--wd-text-secondary);
    color: var(--wd-text-primary);
}

/*
 * Bootstrap hardcodes `border-color: #86b7fe` and a `rgba(13,110,253,.25)` box-shadow on
 * `.form-control:focus` -- two of the very few colours in the framework that are not
 * behind a custom property, so they cannot be repointed and have to be restated. Cyan on
 * the field fill is 7.7:1, comfortably past the 3:1 a focus indicator needs.
 */
body.login-body .form-control:focus {
    background-color: var(--wd-panel-deep);
    border-color: var(--wd-primary-cyan);
    color: var(--wd-text-primary);
    box-shadow: 0 0 0 0.2rem rgba(var(--wd-primary-cyan-rgb), 0.3);
}

/* Keyboard focus additionally draws the outline the dashboard uses for every focusable
   control, so the ring survives a forced-colours mode that drops box-shadows. */
body.login-body .form-control:focus-visible {
    outline: 2px solid var(--wd-primary-cyan);
    outline-offset: 1px;
}

/* Resting and raised are the same tone deliberately. `--wd-text-muted` is >= 8.5:1
   against every ground the label can sit on -- the field fill when raised, the card's
   light end if the strip below is ever removed -- whereas differentiating the raised
   state with `--wd-text-secondary` would put small text at 4.35:1 in that second case.
   The 0.85 scale and the translate Bootstrap already applies are the state change. */
body.login-body .form-floating > label {
    color: var(--wd-text-muted);
}

body.login-body .form-floating > .form-control:focus ~ label,
body.login-body .form-floating > .form-control:not(:placeholder-shown) ~ label {
    color: var(--wd-text-muted);
}

/* The strip Bootstrap paints behind the raised label so it does not sit on the field's
   top border. It defaults to `var(--bs-body-bg)`, which the block at the top of this file
   already repoints; naming the field fill here as well means the strip stays seamless
   even if that variable is later given a different job. */
body.login-body .form-floating > .form-control:focus ~ label::after,
body.login-body .form-floating > .form-control:not(:placeholder-shown) ~ label::after {
    background-color: var(--wd-panel-deep);
}

/* Chromium paints its own near-white autofill background over the field via an internal
   `-internal-light-dark` background, which would put `--wd-text-primary` on white. The
   long inset shadow is the standard way to repaint it, and `-webkit-text-fill-color` the
   standard way to keep the glyphs on the palette. Both are prefixed properties with no
   unprefixed equivalent. */
body.login-body .form-control:-webkit-autofill,
body.login-body .form-control:-webkit-autofill:hover,
body.login-body .form-control:-webkit-autofill:focus {
    -webkit-text-fill-color: var(--wd-text-primary);
    -webkit-box-shadow: 0 0 0 1000px var(--wd-panel-deep) inset;
    caret-color: var(--wd-text-primary);
}

/* ------------------------------------------------------------------- the button */

/* The same repointing agent-config.css gives its Save button, so the two pages' primary
   actions are one object. Cyan fill with a `--wd-background-deep` label is 8.4:1; the
   fill against the card's light end is 5.9:1, so the control's own boundary clears 3:1
   without needing a border of its own. */
body.login-body .btn-primary {
    --bs-btn-bg: var(--wd-primary-cyan);
    --bs-btn-border-color: var(--wd-primary-cyan);
    --bs-btn-color: var(--wd-background-deep);
    /* Lightened towards `--wd-text-primary` rather than towards an invented tint, so hover
       introduces no colour of its own. */
    --bs-btn-hover-bg: color-mix(in srgb, var(--wd-primary-cyan) 82%, var(--wd-text-primary));
    --bs-btn-hover-border-color: color-mix(in srgb, var(--wd-primary-cyan) 82%, var(--wd-text-primary));
    --bs-btn-hover-color: var(--wd-background-deep);
    --bs-btn-active-bg: var(--wd-primary-cyan);
    --bs-btn-active-border-color: var(--wd-primary-cyan);
    --bs-btn-active-color: var(--wd-background-deep);
    --bs-btn-focus-shadow-rgb: var(--wd-primary-cyan-rgb);
    --bs-btn-disabled-bg: var(--wd-primary-cyan);
    --bs-btn-disabled-border-color: var(--wd-primary-cyan);
    --bs-btn-disabled-color: var(--wd-background-deep);
    /* `opacity` fades label and fill together against whatever is behind the button, so
       the pair has to be measured composited. Bootstrap's default .65 puts the disabled
       label at 4.38:1 over the card's light end and 4.26:1 over its dark end -- both under
       4.5:1. At .75 they are 5.35:1 and 5.25:1. The template never disables this button;
       the value is stated so that a future "signing in..." state cannot introduce an
       unreadable one, and because a disabled control is exempt from 1.4.3 only for as
       long as it stays disabled. */
    --bs-btn-disabled-opacity: 0.75;
    font-weight: 600;
    letter-spacing: 0.02em;
}

body.login-body .btn:focus-visible {
    outline: 2px solid var(--wd-primary-cyan);
    outline-offset: 2px;
}
