/* ==========================================================================
   KQH login theme — the stylesheet the login pages ship

   Plain CSS, committed and served as-is: no build step, no compiler in the
   browser. It was authored as Tailwind and this file is the last compile
   frozen in place (Tailwind v4.3.3, ADR 0012). Tailwind generated one
   utility across the whole theme, so all it was still buying was Preflight
   and a token syntax; both are inlined below and now read as ordinary CSS.

   Drawn against the product app's design system (platform-app,
   src/assets/scss/variables/) per ADR 0009; the mockups it was transcribed
   from were removed once this file shipped.
   Every token below has a counterpart there; where this file diverges, the
   rule says why. Namespaced .kqh-*; flat selectors, no descendant chain
   deeper than 2.
   ========================================================================== */

/* Preflight, verbatim from Tailwind v4.3.3, because with parent=base Keycloak
   ships almost no CSS and the rules below are written against this baseline.
   It stays in @layer base so the theme's own rules keep outranking it.
   Vendored, not authored: edit the theme below it, never this block. */
@layer base {
  *, ::after, ::before, ::backdrop, ::file-selector-button {
    box-sizing: border-box;
    margin: 0;
    padding: 0;
    border: 0 solid;
  }
  html, :host {
    line-height: 1.5;
    -webkit-text-size-adjust: 100%;
    tab-size: 4;
    font-family: var(--default-font-family, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', 'Noto Sans', Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji');
    font-feature-settings: var(--default-font-feature-settings, normal);
    font-variation-settings: var(--default-font-variation-settings, normal);
    -webkit-tap-highlight-color: transparent;
  }
  hr {
    height: 0;
    color: inherit;
    border-top-width: 1px;
  }
  abbr:where([title]) {
    -webkit-text-decoration: underline dotted;
    text-decoration: underline dotted;
  }
  h1, h2, h3, h4, h5, h6 {
    font-size: inherit;
    font-weight: inherit;
  }
  a {
    color: inherit;
    -webkit-text-decoration: inherit;
    text-decoration: inherit;
  }
  b, strong {
    font-weight: bolder;
  }
  code, kbd, samp, pre {
    font-family: var(--default-mono-font-family, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace);
    font-feature-settings: var(--default-mono-font-feature-settings, normal);
    font-variation-settings: var(--default-mono-font-variation-settings, normal);
    font-size: 1em;
  }
  small {
    font-size: 80%;
  }
  sub, sup {
    font-size: 75%;
    line-height: 0;
    position: relative;
    vertical-align: baseline;
  }
  sub {
    bottom: -0.25em;
  }
  sup {
    top: -0.5em;
  }
  table {
    text-indent: 0;
    border-color: inherit;
    border-collapse: collapse;
  }
  :-moz-focusring:where(:not(iframe)) {
    outline: auto;
  }
  progress {
    vertical-align: baseline;
  }
  summary {
    display: list-item;
  }
  ol, ul, menu {
    list-style: none;
  }
  img, svg, video, canvas, audio, iframe, embed, object {
    display: block;
    vertical-align: middle;
  }
  img, video {
    max-width: 100%;
    height: auto;
  }
  button, input, select, optgroup, textarea, ::file-selector-button {
    font: inherit;
    font-feature-settings: inherit;
    font-variation-settings: inherit;
    letter-spacing: inherit;
    color: inherit;
    border-radius: 0;
    background-color: transparent;
    opacity: 1;
  }
  :where(select:is([multiple], [size])) optgroup {
    font-weight: bolder;
  }
  :where(select:is([multiple], [size])) optgroup option {
    padding-inline-start: 20px;
  }
  ::file-selector-button {
    margin-inline-end: 4px;
  }
  ::placeholder {
    opacity: 1;
  }
  @supports (not (-webkit-appearance: -apple-pay-button))  or (contain-intrinsic-size: 1px) {
    ::placeholder {
      color: currentcolor;
      @supports (color: color-mix(in lab, red, red)) {
        color: color-mix(in oklab, currentcolor 50%, transparent);
      }
    }
  }
  textarea {
    resize: vertical;
  }
  ::-webkit-search-decoration {
    -webkit-appearance: none;
  }
  ::-webkit-date-and-time-value {
    min-height: 1lh;
    text-align: inherit;
  }
  ::-webkit-datetime-edit {
    display: inline-flex;
  }
  ::-webkit-datetime-edit-fields-wrapper {
    padding: 0;
  }
  ::-webkit-datetime-edit, ::-webkit-datetime-edit-year-field, ::-webkit-datetime-edit-month-field, ::-webkit-datetime-edit-day-field, ::-webkit-datetime-edit-hour-field, ::-webkit-datetime-edit-minute-field, ::-webkit-datetime-edit-second-field, ::-webkit-datetime-edit-millisecond-field, ::-webkit-datetime-edit-meridiem-field {
    padding-block: 0;
  }
  ::-webkit-calendar-picker-indicator {
    line-height: 1;
  }
  :-moz-ui-invalid {
    box-shadow: none;
  }
  button, input:where([type='button'], [type='reset'], [type='submit']), ::file-selector-button {
    appearance: button;
  }
  ::-webkit-inner-spin-button, ::-webkit-outer-spin-button {
    height: auto;
  }
  [hidden]:where(:not([hidden='until-found'])) {
    display: none !important;
  }
}

