/* TypingPlanet login theme -- re-skins keycloak.v2 (PatternFly 5) to match the app's own dark
   chrome (app/src/main/resources/static/css/chrome.css :root palette) without touching any of its
   FTL templates. Class names below (kcButtonPrimaryClass, kcFormLabelTextClass, ...) come straight
   from keycloak.v2/login/theme.properties -- see this theme's own theme.properties for how the two
   stylesheets stack. */

:root {
  --tp-bg: #0b0d11;
  --tp-bg-elevated: #171b21;
  --tp-bg-inset: #10141a;
  --tp-text: #e8eaed;
  --tp-text-muted: #9aa4b2;
  --tp-border: #262c35;
  --tp-border-strong: #343b46;
  --tp-accent: #7c5cff;
  --tp-accent-hover: #9179ff;
  --tp-accent-secondary: #22d3ee;
  --tp-error: #f87171;
  --tp-warning: #fbbf24;
  --tp-success: #34d399;
  --tp-radius: 10px;
  --tp-radius-sm: 6px;
  --tp-font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  --tp-font-mono: "JetBrains Mono", ui-monospace, "Cascadia Code", "Segoe UI Mono", Consolas, "Liberation Mono", Menlo, monospace;

  /* Overrides the parent stylesheet's own custom property (keycloak.v2/login/css/styles.css) so
     no flash of Keycloak's default background image is visible before the planet/starfield rule
     below (which replaces the rest of that same selector's properties directly) paints over it. */
  --keycloak-bg-logo-url: none;
}

/* Self-hosted, same four weights and same reasoning as the main app's own chrome.css: the header
   wordmark below is the only place on this login theme set in --tp-font-mono, so it's the only
   weight this page's request needs at all -- 700 (see #kc-header-wrapper's font-weight). */
@font-face {
  font-family: "JetBrains Mono";
  src: url("../fonts/jetbrains-mono/JetBrainsMono-Bold.woff2") format("woff2");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

html,
body {
  height: 100%;
}

body {
  font-family: var(--tp-font-sans);
  color: var(--tp-text);
  color-scheme: dark;
  -webkit-font-smoothing: antialiased;
}

/* --- Planet/starfield backdrop --------------------------------------------------------------
   Layered radial-gradients, no image asset: a soft purple/cyan nebula glow top-left, a glowing
   "typing planet" with a thin halo ring bottom-right, scattered stars on a small repeating tile,
   over a near-black base -- same visual language as the app's own accent-glow dots
   (.side-nav__brand::before, main section h2::before in chrome.css), just scaled up into a scene. */
.login-pf body {
  background-color: var(--tp-bg);
  background-image:
    /* stars -- a 240x240 tile of small dots, repeated */
    radial-gradient(1.4px 1.4px at 20px 30px, rgba(255, 255, 255, 0.65), transparent),
    radial-gradient(1px 1px at 70px 90px, rgba(255, 255, 255, 0.45), transparent),
    radial-gradient(1.6px 1.6px at 130px 40px, rgba(255, 255, 255, 0.55), transparent),
    radial-gradient(1px 1px at 170px 120px, rgba(255, 255, 255, 0.4), transparent),
    radial-gradient(1.2px 1.2px at 40px 160px, rgba(255, 255, 255, 0.5), transparent),
    radial-gradient(1px 1px at 200px 200px, rgba(255, 255, 255, 0.4), transparent),
    radial-gradient(1.4px 1.4px at 110px 210px, rgba(255, 255, 255, 0.55), transparent),
    radial-gradient(1px 1px at 220px 60px, rgba(255, 255, 255, 0.4), transparent),
    /* nebula glows */
    radial-gradient(ellipse 900px 700px at 12% 15%, rgba(124, 92, 255, 0.18), transparent 60%),
    radial-gradient(ellipse 700px 600px at 90% 10%, rgba(34, 211, 238, 0.12), transparent 55%),
    /* the planet: halo ring, then the disc itself */
    radial-gradient(circle 300px at 88% 85%, transparent 54%, rgba(124, 92, 255, 0.4) 55.5%, transparent 58%),
    radial-gradient(circle 255px at 88% 85%, #8a6bff 0%, #4a35a8 45%, #221a4d 75%, transparent 100%);
  background-repeat: repeat, repeat, repeat, repeat, repeat, repeat, repeat, repeat, no-repeat, no-repeat, no-repeat, no-repeat;
  background-size: 240px 240px, 240px 240px, 240px 240px, 240px 240px, 240px 240px, 240px 240px, 240px 240px, 240px 240px, auto, auto, auto, auto;
  /* Explicit, not left to inherit whatever the parent stylesheet's own `background` shorthand
     (keycloak.v2/login/css/styles.css) last set on this same selector -- longhand declarations
     here only override the sub-properties they name, so background-position would otherwise
     silently carry over from that earlier rule. */
  background-position: 0 0;
  background-attachment: fixed;
  height: 100%;
}

/* --- Header / brand -----------------------------------------------------------------------
   realm.displayNameHtml renders here -- "TypingPla<span class=\"tp-caret\"></span><span
   class=\"tp-untyped\">net</span>" (allowed through kcSanitize's span/class allowlist,
   KeycloakSanitizerPolicy), so the wordmark itself reads as "TypingPla" already typed, a
   blinking cursor, then "net" still to type -- the exact "type here" cue the app's own
   practice-text caret/pending-character convention uses (chrome.css's .practice-char--pending
   and its caret rule), rather than a generic caret merely trailing the whole word. Mirrors the
   app sidebar's own brand mark (.side-nav__brand::before) with the same solid accent dot. */
#kc-header-wrapper {
  text-transform: none !important;
  letter-spacing: -0.01em !important;
  font-family: var(--tp-font-mono) !important;
  font-size: 1.6rem !important;
  font-weight: 700 !important;
  color: var(--tp-text) !important;
  display: inline-flex;
  align-items: center;
  white-space: nowrap !important;
}

/* Margin on the dot itself, not `gap` on the wrapper -- the wordmark's own text node, .tp-caret
   and .tp-untyped are each separate children of this same flex container (a flex container's
   text-node children count as anonymous flex items too), so `gap` would space every one of them
   apart from its neighbors, not just the dot from the wordmark that follows it. */
#kc-header-wrapper::before {
  content: "";
  width: 10px;
  height: 10px;
  margin-right: 3px;
  flex: 0 0 auto;
  border-radius: 50%;
  background: var(--tp-accent);
  box-shadow: 0 0 12px 2px color-mix(in srgb, var(--tp-accent) 55%, transparent);
}

