/*
 * The code layer for the auth UI, served at `/assets/auth.css`.
 *
 * It CONSUMES tokens.css and sets no colour of its own: every colour below is a `var(--color-*)`,
 * so a deployment re-themes the whole surface by overriding tokens and touching nothing here.
 * Class names match the `packages/auth-ui` components exactly.
 *
 * There are zero inline styles anywhere in the auth UI (UI-UX csp.md section 5), so every layout
 * value the design expressed as a `style=` attribute has a class in this file. If a screen needs a
 * width or a margin, it gets a modifier here rather than an attribute there.
 *
 * Authored by hand rather than compiled from Tailwind. The auth surface is ~30 screens sharing one
 * small vocabulary, the class names are the contract the design and the components both hold, and
 * a utility pass buys nothing when the markup is server-rendered once. The admin console keeps
 * Tailwind; the two surfaces share the token layer and nothing else (REFACTOR-PLAN F1).
 */

/* ---- Fonts --------------------------------------------------------------
   Self-hosted, same-origin, `font-src 'self'`. Latin and latin-ext only: the auth surface is
   chrome around a person's own name and email, and the rest of the family is 200 KB nobody on
   this screen reads. `font-display: swap` so a slow font never blocks the sign-in form. */

@font-face {
  font-family: 'IBM Plex Sans';
  font-style: normal;
  font-display: swap;
  font-weight: 100 700;
  src: url('/assets/fonts/ibm-plex-sans-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC,
    U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215,
    U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'IBM Plex Sans';
  font-style: normal;
  font-display: swap;
  font-weight: 100 700;
  src: url('/assets/fonts/ibm-plex-sans-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304,
    U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0,
    U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-display: swap;
  font-weight: 400;
  src: url('/assets/fonts/ibm-plex-mono-latin-400.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC,
    U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215,
    U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-display: swap;
  font-weight: 500;
  src: url('/assets/fonts/ibm-plex-mono-latin-500.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC,
    U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215,
    U+FEFF, U+FFFD;
}

/* ---- Reset --------------------------------------------------------------- */

*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  -webkit-text-size-adjust: 100%;
  min-height: 100%;
}

body {
  margin: 0;
  min-height: 100dvh;
  background: var(--color-bg);
  color: var(--color-text);
  font-family: var(--font-sans);
  font-size: var(--font-size-base);
  line-height: var(--line-height-base);
  -webkit-font-smoothing: antialiased;
}

a {
  color: var(--color-link);
  text-decoration-color: color-mix(in oklab, var(--color-link) 35%, transparent);
  text-underline-offset: 2px;
}
a:hover {
  text-decoration-color: currentColor;
}
a:visited {
  color: var(--color-link-visited);
}

:focus-visible {
  outline: var(--focus-ring-width) solid var(--color-focus);
  outline-offset: var(--focus-ring-offset);
  border-radius: var(--radius-sm);
}

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  border: 0;
  clip-path: inset(50%);
  overflow: hidden;
  white-space: nowrap;
}

/* Skip link, revealed on focus. The account shell has a sidebar ahead of its content. */
.skip-link {
  position: absolute;
  left: var(--space-3);
  top: var(--space-3);
  z-index: 20;
  padding: var(--space-2) var(--space-3);
  background: var(--color-surface);
  border: var(--border-width) solid var(--color-border-strong);
  border-radius: var(--radius-md);
  transform: translateY(-200%);
}
.skip-link:focus-visible {
  transform: none;
}

/* ---- Motion and view transitions -----------------------------------------
   The auth flow is a sequence of full-page navigations, so a cross-document view transition is
   the honest way to make it feel continuous: the shell holds still and only the card changes.
   Named elements keep the brand and the footer visually fixed across the navigation, so the eye
   tracks one card moving rather than a whole page repainting.

   All of it sits behind `prefers-reduced-motion: no-preference`, and a browser without
   cross-document transitions simply navigates. Nothing here is load-bearing. */

@media (prefers-reduced-motion: no-preference) {
  @view-transition {
    navigation: auto;
  }

  .auth-brand {
    view-transition-name: auth-brand;
  }
  .auth-footer {
    view-transition-name: auth-footer;
  }
  .auth-card {
    view-transition-name: auth-card;
  }
  .account-sidebar {
    view-transition-name: account-sidebar;
  }
  .account-main {
    view-transition-name: account-main;
  }

  /* The card cross-fades and lifts rather than sliding sideways: the flow moves forward, but a
     sideways slide implies a back button that these screens deliberately do not offer. */
  ::view-transition-old(auth-card) {
    animation: auth-fade-out var(--duration-base) ease both;
  }
  ::view-transition-new(auth-card) {
    animation: auth-rise-in var(--duration-base) ease both;
  }
  ::view-transition-old(account-main) {
    animation: auth-fade-out var(--duration-fast) ease both;
  }
  ::view-transition-new(account-main) {
    animation: auth-rise-in var(--duration-base) ease both;
  }
  /* The persistent chrome is matched by name, so it holds still instead of cross-fading. */
  ::view-transition-group(auth-brand),
  ::view-transition-group(auth-footer),
  ::view-transition-group(account-sidebar) {
    animation-duration: var(--duration-fast);
  }
}

@keyframes auth-fade-out {
  to {
    opacity: 0;
  }
}
@keyframes auth-rise-in {
  from {
    opacity: 0;
    transform: translateY(6px);
  }
}

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    transition-duration: 0ms !important;
    animation-duration: 0ms !important;
  }
}