/* Self-hosted, as the old theme already ships it, and as the app does. The file
   is variable — DM Sans carries a weight axis of 100–1000 plus an optical-size
   axis — so declaring the real range is what stops the browser from
   synthesising every weight the design asks for. A third-party font request
   would leak the visitor's IP, which is why it is never fetched remotely. */
@font-face {
  font-family: "DM Sans";
  src: url("DMSans.woff2") format("woff2");
  font-weight: 100 1000;
  font-stretch: 100%;
  font-display: swap;
}

:root {
  /* Brand — $amaranth-500 and $gold-500 of the app's colour primitives.
     White on the magenta measures 7.0:1. */
  --color-brand:        #a42168;  /* --primary */
  --color-brand-hover:  #c84189;  /* --primary-light, 4.6:1 under white */
  --color-brand-active: #772251;  /* --primary-dark */
  --color-accent:       #e2af0e;  /* --secondary */

  /* Surfaces — the app lifts panels above a white page, but a login page has
     no dashboard around the card, so a #fafafa card reads as a dim slab. The
     two are swapped: the page takes --fill-bg-secondary and the card the
     white. Both values are the app's, and the swap is what makes the app's
     own grey input sit on white here exactly as it does there. */
  --color-page:       #fafafa;    /* --fill-bg-secondary */
  --color-surface:    #ffffff;    /* --fill-bg-primary */
  --color-fill-input: #f5f5f5;    /* --fill-input */
  --color-fill-hover: #ededed;    /* --fill-card-hover */

  /* Borders */
  --color-border-soft:   #ededed; /* --border-soft */
  --color-border-base:   #d9d9d9; /* --border-base */
  --color-border-strong: #bfbfbf; /* --border-strong */

  /* Text */
  --color-text:          #333333; /* --text-base */
  --color-text-soft:     #666666; /* --text-soft */
  --color-text-subtle:   #808080; /* --text-subtle */
  --color-text-emphasis: #0e0e0e; /* --text-emphasis */
  --color-text-on-brand: #ffffff;

  /* Links — the app ships $blue-500 #157bd9, which measures 4.31:1 on white.
     Link ink drops one step to $blue-600, the same AA correction the error
     red takes; the app's own blue stays as the hover. */
  --color-link:       #2175c5;    /* $blue-600, 4.8:1 on white */
  --color-link-hover: #157bd9;    /* $blue-500 */

  /* Danger — the app's red ramp. The base carries borders and the icon; text
     takes the darker step, because #e12b2b on white is 4.58:1 and a field
     error should not sit that close to the threshold. */
  --color-danger:        #e12b2b; /* --danger-base */
  --color-danger-text:   #c51c1c; /* $red-600, 5.9:1 on white */
  --color-danger-bg:     #f7c4c4; /* --danger-bg-subtle */
  --color-danger-border: #ef8f8f; /* --danger-border-subtle */
  --color-danger-strong: #550c0c; /* --danger-text-emphasis */

  /* Radii — the app's scale: panels 15, inputs and dialogs 10, buttons pill */
  --radius-panel: 15px;
  --radius-input: 10px;
  --radius-pill:  50em;

  /* Spacing scale (4px base) */
  --spacing-1:  0.25rem;
  --spacing-2:  0.5rem;
  --spacing-3:  0.75rem;
  --spacing-4:  1rem;
  --spacing-5:  1.25rem;
  --spacing-6:  1.5rem;
  --spacing-8:  2rem;
  --spacing-10: 2.5rem;

  /* Typography — DM Sans alone, as the app loads it. No display face. */
  --font-kqh: "DM Sans", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;

  --text-xs:   0.625rem;  /* 10 */
  --text-sm:   0.75rem;   /* 12 */
  --text-md:   0.875rem;  /* 14 */
  --text-base: 0.9375rem; /* 15 */
  --text-lg:   1.0625rem; /* 17 */
  --text-h4:   1.25rem;   /* 20 */

  --font-weight-body:     300;
  --font-weight-emphasis: 400;
  --font-weight-label:    450;

  --tracking-body: 0.04em;    /* body, as the app sets on html, body, p, a */
  --tracking-btn:  0.03em;    /* buttons, as the app sets on .btn */

  /* Depth + focus */
  --shadow-panel: 0 2px 5px rgba(14, 14, 14, 0.07);

  /* The app marks focus with a border colour and a soft shadow. A login form
     needs the ring to be unmissable, so this is a deliberate divergence. */
  --shadow-focus:        0 0 0 3px rgba(164, 33, 104, 0.24);
  --shadow-focus-danger: 0 0 0 3px rgba(225, 43, 43, 0.24);

  --ease-kqh: cubic-bezier(0.2, 0.6, 0.2, 1);
}