/* The "net" that's not yet "typed" -- same muted color the app's own untyped/pending practice
   text uses (chrome.css's .practice-char--pending), so the wordmark's own visual logic matches
   the product it's the front door for. */
#kc-header-wrapper .tp-untyped {
  color: var(--tp-text-muted);
}

#kc-header-wrapper .tp-caret {
  display: inline-block;
  width: 3px;
  height: 1em;
  margin: 0 1px;
  background: var(--tp-accent-secondary);
  animation: tp-caret-blink 1.1s steps(1) infinite;
}

@keyframes tp-caret-blink {
  50% {
    opacity: 0;
  }
}

@media (prefers-reduced-motion: reduce) {
  #kc-header-wrapper .tp-caret {
    animation: none;
  }
}

/* --- Login card ----------------------------------------------------------------------------
   Same card recipe as the app's own `main section` cards (chrome.css): elevated surface, hairline
   border, soft shadow, rounded corners -- so the card the player signs in on reads as the same UI
   system as the one they land in a moment later. */
.pf-v5-c-login__main {
  background: var(--tp-bg-elevated);
  border: 1px solid var(--tp-border);
  border-radius: var(--tp-radius);
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.4), 0 8px 24px rgba(0, 0, 0, 0.45);
  padding-bottom: 8px;
}

.pf-v5-c-login__main-header {
  border-top: 4px solid transparent;
  border-image: linear-gradient(90deg, var(--tp-accent), var(--tp-accent-secondary)) 1;
  border-radius: var(--tp-radius) var(--tp-radius) 0 0;
}

.pf-v5-c-login__container {
  filter: drop-shadow(0 20px 60px rgba(0, 0, 0, 0.5));
}

.pf-v5-c-title,
#kc-page-title {
  color: var(--tp-text) !important;
  font-weight: 600;
}

.pf-v5-c-login__main-body,
.pf-v5-c-login__main-footer,
.pf-v5-c-form__label-text,
.pf-v5-c-form__label {
  color: var(--tp-text-muted);
}

.pf-v5-c-login__main-footer-helper-text,
.pf-v5-u-color-200 {
  color: var(--tp-text-muted) !important;
}

/* --- Form fields ---------------------------------------------------------------------------
   Matches the app's own input[type="text"]/button rules (chrome.css "Forms & controls" section)
   almost token-for-token, so focus rings, radii and the accent-purple primary action feel
   identical to the rest of the product.

   keycloak.v2 wraps the actual <input> in a bare <span class="pf-v5-c-form-control"> -- the input
   itself carries no class at all. Box styling (background/border/radius) belongs on that span,
   but `color` and every pseudo-class below (:focus, ::placeholder, autofill) only ever match the
   real form control, so they're targeted at the nested input explicitly rather than relying on
   inheritance -- form controls don't inherit `color` from an ancestor the way ordinary elements
   do, so a `color` declared only on the span leaves the input at the browser's own near-black
   default, invisible against the span's now-dark background. */