/* ---- Navigation feedback -------------------------------------------------
   A progress bar for the moment between pressing a link and the next document painting. The
   account area is the surface that needs it: a sidebar link is a full navigation, and without any
   acknowledgement a slow one reads as a dead control and gets clicked again.

   Deliberately indeterminate. We do not know how long the request will take, and a bar that
   pretends to know stalls at 90% and looks more broken than no bar at all. It eases toward the
   right and never arrives, because arriving would be a lie about being finished. */

.nav-progress {
  position: fixed;
  top: 0;
  left: 0;
  height: 2px;
  width: 0;
  z-index: 30;
  background: var(--color-accent);
  animation: nav-progress 8s cubic-bezier(0.1, 0.7, 0.1, 1) forwards;
}
@keyframes nav-progress {
  0% {
    width: 0;
  }
  100% {
    width: 92%;
  }
}
@media (prefers-reduced-motion: reduce) {
  /* Still visible, because it is feedback rather than decoration, but it does not travel. */
  .nav-progress {
    animation: none;
    width: 100%;
    opacity: 0.5;
  }
}

/* ---- Shell -------------------------------------------------------------- */

.auth-shell {
  color: var(--color-text);
  background: var(--color-bg);
  /* Fills the viewport so a short card still paints the page background to the edges, but the
     content stacks from the top: the footer sits under the card rather than at the foot. */
  min-height: 100dvh;
  justify-content: flex-start;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-5);
  padding: var(--space-7) var(--space-4) var(--space-5);
}

.auth-brand {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  width: 100%;
  max-width: var(--max-width-form);
}
.auth-brand__logo {
  height: 24px;
  width: auto;
  display: block;
}
.auth-brand__name {
  font-size: var(--font-size-sm);
  font-weight: var(--font-weight-medium);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--color-text-muted);
}

/*
 * Directly beneath the card, NOT pinned to the bottom of the viewport.
 *
 * It used to carry `margin-top: auto`, which pushed it to the foot of a full-height shell and left
 * a lake of empty space between a short card and the only two controls on the page. The language
 * and the appearance menu belong to the card they sit under, and reading them as page furniture at
 * the bottom of a tall screen made them furniture nobody looked at.
 */
.auth-footer {
  width: 100%;
  max-width: var(--max-width-form);
  padding-top: var(--space-2);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
}
.auth-footer__meta {
  font-size: var(--font-size-sm);
  color: var(--color-text-muted);
  font-variant-numeric: tabular-nums;
}

/* The wide card (consent, S14) widens its chrome to match, so the brand and footer stay flush
   with the card edges instead of floating inside them. */
.auth-shell--wide > .auth-brand,
.auth-shell--wide > .auth-footer {
  max-width: 34rem;
}

/* Appearance menu. A <details> disclosure wrapping a real form, so it opens and submits with no
   JS at all; the island upgrades it to apply without a round trip and to close on Escape or an
   outside click. */