/* --------------------------------------------------------------------------
   Page shell — one centred column on every screen
   -------------------------------------------------------------------------- */

/* The element that HOSTS the page is the container, so the same markup
   responds to width in the preview harness and in the real Keycloak page. */
.kqh-body {
  container-type: inline-size;
  container-name: kqh-page;
  margin: 0;
}

.kqh-page {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--spacing-6);

  min-height: 100vh;
  width: 100%;
  padding: var(--spacing-10) var(--spacing-4);

  font-family: var(--font-kqh);
  font-size:   var(--text-base);
  font-weight: var(--font-weight-body);
  line-height: 1.5;
  letter-spacing: var(--tracking-body);
  color:       var(--color-text);
  background:  var(--color-page);

  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

/* The lockup the e-mails use: the same Kipu mark, then the name. Both ship with
   their ink baked in (gold and #1a1a1a); the mark's counters are transparent, so
   the one asset works on the dark e-mail band and on this light page alike. */
.kqh-wordmark {
  display: flex;
  align-items: center;
  gap: var(--spacing-3);
}

.kqh-wordmark__mark {
  width: 40px;
  height: 40px;
}

.kqh-wordmark__name {
  width: 200px;
  height: auto;
}

/* The app's .panel-outline, on the app's secondary page fill: white, 15px,
   a hairline border and the app's panel shadow to lift it off the page.
   The gold rule on top is this theme's own — the accent has no other job here. */
.kqh-card {
  width: 100%;
  max-width: 420px;
  padding: var(--spacing-8);
  background: var(--color-surface);
  border: 1px solid var(--color-border-base);
  border-top: 3px solid var(--color-accent);
  border-radius: var(--radius-panel);
  box-shadow: var(--shadow-panel);
}


/* Registration only: its field set in a 420px column is a scroll, not a form.
   The grouped form is what asks for the width, so the card is selected by the
   groups it holds rather than by a modifier the layout has to thread through. */
.kqh-card:has(.kqh-fieldgroup) {
  max-width: 640px;
}

@container kqh-page (max-width: 420px) {
  .kqh-page {
    padding: var(--spacing-6) var(--spacing-3);
  }

  .kqh-card {
    padding: var(--spacing-6) var(--spacing-5);
  }
}

.kqh-card__title {
  margin: 0;
  font-size: var(--text-h4);
  font-weight: var(--font-weight-emphasis);
}

.kqh-card__subtitle {
  margin: var(--spacing-2) 0 0 0;
  color: var(--color-text-soft);
  font-size: var(--text-md);
}

.kqh-card__header {
  margin-bottom: var(--spacing-6);
}