.pf-v5-c-form-control {
  background: var(--tp-bg-inset) !important;
  border: 1px solid var(--tp-border-strong) !important;
  border-radius: var(--tp-radius-sm) !important;
}

.pf-v5-c-form-control input {
  background: transparent !important;
  color: var(--tp-text) !important;
}

.pf-v5-c-form-control:focus-within {
  border-color: var(--tp-accent) !important;
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--tp-accent) 25%, transparent) !important;
}

.pf-v5-c-form-control input:focus {
  outline: none !important;
}

.pf-v5-c-form-control input::placeholder {
  color: var(--tp-text-muted);
}

/* Chrome/Edge autofill (username/password on login, password on registration -- exactly the
   fields a saved-credential browser autofills) paints its own black-on-transparent text via an
   internal UA style that a plain `color` declaration can't override, no matter how it's
   specified -- only `-webkit-text-fill-color`, plus an inset box-shadow the same color as the
   field background to defeat the autofill's own yellow/light fill, actually wins. Username,
   email, name, and surname on registration are unaffected since browsers don't offer saved
   autofill for those field types the same way. */
/* Split into two rules, not one comma-separated selector list -- an unprefixed :autofill
   selector sitting in the same list as :-webkit-autofill would invalidate the whole rule in any
   browser that doesn't recognize one of the two, since a plain selector list (unlike :is()/
   :where()) isn't forgiving. Targets the nested input, not the .pf-v5-c-form-control span --
   autofill is a state of the actual form control, and a plain wrapping span can never match
   either pseudo-class. */
.pf-v5-c-form-control input:-webkit-autofill,
.pf-v5-c-form-control input:-webkit-autofill:hover,
.pf-v5-c-form-control input:-webkit-autofill:focus {
  -webkit-text-fill-color: var(--tp-text) !important;
  -webkit-box-shadow: 0 0 0 1000px var(--tp-bg-inset) inset !important;
  box-shadow: 0 0 0 1000px var(--tp-bg-inset) inset !important;
  caret-color: var(--tp-text);
  transition: background-color 600000s ease-in-out 0s;
}

.pf-v5-c-form-control input:autofill {
  color: var(--tp-text) !important;
  box-shadow: 0 0 0 1000px var(--tp-bg-inset) inset !important;
  caret-color: var(--tp-text);
}

.pf-v5-c-check__input {
  accent-color: var(--tp-accent);
}

.pf-v5-c-button.pf-m-primary {
  background: var(--tp-accent) !important;
  border-color: var(--tp-accent) !important;
  color: #ffffff !important;
  border-radius: var(--tp-radius-sm) !important;
  font-weight: 600;
  transition: background 0.15s ease, box-shadow 0.15s ease;
}

.pf-v5-c-button.pf-m-primary:hover,
.pf-v5-c-button.pf-m-primary:focus {
  background: var(--tp-accent-hover) !important;
  border-color: var(--tp-accent-hover) !important;
  box-shadow: 0 4px 14px color-mix(in srgb, var(--tp-accent) 35%, transparent);
}

.pf-v5-c-button.pf-m-secondary {
  background: var(--tp-bg-inset) !important;
  border-color: var(--tp-border-strong) !important;
  color: var(--tp-text) !important;
  border-radius: var(--tp-radius-sm) !important;
}

.pf-v5-c-button.pf-m-secondary:hover {
  border-color: var(--tp-accent) !important;
}

.pf-v5-c-button.pf-m-link {
  color: var(--tp-accent) !important;
}

a,
a:link {
  color: var(--tp-accent);
}

a:hover {
  color: var(--tp-accent-hover);
}

/* --- Alerts (error/info banners) ------------------------------------------------------------ */
.pf-v5-c-alert {
  background: var(--tp-bg-inset) !important;
  border-radius: var(--tp-radius-sm);
}

.pf-v5-c-alert.pf-m-danger {
  border-left: 3px solid var(--tp-error);
}

.pf-v5-c-alert.pf-m-danger .pf-v5-c-alert__icon {
  color: var(--tp-error);
}

.pf-v5-c-alert.pf-m-warning {
  border-left: 3px solid var(--tp-warning);
}

.pf-v5-c-alert.pf-m-success {
  border-left: 3px solid var(--tp-success);
}

.pf-v5-c-alert__title {
  color: var(--tp-text) !important;
}

/* --- Language picker + misc small text ------------------------------------------------------ */
#login-select-toggle {
  background: var(--tp-bg-inset);
  color: var(--tp-text);
  border: 1px solid var(--tp-border-strong);
  border-radius: var(--tp-radius-sm);
}

::selection {
  background: color-mix(in srgb, var(--tp-accent) 45%, transparent);
}