.auth-prefs {
  position: relative;
}
.auth-prefs__button {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 2rem;
  height: 2rem;
  border-radius: var(--radius-md);
  color: var(--color-text-muted);
  cursor: pointer;
  list-style: none;
}
/* The language trigger names the current language, so it is a pill rather than a square icon. */
.auth-prefs__button--wide {
  width: auto;
  gap: var(--space-2);
  padding: 0 var(--space-2);
}
.auth-prefs__current {
  font-size: var(--font-size-sm);
  font-weight: var(--font-weight-medium);
}
.auth-prefs__menu--left {
  right: auto;
  left: 0;
}

.auth-prefs__button::-webkit-details-marker {
  display: none;
}
.auth-prefs__button:hover {
  color: var(--color-text);
  background: var(--color-surface-raised);
}
.auth-prefs[open] .auth-prefs__button {
  color: var(--color-text);
  background: var(--color-surface-raised);
}
.auth-prefs__button svg {
  width: 1.125rem;
  height: 1.125rem;
  display: block;
}

.auth-prefs__menu {
  position: absolute;
  right: 0;
  bottom: calc(100% + var(--space-2));
  z-index: 10;
  min-width: 11rem;
  display: flex;
  flex-direction: column;
  padding: var(--space-1);
  background: var(--color-surface);
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-md);
}
.auth-prefs__item {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  width: 100%;
  padding: var(--space-2) var(--space-3);
  font: inherit;
  font-size: var(--font-size-sm);
  text-align: left;
  color: var(--color-text);
  background: transparent;
  border: 0;
  border-radius: var(--radius-sm);
  cursor: pointer;
}
.auth-prefs__item:hover {
  background: var(--color-surface-raised);
}
.auth-prefs__item::before {
  content: '';
  width: 1rem;
  flex: none;
  color: var(--color-accent);
  font-weight: var(--font-weight-bold);
}
.auth-prefs__item[aria-current='true']::before {
  content: '✓';
}

/* ---- Card --------------------------------------------------------------- */

.auth-card {
  width: 100%;
  max-width: var(--max-width-form);
  background: var(--color-surface);
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-md);
  padding: var(--space-6);
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
}

/*
 * The back affordance, above the heading.
 *
 * Sized down and muted so it reads as chrome rather than as the screen's action: on a card whose
 * whole point is one decision, a back link with the visual weight of a button competes with the
 * thing the person came to do. It keeps a full-size hit target through the padding.
 */
.auth-back {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  align-self: flex-start;
  margin: calc(var(--space-2) * -1) 0 calc(var(--space-3) * -1) calc(var(--space-2) * -1);
  padding: var(--space-2);
  font-size: var(--font-size-sm);
  font-weight: var(--font-weight-medium);
  color: var(--color-text-muted);
  text-decoration: none;
  border-radius: var(--radius-sm);
}
.auth-back:visited {
  color: var(--color-text-muted);
}
.auth-back:hover {
  color: var(--color-text);
  background: var(--color-surface-raised);
}
.auth-back__icon {
  width: 1rem;
  height: 1rem;
  flex: none;
}

.auth-card--wide {
  max-width: 34rem;
}

.auth-card__heading {
  margin: 0;
  font-size: var(--font-size-xl);
  line-height: var(--line-height-tight);
  font-weight: var(--font-weight-bold);
  letter-spacing: -0.015em;
  text-wrap: pretty;
}
/* The wide card carries a client name inside the heading, so it steps down a size to stay on
   two lines rather than three. */
.auth-card__heading--sm {
  font-size: 1.25rem;
}

.auth-copy {
  margin: 0;
  text-wrap: pretty;
}
.auth-copy--muted {
  color: var(--color-text-muted);
  font-size: var(--font-size-sm);
}
.auth-copy + .auth-copy {
  margin-top: var(--space-2);
}

.auth-bullets {
  margin: 0;
  padding-left: 1.1rem;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.auth-hint {
  font-size: var(--font-size-sm);
  color: var(--color-text-muted);
  padding: var(--space-3);
  background: var(--color-surface-raised);
  border-radius: var(--radius-md);
}
.auth-hint[hidden] {
  display: none;
}

.auth-code {
  font-family: var(--font-mono);
  font-size: var(--font-size-sm);
  background: var(--color-surface-raised);
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-sm);
  padding: 0.1em 0.4em;
  user-select: all;
  word-break: break-all;
}