.kqh-card__footer {
  margin-top: var(--spacing-6);
  padding-top: var(--spacing-5);
  border-top: 1px solid var(--color-border-soft);
  text-align: center;
  font-size: var(--text-md);
  color: var(--color-text-soft);
}

.kqh-page__legal {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--spacing-4);
  margin: 0;
  font-size: var(--text-sm);
  color: var(--color-text-subtle);
}

/* --------------------------------------------------------------------------
   Form
   -------------------------------------------------------------------------- */

.kqh-form {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-5);
}

/* A group states what the block of fields asks for — who you are, where you
   work, how you sign in. The legend is the only structure the long form has,
   so it carries a rule and nothing else. */
.kqh-fieldgroup {
  margin: 0;
  padding: 0;
  border: 0;
}

.kqh-fieldgroup__legend {
  width: 100%;
  margin-bottom: var(--spacing-4);
  padding-bottom: var(--spacing-2);
  border-bottom: 1px solid var(--color-border-soft);
  color: var(--color-text-soft);
  font-size: var(--text-sm);
  font-weight: var(--font-weight-label);
}

.kqh-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--spacing-5);
}

/* The two long selects and anything else whose text needs the whole row. */
.kqh-field--full {
  grid-column: 1 / -1;
}

/* One column below the wide card's own width, which is what keeps 360px honest. */
@container kqh-page (max-width: 640px) {
  .kqh-grid {
    grid-template-columns: 1fr;
  }
}

.kqh-field {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-2);
}

.kqh-field__row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--spacing-3);
}

.kqh-field__label {
  font-size: var(--text-md);
  font-weight: var(--font-weight-label);
}

.kqh-field__input,
.kqh-field__select {
  width: 100%;
  min-height: 44px;
  padding: var(--spacing-3);
  font: inherit;
  letter-spacing: inherit;
  color: var(--color-text);
  background: var(--color-fill-input);
  border: 1px solid var(--color-border-base);
  border-radius: var(--radius-input);
  transition: border-color 120ms var(--ease-kqh), box-shadow 120ms var(--ease-kqh);
}

/* Native chevron is dropped for one that matches the type colour; the control
   itself stays a plain <select>, so keyboard and screen-reader behaviour is
   the platform's. */
.kqh-field__select {
  appearance: none;
  padding-right: var(--spacing-8);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' fill='none' stroke='%23666666' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 8l4 4 4-4'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right var(--spacing-3) center;
  background-size: 20px 20px;
}

/* The placeholder option reads as a prompt rather than as a chosen value. */
.kqh-field__select:invalid,
.kqh-field__select option[value=""] {
  color: var(--color-text-subtle);
}

.kqh-field__input:hover,
.kqh-field__select:hover {
  border-color: var(--color-border-strong);
  box-shadow: var(--shadow-panel);
}

.kqh-field__input:focus-visible,
.kqh-field__select:focus-visible {
  outline: none;
  border-color: var(--color-brand);
  box-shadow: var(--shadow-focus);
}

.kqh-field__input[aria-invalid="true"],
.kqh-field__select[aria-invalid="true"] {
  border-color: var(--color-danger);
}

.kqh-field__input[aria-invalid="true"]:focus-visible,
.kqh-field__select[aria-invalid="true"]:focus-visible {
  box-shadow: var(--shadow-focus-danger);
}

.kqh-field__error {
  color: var(--color-danger-text);
  font-size: var(--text-md);
}

/* Says what the field is for before the user gets it wrong; the error says
   what went wrong afterwards. Both are read out, in that order. */
.kqh-field__hint {
  color: var(--color-text-soft);
  font-size: var(--text-sm);
}

.kqh-field__hint-link {
  font-size: var(--text-md);
}

.kqh-check {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--spacing-3);
  align-items: start;
}

.kqh-check__input {
  width: 18px;
  height: 18px;
  margin: 2px 0 0 0;
  accent-color: var(--color-brand);
}

.kqh-check__input:focus-visible {
  outline: none;
  box-shadow: var(--shadow-focus);
  border-radius: 4px;
}

.kqh-check__label {
  font-size: var(--text-md);
  color: var(--color-text);
}