.auth-divider {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  color: var(--color-text-muted);
  font-size: var(--font-size-sm);
}
.auth-divider::before,
.auth-divider::after {
  content: '';
  flex: 1;
  height: var(--border-width);
  background: var(--color-border);
}

/* ---- Lists (sessions, passkeys, applications, connections) -------------- */

.auth-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}
.auth-list__item {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding: var(--space-4);
  background: var(--color-surface);
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-md);
}
.auth-list__item--current {
  border-color: var(--color-border-strong);
}
.auth-list__item form {
  display: block;
}
.auth-list__item .button {
  width: 100%;
  margin-top: var(--space-1);
}
.auth-list__title {
  margin: 0;
  font-size: var(--font-size-base);
  font-weight: var(--font-weight-medium);
  display: flex;
  align-items: center;
  gap: var(--space-2);
  flex-wrap: wrap;
}

.auth-tag {
  font-size: 0.6875rem;
  font-weight: var(--font-weight-medium);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  padding: 0.15em 0.5em;
  border-radius: var(--radius-full);
  background: var(--color-surface);
  border: var(--border-width) solid var(--color-border-strong);
  color: var(--color-text-muted);
}
.auth-tag--current {
  background: var(--color-success-bg);
  border-color: var(--color-success);
  color: var(--color-success-text);
}

/* Overview tiles, S23 */
.auth-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
  gap: var(--space-3);
}
.auth-tile {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  padding: var(--space-4);
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-surface);
  text-decoration: none;
  color: inherit;
  transition:
    border-color var(--duration-fast) ease,
    background var(--duration-fast) ease;
}
.auth-tile:hover {
  border-color: var(--color-border-strong);
  background: var(--color-surface-raised);
}
.auth-tile__label {
  font-weight: var(--font-weight-medium);
  /* The tile is the tightest label on the surface: four of them share the main column, so each gets
     about 143px of text. "Linked accounts" already sits on that boundary and the German
     "Verknüpfte Konten" crosses it, so the wrap is a fact rather than a risk. Balancing it splits
     the two words evenly instead of leaving one orphan under a full line, and a browser without
     `text-wrap` gets the ordinary wrap it would have had. */
  text-wrap: balance;
}
.auth-tile__meta {
  font-size: var(--font-size-sm);
  color: var(--color-text-muted);
}

/* ---- Fields ------------------------------------------------------------- */

.field {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}
.field + .field {
  margin-top: var(--space-4);
}
/* A submit that follows the last field, instead of a `style="margin-top:16px"` on every one. */
.field + .button,
.field + .button-row,
.choice-group + .button,
.choice-group + .button-row {
  margin-top: var(--space-4);
}

.field--narrow {
  max-width: 14rem;
}
.field--medium {
  max-width: 22rem;
}

.field__label {
  font-size: var(--font-size-sm);
  font-weight: var(--font-weight-medium);
  color: var(--color-text);
}
.field__optional {
  color: var(--color-text-muted);
  font-weight: var(--font-weight-normal);
}

.field__input {
  width: 100%;
  font: inherit;
  color: var(--color-text);
  background: var(--color-surface);
  border: var(--border-width) solid var(--color-border-strong);
  border-radius: var(--radius-md);
  padding: var(--space-3) var(--space-3);
  min-height: 2.75rem;
  transition:
    border-color var(--duration-fast) ease,
    box-shadow var(--duration-fast) ease;
}
.field__input::placeholder {
  color: var(--color-text-muted);
}
.field__input:hover {
  border-color: var(--color-text-muted);
}
.field__input:focus-visible {
  border-color: var(--color-focus);
  outline: var(--focus-ring-width) solid var(--color-focus);
  outline-offset: 0;
}
.field__input:disabled {
  background: var(--color-surface-raised);
  color: var(--color-text-muted);
  cursor: not-allowed;
}
.field__input--invalid {
  border-color: var(--color-danger);
}
.field__input--code {
  font-family: var(--font-mono);
  font-size: 1.375rem;
  letter-spacing: 0.35em;
  text-align: center;
  font-variant-numeric: tabular-nums;
}

.field__help {
  margin: 0;
  font-size: var(--font-size-sm);
  color: var(--color-text-muted);
}
.field__error {
  margin: 0;
  font-size: var(--font-size-sm);
  font-weight: var(--font-weight-medium);
  color: var(--color-danger-text);
}
/* The island writes into this and it stays empty on the server, so it must not reserve space. */
.field__error:empty {
  display: none;
}

.field__select {
  width: 100%;
  font: inherit;
  color: var(--color-text);
  background: var(--color-surface);
  border: var(--border-width) solid var(--color-border-strong);
  border-radius: var(--radius-md);
  padding: var(--space-3);
  min-height: 2.75rem;
}

/* Radio and checkbox rows (S8 factor chooser, S7 link confirm) */
.choice-group {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

.choice {
  display: flex;
  gap: var(--space-3);
  align-items: flex-start;
  padding: var(--space-3) var(--space-4);
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-surface);
  cursor: pointer;
}
.choice:hover {
  border-color: var(--color-border-strong);
}
.choice input {
  appearance: none;
  -webkit-appearance: none;
  margin: 0.2rem 0 0;
  width: 1.125rem;
  height: 1.125rem;
  flex: none;
  border: 1.5px solid var(--color-border-strong);
  background: var(--color-surface);
  border-radius: var(--radius-full);
  cursor: pointer;
  display: grid;
  place-content: center;
  transition:
    border-color var(--duration-fast) ease,
    background var(--duration-fast) ease;
}
.choice input[type='checkbox'] {
  border-radius: var(--radius-sm);
}
.choice:hover input {
  border-color: var(--color-text-muted);
}
.choice input::before {
  content: '';
  width: 0.5rem;
  height: 0.5rem;
  border-radius: inherit;
  transform: scale(0);
  background: var(--color-text-inverse);
  transition: transform var(--duration-fast) ease;
}
.choice input:checked {
  background: var(--color-accent);
  border-color: var(--color-accent);
}
.choice input:checked::before {
  transform: scale(1);
}
.choice:has(input:checked) {
  border-color: var(--color-accent);
}
.choice__body {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}
.choice__label {
  font-weight: var(--font-weight-medium);
}
.choice__meta {
  font-size: var(--font-size-sm);
  color: var(--color-text-muted);
}

/* ---- Buttons ------------------------------------------------------------ */

.button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  width: 100%;
  min-height: 2.75rem;
  padding: var(--space-3) var(--space-5);
  font: inherit;
  font-weight: var(--font-weight-medium);
  text-decoration: none;
  border-radius: var(--radius-md);
  border: var(--border-width) solid transparent;
  cursor: pointer;
  transition:
    background var(--duration-fast) ease,
    border-color var(--duration-fast) ease;
}
.button + .button {
  margin-top: var(--space-3);
}

.button--primary {
  background: var(--color-accent);
  color: var(--color-text-inverse);
}
.button--primary:hover {
  background: var(--color-accent-hover);
}
.button--primary:active {
  background: var(--color-accent-active);
}

.button--secondary {
  background: var(--color-surface);
  color: var(--color-text);
  border-color: var(--color-border-strong);
}
.button--secondary:hover {
  background: var(--color-surface-raised);
}
.button--secondary:visited {
  color: var(--color-text);
}

.button--danger {
  background: var(--color-surface);
  color: var(--color-danger-text);
  border-color: var(--color-danger);
}
.button--danger:hover {
  background: var(--color-danger-bg);
}

.button--inline {
  width: auto;
}

.button:disabled {
  cursor: not-allowed;
  background: var(--color-surface-raised);
  color: var(--color-text-muted);
  border-color: var(--color-border);
}

/*
 * Pending state, set by the form island on submit. The button keeps its label and its width (so
 * the layout does not jump) and gains a spinner. It is NOT disabled: a disabled control loses
 * focus and is announced as unavailable, and a submit that fails would strand the keyboard user.
 * `aria-disabled` plus the island swallowing the second submit is the accessible equivalent.
 */
.button[aria-disabled='true'] {
  cursor: progress;
}
.button__spinner {
  width: 1rem;
  height: 1rem;
  flex: none;
  border: 2px solid currentColor;
  border-right-color: transparent;
  border-radius: var(--radius-full);
  opacity: 0.75;
  animation: auth-spin 640ms linear infinite;
}
@keyframes auth-spin {
  to {
    transform: rotate(360deg);
  }
}

.button-row {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}
.button-row > .button {
  width: 100%;
  margin-top: 0;
}
.button-row--medium {
  max-width: 22rem;
}

/* ---- Alerts ------------------------------------------------------------- */