/* --------------------------------------------------------------------------
   Buttons and links
   -------------------------------------------------------------------------- */

/* Pill, light weight and tracked out, as .btn is in the app. */
.kqh-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--spacing-2);

  width: 100%;
  min-height: 44px;
  padding: var(--spacing-2) var(--spacing-5);

  font: inherit;
  font-weight: var(--font-weight-body);
  letter-spacing: var(--tracking-btn);
  text-align: center;
  text-decoration: none;
  border: 1px solid transparent;
  border-radius: var(--radius-pill);
  cursor: pointer;
  transition: background-color 120ms var(--ease-kqh), border-color 120ms var(--ease-kqh);
}

.kqh-btn:focus-visible {
  outline: none;
  box-shadow: var(--shadow-focus);
}

/* Solid magenta. The app's hover lightens rather than darkens, and white on
   that lighter step still measures 4.6:1. */
.kqh-btn--primary {
  color: var(--color-text-on-brand);
  background: var(--color-brand);
}

.kqh-btn--primary:hover {
  background: var(--color-brand-hover);
}

.kqh-btn--primary:active {
  background: var(--color-brand-active);
}

.kqh-btn--secondary {
  color: var(--color-text);
  background: var(--color-fill-input);
  border-color: var(--color-border-base);
}

.kqh-btn--secondary:hover {
  color: var(--color-text-emphasis);
  background: var(--color-fill-hover);
  border-color: var(--color-border-strong);
}

.kqh-btn:disabled {
  opacity: 0.6;
  cursor: not-allowed;
}

.kqh-actions {
  display: flex;
  gap: var(--spacing-3);
}

/* Buttons are excluded: a link styled as a button carries the button's colour,
   and .kqh-page a would otherwise outrank .kqh-btn--secondary. */
.kqh-page a:not(.kqh-btn) {
  color: var(--color-link);
  text-decoration: none;
}

.kqh-page a:not(.kqh-btn):hover {
  color: var(--color-link-hover);
}

/* A link inside a sentence keeps its underline. The app can leave links bare
   because position marks them there; in running text colour alone is the one
   signal a colour-blind reader does not get. Links that stand alone — the
   forgot-password hint, the legal pair — are marked by position, as in the app. */
.kqh-page .kqh-card__footer a,
.kqh-page .kqh-check__label a,
.kqh-page .kqh-prose a {
  font-weight: var(--font-weight-emphasis);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.15em;
}

.kqh-page a:focus-visible {
  outline: none;
  border-radius: 4px;
  box-shadow: var(--shadow-focus);
}

/* --------------------------------------------------------------------------
   Alerts and status pages
   -------------------------------------------------------------------------- */

.kqh-alert {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--spacing-3);
  margin-bottom: var(--spacing-5);
  padding: var(--spacing-4);
  border: 1px solid var(--color-border-base);
  border-radius: var(--radius-input);
  background: var(--color-fill-input);
  font-size: var(--text-md);
}

.kqh-alert--error {
  border-color: var(--color-danger-border);
  background: var(--color-danger-bg);
  color: var(--color-danger-strong);
}

.kqh-alert__icon {
  margin-top: 1px;
  color: var(--color-danger);
}

.kqh-alert__title {
  margin: 0 0 var(--spacing-1) 0;
  font-weight: var(--font-weight-label);
}

.kqh-alert p {
  margin: 0;
}

.kqh-prose {
  color: var(--color-text-soft);
  font-size: var(--text-md);
}

.kqh-prose p {
  margin: 0 0 var(--spacing-4) 0;
}

.kqh-prose p:last-child {
  margin-bottom: 0;
}

.kqh-prose ul {
  margin: 0 0 var(--spacing-4) 0;
  padding-left: var(--spacing-5);
}

.kqh-prose strong {
  color: var(--color-text-emphasis);
  font-weight: var(--font-weight-label);
}

/* Outside the form there is no flex gap to space these, and read-then-act
   needs the break: the text is what the buttons are answering. */
.kqh-prose + .kqh-actions,
.kqh-prose + .kqh-btn,
.kqh-prose + form {
  margin-top: var(--spacing-6);
}

.kqh-rule {
  height: 1px;
  margin: var(--spacing-6) 0;
  border: 0;
  background: var(--color-border-soft);
}