.alert {
  display: flex;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-md);
  border: var(--border-width) solid;
  border-left-width: 3px;
  font-size: var(--font-size-sm);
}
.alert--error {
  background: var(--color-danger-bg);
  border-color: var(--color-danger);
  color: var(--color-danger-text);
}
.alert--notice {
  background: transparent;
  border-color: transparent;
  border-left-width: var(--border-width);
  padding-left: 0;
  color: var(--color-text-muted);
}
.alert--warning {
  background: var(--color-warning-bg);
  border-color: var(--color-warning);
  color: var(--color-warning-text);
}
.alert a {
  color: inherit;
}
/* An alert that carries its own control: the message, then the button under it. */
.alert--stack {
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-2);
}

.status-region:empty {
  display: none;
}
.status-region {
  font-size: var(--font-size-sm);
  color: var(--color-text-muted);
}

/* ---- Sign-in alternatives ------------------------------------------------
   The passkey button and the federated providers share ONE block under ONE `or`, because they are
   the same answer to the same question: a way in other than a code to this address. Two separate
   rules read as two unrelated offers. */

.auth-alternatives {
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
}
.auth-alternatives[hidden] {
  display: none;
}

/*
 * Monochrome, inherits the button's colour, and never grows with the label.
 *
 * 1.125rem matches the footer menu icons, so every mark on the surface is one size. It is also the
 * smallest the Lucide fingerprint reads at: it carries nine separate strokes, and below this the
 * ridges close up into a grey smudge. A simpler glyph could go smaller, but then the passkey button
 * would be the odd one out.
 */
.button__icon {
  width: 1.125rem;
  height: 1.125rem;
  flex: none;
}

/* ---- Providers (S1 federation buttons) ---------------------------------- */

.auth-providers {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}
.auth-providers .button + .button {
  margin-top: 0;
}

/* ---- Consent, S14 ------------------------------------------------------- */

.consent-client {
  display: flex;
  align-items: center;
  gap: var(--space-3);
}
.consent-client__logo {
  width: 40px;
  height: 40px;
  border-radius: var(--radius-md);
  border: var(--border-width) solid var(--color-border);
  background: var(--color-surface-raised);
  object-fit: contain;
}
.consent-client__host {
  font-family: var(--font-mono);
  font-size: var(--font-size-sm);
  color: var(--color-text-muted);
}

.consent-fieldset {
  margin: 0;
  padding: 0;
  border: 0;
}
.consent-fieldset + .consent-fieldset {
  margin-top: var(--space-5);
}
.consent-fieldset > legend {
  padding: 0;
  font-size: var(--font-size-sm);
  font-weight: var(--font-weight-medium);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--color-text-muted);
  margin-bottom: var(--space-3);
}

.consent-group + .consent-group {
  margin-top: var(--space-4);
}
.consent-group__heading {
  margin: 0 0 var(--space-2);
  font-size: var(--font-size-sm);
  font-weight: var(--font-weight-medium);
  color: var(--color-text);
}

.consent-scopes {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.consent-scope {
  display: flex;
  gap: var(--space-3);
  align-items: flex-start;
  padding: var(--space-3) var(--space-4);
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-surface);
}
/* Every scope in the request is granted together, so a scope is a statement, not a control. The
   text sits in one wrapper so the row's flex axis never splits a name from its description. */
.consent-scope > span:not(.consent-scope__approved) {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}
.consent-scope__name {
  display: block;
  font-weight: var(--font-weight-medium);
}
.consent-scope__description {
  display: block;
  font-size: var(--font-size-sm);
  color: var(--color-text-muted);
}
.consent-scope__approved::before {
  content: '✓';
  color: var(--color-success);
  font-weight: var(--font-weight-bold);
  line-height: var(--line-height-base);
}
/*
 * A sensitive scope carries a border and a warning surface, never colour alone
 * (UI-UX flow-screens.md section 1.4). The visually-hidden "Sensitive permission" text is in the
 * markup, so a screen reader hears what a sighted user sees.
 */
.consent-scope--sensitive {
  background: var(--color-warning-bg);
  border-color: var(--color-warning);
  border-left-width: 3px;
}
.consent-scope--sensitive .consent-scope__name {
  color: var(--color-warning-text);
}

.consent-details {
  border-top: var(--border-width) solid var(--color-border);
  padding-top: var(--space-3);
}
.consent-details > summary {
  cursor: pointer;
  font-size: var(--font-size-sm);
  color: var(--color-text-muted);
}
.consent-raw {
  list-style: none;
  margin: var(--space-3) 0 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}
.consent-raw code {
  font-family: var(--font-mono);
  font-size: var(--font-size-sm);
  background: var(--color-surface-raised);
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-sm);
  padding: 0.1em 0.4em;
}

.consent-actions {
  display: flex;
  gap: var(--space-3);
  margin-top: var(--space-5);
}
.consent-actions > .button {
  margin-top: 0;
}

/* ---- Device grant, S20 to S22 ------------------------------------------- */

.device-code {
  font-family: var(--font-mono);
  font-size: 1.5rem;
  letter-spacing: 0.22em;
  text-align: center;
  text-transform: uppercase;
}

/* ---- TOTP enrolment, S26 ------------------------------------------------ */

.totp-enrol {
  display: flex;
  gap: var(--space-4);
  align-items: flex-start;
  flex-wrap: wrap;
}
.totp-enrol__aside {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  flex: 1 1 14rem;
}
/*
 * The provisioning QR, a `data:` SVG the server rendered.
 *
 * The white plate and the padding are not decoration. The image is dark-on-light by specification
 * and resolves no custom property of its own, so under the dark theme it would otherwise be a
 * bright rectangle butted against a dark surface, and a camera needs the quiet zone to read as
 * background rather than as a page edge. `flex: none` keeps it square while the setup key beside it
 * takes the remaining width, and it wraps below on a narrow viewport.
 */
.totp-qr {
  flex: none;
  width: 11rem;
  height: 11rem;
  max-width: 100%;
  padding: var(--space-2);
  background: #fff;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
}
.totp-secret {
  font-family: var(--font-mono);
  font-size: var(--font-size-sm);
  word-break: break-all;
  user-select: all;
}

/* A copy control that sits beside a code. Ghost by default; the island swaps its label to
   "Copied" for a moment and puts nothing in the DOM when clipboard access is unavailable. */
.copy-button {
  align-self: flex-start;
  width: auto;
  min-height: 2rem;
  padding: var(--space-1) var(--space-3);
  font-size: var(--font-size-sm);
  background: var(--color-surface);
  color: var(--color-text-muted);
  border-color: var(--color-border);
}
.copy-button:hover {
  background: var(--color-surface-raised);
  color: var(--color-text);
}

/* ---- Account navigation ------------------------------------------------- */

.account-nav {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  width: 100%;
  max-width: var(--max-width-form);
}
.account-nav__link {
  font-size: var(--font-size-sm);
  text-decoration: none;
  color: var(--color-text-muted);
  padding: var(--space-1) var(--space-2);
  border-radius: var(--radius-sm);
}
.account-nav__link:hover {
  background: var(--color-surface-raised);
  color: var(--color-text);
}
.account-nav__link[aria-current='page'] {
  color: var(--color-text);
  font-weight: var(--font-weight-medium);
  background: var(--color-surface-raised);
}

/* ---- Account shell ------------------------------------------------------
   The auth flow is one decision per screen, so the card is right for it. The account area is a
   place you browse, with records that carry six or seven fields each, so it gets its own width
   and a persistent nav. Same tokens, same components: only the shell differs. */

.auth-shell--app {
  padding: var(--space-5) var(--space-6) var(--space-6);
  gap: var(--space-5);
}
.auth-shell--app > .auth-brand,
.auth-shell--app > .auth-footer {
  max-width: 60rem;
}
.auth-shell--app > .auth-footer {
  padding-top: var(--space-4);
}

.auth-shell--app > .auth-brand {
  justify-content: space-between;
  padding-bottom: var(--space-4);
  border-bottom: var(--border-width) solid var(--color-border);
}
.auth-brand__account {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  font-size: var(--font-size-sm);
  color: var(--color-text-muted);
  margin-left: auto;
}

.account-layout {
  display: grid;
  grid-template-columns: 12rem minmax(0, 1fr);
  gap: var(--space-6);
  width: 100%;
  max-width: 60rem;
  align-items: start;
}
@media (max-width: 48rem) {
  .account-layout {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-4);
  }
}

.account-sidebar {
  display: flex;
  flex-direction: column;
  gap: 2px;
  position: sticky;
  top: var(--space-5);
}
@media (max-width: 48rem) {
  .account-sidebar {
    position: static;
    flex-direction: row;
    flex-wrap: wrap;
  }
}
.account-sidebar .account-nav__link {
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-md);
}
.account-sidebar__group {
  font-size: 0.6875rem;
  font-weight: var(--font-weight-medium);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--color-text-muted);
  padding: var(--space-4) var(--space-3) var(--space-2);
}
.account-sidebar__group:first-child {
  padding-top: 0;
}
@media (max-width: 48rem) {
  .account-sidebar__group {
    display: none;
  }
}

.account-main {
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
  min-width: 0;
}

.account-head {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}
/*
 * The account area's own back link.
 *
 * It exists for the narrow layout, where `.account-sidebar` collapses to a wrapped row above the
 * content and "where am I" stops being obvious. On a wide screen the sidebar already answers it,
 * so this is deliberately quiet rather than hidden: a control that appears and disappears with the
 * viewport is a control people stop trusting.
 */
.account-head .auth-back {
  margin-left: calc(var(--space-2) * -1);
  margin-bottom: calc(var(--space-1) * -1);
}

.account-head__title {
  margin: 0;
  font-size: var(--font-size-xl);
  line-height: var(--line-height-tight);
  font-weight: var(--font-weight-bold);
  letter-spacing: -0.015em;
}
.account-head__lede {
  margin: 0;
  color: var(--color-text-muted);
  max-width: 56ch;
  text-wrap: pretty;
}

/* A section inside the account area: a heading bar, then rows. */
.account-section {
  background: var(--color-surface);
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  overflow: hidden;
}
.account-section__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-4) var(--space-5);
  border-bottom: var(--border-width) solid var(--color-border);
}
.account-section__title {
  margin: 0;
  font-size: var(--font-size-base);
  font-weight: var(--font-weight-bold);
}
.account-section__link {
  font-size: var(--font-size-sm);
  white-space: nowrap;
}
.account-section__body {
  padding: var(--space-5);
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}
.account-section__foot {
  padding: var(--space-4) var(--space-5);
  border-top: var(--border-width) solid var(--color-border);
  background: var(--color-surface-raised);
}
.account-section--danger {
  border-color: var(--color-danger);
}
.account-section--danger .account-section__head {
  border-bottom-color: var(--color-danger);
}

/* Records: one row per session, passkey, application, connection. */
.record-list {
  list-style: none;
  margin: 0;
  padding: 0;
}
.record {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: var(--space-3) var(--space-5);
  align-items: start;
  padding: var(--space-4) var(--space-5);
  border-top: var(--border-width) solid var(--color-border);
}
.record:first-child {
  border-top: 0;
}
.record--current {
  background: var(--color-surface-raised);
}
@media (max-width: 34rem) {
  .record {
    grid-template-columns: minmax(0, 1fr);
  }
}

.record__title {
  margin: 0;
  font-weight: var(--font-weight-medium);
  display: flex;
  align-items: center;
  gap: var(--space-2);
  flex-wrap: wrap;
}
.record__body {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  min-width: 0;
}
.record__actions {
  display: flex;
  gap: var(--space-2);
  align-items: center;
}
.record__actions .button {
  width: auto;
  margin-top: 0;
  white-space: nowrap;
}
.record__note {
  margin: 0;
  font-size: var(--font-size-sm);
  color: var(--color-text-muted);
}

/* Field pairs, so seven attributes read as data rather than a paragraph. */
.record__meta {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
  gap: var(--space-2) var(--space-5);
  margin: 0;
  font-size: var(--font-size-sm);
}
.record__meta > div {
  display: flex;
  flex-direction: column;
  gap: 1px;
  min-width: 0;
}
.record__meta dt {
  color: var(--color-text-muted);
}
.record__meta dd {
  margin: 0;
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}

.record__scopes {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  font-size: var(--font-size-sm);
}
.record__scopes li {
  padding: 0.15em 0.55em;
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-full);
  color: var(--color-text-muted);
}

.account-empty {
  padding: var(--space-6) var(--space-5);
  text-align: center;
  color: var(--color-text-muted);
}

/* In the wide shell an action sits beside its record, not under it. */
.account-layout .auth-list__item .button {
  width: auto;
}
