/*
 * SANTUN public auth design system.
 *
 * Sources of truth:
 *   - docs/design/design-handoff/design-tokens.json (colors, radii, borders)
 *   - docs/plans/2026-10-07-santun-public-auth-redesign.md section 2
 *
 * Style direction (docs/design/design-handoff/README.md): flat institutional
 * look, no large shadows, border-radius <= 8px, gold used as structural rules
 * (4px), status blocks with a 4px left border instead of shadowed cards.
 *
 * No runtime external requests: Poppins is self-hosted in static/fonts/
 * (SIL Open Font License 1.1, see static/fonts/OFL.txt) so auth pages never
 * depend on any third-party font service.
 */

/* --------------------------------------------------------------------------
 * Fonts: Poppins, self-hosted (subsets latin + latin-ext, weights 400-800).
 * -------------------------------------------------------------------------- */

@font-face {
  font-family: "Poppins";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('../fonts/poppins-400-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: "Poppins";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('../fonts/poppins-400-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-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: "Poppins";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('../fonts/poppins-500-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: "Poppins";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('../fonts/poppins-500-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-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: "Poppins";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('../fonts/poppins-600-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: "Poppins";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('../fonts/poppins-600-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-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: "Poppins";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('../fonts/poppins-700-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: "Poppins";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('../fonts/poppins-700-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-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: "Poppins";
  font-style: normal;
  font-weight: 800;
  font-display: swap;
  src: url('../fonts/poppins-800-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: "Poppins";
  font-style: normal;
  font-weight: 800;
  font-display: swap;
  src: url('../fonts/poppins-800-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-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* --------------------------------------------------------------------------
 * Design tokens. The color block matches the handoff exactly; everything
 * below it is the shared scale used by the components in this file.
 * -------------------------------------------------------------------------- */

:root {
  color-scheme: light;

  /* Brand palette (design-tokens.json) */
  --udinus-blue: #114d91;
  --udinus-blue-deep: #0e4584;
  --udinus-gold: #f3bc45;
  --udinus-ink: #1f2937;
  --udinus-muted: #5b6675;
  --udinus-line: #d9dee5;
  --udinus-paper: #f4f6f9;
  --error-border: #b3362e;
  --error-bg: #fbefee;
  --error-text: #8c2b25;

  /* Derived status colors: error comes from the tokens; success is a muted
     green tint that follows the same border/bg/text pattern as the error
     block. Info reuses brand blue on the paper background. */
  --success-border: #1e7a44;
  --success-bg: #eef7f1;
  --success-text: #175c33;

  /* Interaction shades derived from brand colors (hover / focus) */
  --udinus-gold-strong: #e3ac33;
  --focus-ring: var(--udinus-blue);

  /* Visual panel motif: two pale blue tints over the paper background. Large
     quarter circles (handoff screens 01-04), never behind the panel copy. */
  --panel-motif-strong: #dce3ec;
  --panel-motif-soft: #e7ecf3;

  /* Typography */
  --font-sans: "Poppins", system-ui, -apple-system, "Segoe UI", Roboto,
    "Helvetica Neue", Arial, sans-serif;
  --font-weight-body: 400;
  --font-weight-body-medium: 500;
  --font-weight-label: 600;
  --font-weight-subheading: 700;
  --font-weight-heading: 800;

  /* Geometry */
  --radius-control: 8px;
  --radius-input: 6px;
  --border-input: 1.5px solid var(--udinus-blue-deep);
  --accent-width: 4px;
  --input-height: 52px;
  --hit-min: 44px;

  /* Spacing scale, 4px based */
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 24px;
  --space-6: 32px;
  --space-7: 40px;
  --space-8: 48px;
  --space-9: 64px;

  /* Page gutter: 24px on mobile (390px reference), 16px at 360px (media
     query at the bottom of this file adjusts the token for narrow screens). */
  --gutter: 24px;

  --content-max: 1120px;

  /* Split layout (>= 1024px): the shell goes edge to edge so the visual panel
     can reach the right viewport edge, and this inset replaces the centered
     container gutter for header, footer, and the form column. */
  --shell-inset: 64px;
  --form-column-max: 400px;
  /* Consent only (task-086): two sub-columns need more than 400px. */
}

/* --------------------------------------------------------------------------
 * Base
 * -------------------------------------------------------------------------- */

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

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

body {
  margin: 0;
  font-family: var(--font-sans);
  font-size: 16px;
  font-weight: var(--font-weight-body);
  line-height: 1.5;
  color: var(--udinus-ink);
  background-color: #ffffff;
  overflow-wrap: break-word;
}

h1,
h2,
h3,
h4,
p,
ul,
ol {
  margin: 0;
}

h1,
h2,
h3,
h4 {
  line-height: 1.25;
  color: var(--udinus-ink);
}

img,
svg {
  max-width: 100%;
  height: auto;
}

a {
  color: var(--udinus-blue);
}

a:hover {
  text-decoration-thickness: 2px;
}

/* Global focus indicator. Specific components override the outline color
   where the ring would sit on a same-colored background. */
:where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
  outline: 3px solid var(--focus-ring);
  outline-offset: 2px;
}

/* Skip link: visually hidden until focused (keyboard access to main content). */
.skip-link {
  position: absolute;
  left: var(--gutter);
  top: -56px;
  z-index: 100;
  min-height: var(--hit-min);
  display: inline-flex;
  align-items: center;
  padding: var(--space-2) var(--space-4);
  background-color: var(--udinus-blue-deep);
  color: #ffffff;
  font-weight: var(--font-weight-label);
  text-decoration: none;
  border-radius: var(--radius-input);
  transition: top 0.15s ease-in-out;
}

.skip-link:focus {
  top: var(--space-3);
}

/* --------------------------------------------------------------------------
 * Page shell. Uses min-height only: the page must keep flowing when content
 * grows (zoom, long errors, translations). The footer is never sticky; it
 * simply sits after the main content.
 * -------------------------------------------------------------------------- */

.page-shell {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  min-height: 100dvh;
}

.container {
  width: 100%;
  max-width: var(--content-max);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.site-main {
  flex: 1 1 auto;
  width: 100%;
  padding-block: var(--space-7) var(--space-9);
}

/* Shared typography blocks for auth screens. */
.page-heading {
  font-size: clamp(28px, 4vw, 40px);
  font-weight: var(--font-weight-heading);
  letter-spacing: -0.01em;
}

.page-subheading {
  font-size: clamp(20px, 2.5vw, 24px);
  font-weight: var(--font-weight-subheading);
}

.page-intro {
  max-width: 46ch;
  color: var(--udinus-muted);
}

/* --------------------------------------------------------------------------
 * Header. Desktop: optional thin institutional top bar + white lockup bar.
 * Mobile: top bar is hidden and the lockup stays compact enough for 360px.
 * (Product decision 2026-10-07: top-bar links are omitted from templates
 * for now; the style hook remains for later institutional navigation.)
 * -------------------------------------------------------------------------- */

.site-header {
  background-color: #ffffff;
  border-bottom: 1px solid var(--udinus-line);
}

.site-header__top-bar {
  display: flex;
  align-items: center;
  min-height: 36px;
  background-color: var(--udinus-blue-deep);
  color: #ffffff;
  font-size: 13px;
}

.site-header__top-bar a {
  color: #ffffff;
  text-decoration: none;
}

.site-header__top-bar a:hover {
  text-decoration: underline;
}

.site-header__top-bar :focus-visible {
  outline-color: #ffffff;
}

.site-header__main {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  min-height: var(--hit-min);
  padding-block: var(--space-3);
}

.site-header__lockup {
  display: inline-flex;
  align-items: center;
  gap: var(--space-3);
  min-height: var(--hit-min);
  text-decoration: none;
  color: inherit;
}

/* UDINUS lockup: logo, hairline divider, institutional name in brand blue. */
.site-header__lockup .site-header__identity {
  padding-left: var(--space-3);
  border-left: 1px solid var(--udinus-line);
}

.site-header__lockup .site-header__name,
.site-header__lockup .site-header__domain {
  color: var(--udinus-blue);
}

.site-header__logo {
  display: block;
  width: auto;
  height: 40px;
}

.site-header__identity {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.site-header__name {
  font-size: 18px;
  font-weight: var(--font-weight-subheading);
  letter-spacing: 0.04em;
  color: var(--udinus-ink);
}

.site-header__domain {
  font-size: 13px;
  color: var(--udinus-muted);
}

.site-header__actions {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: var(--space-3);
}

/* Service identity sits opposite the lockup and reads right-aligned. */
.site-header__actions .site-header__identity {
  align-items: flex-end;
  text-align: right;
}

/* --------------------------------------------------------------------------
 * Section tag: dark blue box with a gold dot, followed by a blue label.
 * Structural replacement for pill badges / eyebrow chips.
 * -------------------------------------------------------------------------- */

.section-tag {
  display: inline-flex;
  align-items: stretch;
}

.section-tag__mark {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  padding: 6px;
  background-color: var(--udinus-blue-deep);
}

.section-tag__dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background-color: var(--udinus-gold);
}

.section-tag__label {
  display: inline-flex;
  align-items: center;
  padding: 6px 14px;
  background-color: var(--udinus-blue);
  color: #ffffff;
  font-size: 13px;
  font-weight: var(--font-weight-label);
  letter-spacing: 0.02em;
}

/* Gold structural rule under headings. */
.accent-rule {
  width: 56px;
  height: var(--accent-width);
  border: 0;
  margin: 0;
  background-color: var(--udinus-gold);
}

/* --------------------------------------------------------------------------
 * Auth layout. Mobile first: single column, decorative panel omitted.
 * At >= 1024px the layout splits into form column + visual panel.
 * -------------------------------------------------------------------------- */

.auth-layout {
  display: block;
}

.auth-layout > * {
  min-width: 0;
}

.auth-layout__form {
  width: 100%;
  max-width: 560px;
  margin-inline: auto;
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
}

.auth-layout__header {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  align-items: flex-start;
}

/* Decorative visual panel with the quarter-circle tile pattern, drawn with
 * radial gradients only (no raster images). Hidden below the split layout so
 * medium and small screens stay a single compact column. */
.visual-panel {
  display: none;
}

@media (min-width: 1024px) {
  /* Split layout: header and footer drop the centered container and align to
     the same 64px inset as the form column, so every edge lines up with the
     full-bleed visual panel. */
  .container {
    max-width: none;
    padding-inline: var(--shell-inset);
  }

  /* The main container must not clamp or pad the layout: the visual panel
     runs to the right viewport edge, so the inset moves onto the form
     column instead. Flex chain (shell -> main -> container -> layout) gives
     the layout a real height to stretch into without percentage heights. */
  .site-main {
    display: flex;
    padding-block: 0;
  }

  .site-main > .container {
    display: flex;
    flex-direction: column;
    max-width: none;
    padding-inline: 0;
  }

  .auth-layout {
    flex: 1 1 auto;
    display: grid;
    grid-template-columns: minmax(0, 7fr) minmax(0, 9fr);
    align-items: stretch;
  }

  /* Vertical rhythm of the form column. Still a fixed top inset, not flex
     centering (task-084 P1-2): centering only applies while the content fits
     the main area, so a page one line taller silently switches to
     top-alignment and jumps ~40px up. Every desktop page therefore starts
     its section tag at the same y.

     The inset is 48px, not the 128px task-084 used to match the mockup
     rhythm (section tag at y=212). task-085 traded that single mockup number
     for the stronger requirement that the login submit button stays visible
     without scrolling on a 1366x768 laptop (~660px after browser chrome):
     48px inset + a 16px rhythm inside the column puts the button bottom at
     646px instead of 906px. Do not grow these back without re-measuring
     that button. */
  .auth-layout__form {
    max-width: var(--form-column-max);
    margin-inline: var(--shell-inset) 0;
    padding-block: var(--space-8);
    gap: var(--space-4);
  }

  .visual-panel {
    position: relative;
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
    align-items: flex-start;
    gap: var(--space-3);
    min-height: 520px;
    padding: var(--space-7) var(--shell-inset) var(--space-8);
    overflow: hidden;
    background-color: var(--udinus-paper);
    color: var(--udinus-muted);
  }

  /* Motif: large quarter circles on a 130px grid, checkerboarded through a
     260px super-cell (one strong tint at the cell's top-left corner, one
     soft tint at its bottom-right). Confined to the top-right 520px square
     so panel copy always sits on the plain paper background and keeps its
     measured contrast ratio. The height cap reserves room for that copy on
     short desktop viewports. */
  .visual-panel::before {
    content: "";
    position: absolute;
    top: 0;
    right: 0;
    width: 520px;
    height: min(520px, calc(100% - 180px));
    background-image:
      radial-gradient(circle at 0 0, var(--panel-motif-strong) 0 129px, transparent 130px),
      radial-gradient(circle at 100% 100%, var(--panel-motif-soft) 0 129px, transparent 130px);
    background-size: 260px 260px;
    background-position: right top;
    pointer-events: none;
  }

  .visual-panel > * {
    position: relative;
    max-width: 34ch;
  }

  /* The panel rule is shorter than the heading rule in the form column. */
  .visual-panel .accent-rule {
    width: 40px;
  }

  .visual-panel__title {
    font-size: 28px;
    font-weight: var(--font-weight-heading);
    letter-spacing: -0.01em;
    color: var(--udinus-blue);
  }

  .visual-panel__caption {
    color: var(--udinus-muted);
  }
}

/* --------------------------------------------------------------------------
 * Form fields. Inputs are 52px tall with a 1.5px deep blue border; the
 * optional toggle button keeps a 44px square hit area inside the control.
 * -------------------------------------------------------------------------- */

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

.field__label {
  font-size: 15px;
  font-weight: var(--font-weight-label);
  color: var(--udinus-ink);
}

.field__control {
  position: relative;
  display: flex;
  min-width: 0;
}

.field__input,
.field__textarea,
.field__select {
  width: 100%;
  min-height: var(--input-height);
  padding: var(--space-3) 14px;
  border: var(--border-input);
  border-radius: var(--radius-input);
  background-color: #ffffff;
  color: var(--udinus-ink);
  font: inherit;
}

.field__textarea {
  resize: vertical;
}

.field__input::placeholder,
.field__textarea::placeholder {
  color: var(--udinus-muted);
  opacity: 1;
}

.field__input:disabled,
.field__textarea:disabled,
.field__select:disabled {
  background-color: var(--udinus-paper);
  color: var(--udinus-muted);
  cursor: not-allowed;
}

.field__input[aria-invalid="true"],
.field__textarea[aria-invalid="true"],
.field__select[aria-invalid="true"] {
  border-color: var(--error-border);
  background-color: var(--error-bg);
}

.field__input[aria-invalid="true"]:focus-visible,
.field__textarea[aria-invalid="true"]:focus-visible {
  outline-color: var(--error-border);
}

.field--password .field__input {
  padding-right: 56px;
}

/* Password visibility toggle button (wired by static/js/santun-auth.js).
 * The icon/text inside is supplied by the template; this rule only fixes
 * position and the 44px minimum hit area. */
.field__toggle {
  position: absolute;
  top: 50%;
  right: var(--space-1);
  transform: translateY(-50%);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--hit-min);
  height: var(--hit-min);
  border: 0;
  border-radius: var(--radius-input);
  background-color: transparent;
  color: var(--udinus-blue-deep);
  cursor: pointer;
}

.field__toggle:hover {
  color: var(--udinus-blue);
}

/* Only one eye icon shows at a time; swap on toggle state. */
.field__toggle .icon-hide {
  display: none;
}

.field__toggle[aria-pressed="true"] .icon-show {
  display: none;
}

.field__toggle[aria-pressed="true"] .icon-hide {
  display: block;
}

/* Vertical rhythm between direct children of a form (fields, actions, links). */
form > * + * {
  margin-top: var(--space-4);
}

.field__help {
  font-size: 13px;
  color: var(--udinus-muted);
}

.field__error {
  font-size: 13px;
  font-weight: var(--font-weight-body-medium);
  color: var(--error-text);
}

/* --------------------------------------------------------------------------
 * Buttons. Primary: gold with ink text. Secondary: white with a 1.5px deep
 * blue outline. All variants keep at least a 44px hit area.
 * -------------------------------------------------------------------------- */

.button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  min-height: var(--hit-min);
  padding: var(--space-3) var(--space-5);
  border: 1.5px solid transparent;
  border-radius: var(--radius-control);
  font: inherit;
  font-size: 16px;
  font-weight: var(--font-weight-label);
  text-decoration: none;
  cursor: pointer;
  transition: background-color 0.15s ease, border-color 0.15s ease,
    color 0.15s ease;
}

.button--primary {
  padding: 15px 24px;
  background-color: var(--udinus-gold);
  color: var(--udinus-ink);
}

.button--primary:hover {
  background-color: var(--udinus-gold-strong);
}

.button--primary:focus-visible {
  outline-color: var(--udinus-blue-deep);
}

.button--secondary {
  padding: 15px 24px;
  background-color: #ffffff;
  color: var(--udinus-blue);
  border-color: var(--udinus-blue-deep);
}

.button--secondary:hover {
  background-color: var(--udinus-paper);
}

.button--danger {
  background-color: #ffffff;
  color: var(--error-border);
  border-color: var(--error-border);
}

.button--danger:hover {
  background-color: var(--error-bg);
}

.button--danger:focus-visible {
  outline-color: var(--error-border);
}

.button:disabled,
.button[aria-disabled="true"] {
  cursor: not-allowed;
  opacity: 0.65;
}

/* Full-width call to action (applied by templates on primary CTAs; mobile
 * media query below also widens form action buttons automatically). */
.button--block {
  display: flex;
  width: 100%;
}

/* Pending state, set by static/js/santun-auth.js while the form submits.
 * Lightweight single-spinner indicator; disabled look without losing the
 * label. Animations are neutralized by the reduced-motion block below. */
.button.is-loading {
  cursor: progress;
}

.button.is-loading::after {
  content: "";
  width: 16px;
  height: 16px;
  border-radius: 50%;
  border: 2px solid currentColor;
  border-right-color: transparent;
  animation: santun-spin 0.8s linear infinite;
}

@keyframes santun-spin {
  to {
    transform: rotate(360deg);
  }
}

.form-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
}

/* Trailing helper row inside a form (for example the "forgot password" link
 * between the password field and the submit button). */
.form-aside {
  display: flex;
  justify-content: flex-end;
}

/* Standalone in-page link that needs the 44px minimum hit area (for example
 * the "forgot password" link placed above the submit button). */
.link-action {
  display: inline-flex;
  align-items: center;
  min-height: var(--hit-min);
  font-weight: var(--font-weight-label);
}

/* --------------------------------------------------------------------------
 * Status blocks: 4px left border + flat background. Not cards: no shadow,
 * no full border. Variants: info (default), success, error.
 * -------------------------------------------------------------------------- */

.status-block {
  border-left: var(--accent-width) solid var(--udinus-blue);
  background-color: var(--udinus-paper);
  color: var(--udinus-ink);
  padding: 14px 16px;
}

/* Stacked status blocks (multiple messages/errors) keep vertical rhythm. */
.status-block + .status-block {
  margin-top: var(--space-3);
}

.status-block__title {
  font-size: 15px;
  font-weight: var(--font-weight-subheading);
  margin-bottom: var(--space-1);
}

.status-block__title:last-child {
  margin-bottom: 0;
}

.status-block--info {
  border-left-color: var(--udinus-blue);
  background-color: var(--udinus-paper);
  color: var(--udinus-ink);
}

.status-block--success {
  border-left-color: var(--success-border);
  background-color: var(--success-bg);
  color: var(--success-text);
}

.status-block--error {
  border-left-color: var(--error-border);
  background-color: var(--error-bg);
  color: var(--error-text);
}

.status-block a {
  color: inherit;
  font-weight: var(--font-weight-label);
}

/* --------------------------------------------------------------------------
 * Permission list (OAuth consent): semantic list, one permission per item,
 * separated by thin lines. Used inside .status-block--info or on its own.
 * -------------------------------------------------------------------------- */

.permission-list {
  list-style: none;
  padding: 0;
}

.permission-list li {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  padding: var(--space-3) 0;
  border-bottom: 1px solid var(--udinus-line);
  min-width: 0;
}

.permission-list li:last-child {
  border-bottom: 0;
}

.permission-list li::before {
  content: "";
  flex: none;
  width: 8px;
  height: 8px;
  margin-top: 7px;
  background-color: var(--udinus-gold);
}

.permission-list__label {
  font-weight: var(--font-weight-label);
}

.permission-list__text {
  flex: 1 1 auto;
  min-width: 0;
  font-size: 14px;
}

/* --------------------------------------------------------------------------
 * Footer. Confirmed address (product decision 2026-10-07):
 * "Jl. Imam Bonjol No. 207, Semarang" — rendered by the template inside
 * an <address> element. Not sticky; follows the page flow.
 * -------------------------------------------------------------------------- */

.site-footer {
  border-top: var(--accent-width) solid var(--udinus-gold);
  background-color: #ffffff;
}

/* Footer security strip: the shell's single render of the anti-phishing
 * notice (task-085 moved it out of the form flow, where it cost ~148px above
 * the login button). Full-width paper band directly under the gold rule, so
 * it reads as part of the chrome rather than a step in the task; on mobile
 * the footer follows the form, which makes the same element the footnote
 * right under the submit button. Never display:none — the exact host it
 * shows is the point of the notice. */
.site-footer__security {
  border-bottom: 1px solid var(--udinus-line);
  background-color: var(--udinus-paper);
  color: var(--udinus-ink);
  font-size: 14px;
}

.site-footer__security > .container {
  padding-block: var(--space-3);
}

.site-footer__inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2) var(--space-5);
  padding-block: var(--space-5);
  color: var(--udinus-muted);
  font-size: 14px;
}

.site-footer__legal {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
}

/* Decorative separator between the copyright line and the address. */
.site-footer__legal address::before {
  content: "·";
  margin-right: var(--space-2);
}

.site-footer address {
  font-style: normal;
}

/* --------------------------------------------------------------------------
 * OAuth consent density (task-086, reworked by task-087).
 *
 * task-086 tried a two-column grid. It was shorter but stopped looking like a
 * Santun form, so task-087 restored the normal ~400px single column and buys
 * the height back from spacing and copy instead of from layout:
 *   - the shell intro is not rendered on consent at all (template override);
 *   - metadata blocks sit on a tighter rhythm than the 24px shell gap;
 *   - the static permission collection flows inline and wraps naturally;
 *   - the decision explanation uses the otherwise spacious visual panel.
 *
 * Nothing is hidden at any viewport: every scope, claim, email and warning is
 * in the DOM and visible. Below the desktop split, the same decision node moves
 * below the form as a compact note, so it is announced only once.
 * -------------------------------------------------------------------------- */

.consent-body {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  min-width: 0;
}

/* App identity + active account: grouped tighter than the 24px shell rhythm
   because they are reference data, not the decision. */
.consent-meta {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  min-width: 0;
}

.consent-meta__block {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

/* The app name and the account name are reference lines inside a form, not
   page headings; the shell's clamp(20px, 2.5vw, 24px) is oversized here. */
.consent-meta__block .page-subheading {
  font-size: 18px;
  line-height: 1.35;
}

/* "Ganti akun" is a real secondary control now (task-087). Inline-flex keeps
   it at its text width on desktop while .button already guarantees the 44px
   minimum hit area; the mobile block below stretches it full width. */
.consent-switch {
  align-self: flex-start;
  margin-top: var(--space-2);
  /* 12px vertical padding clears the 44px minimum by ~4px instead of the
     0.5px that 10px produced - a font or line-height change must not be
     able to drop this control under the hit-area floor. */
  padding: 12px var(--space-4);
  font-size: 15px;
}

.consent-permissions {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  min-width: 0;
}

/* A semantic list of static values, not interactive chips. Inline flex keeps
   short permissions on one row and wraps complete, untruncated items only
   when their content needs more room. */
.permission-list--inline {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--space-1) var(--space-4);
}

.consent-permissions .permission-list--inline li {
  display: inline-flex;
  flex: 0 1 auto;
  gap: var(--space-2);
  min-width: 0;
  padding: 0;
  border: 0;
}

.consent-permissions .permission-list--inline li::before {
  margin-top: 6px;
}

.consent-permissions .permission-list--inline :is(.permission-list__text, .permission-list__label) {
  overflow-wrap: anywhere;
}

/* Below the desktop split, the shared panel is normally absent. The consent
   variant instead follows the form as a compact note, preserving all copy in
   one accessible node without adding height before the decision buttons. */
.visual-panel--consent {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  width: 100%;
  max-width: 560px;
  min-height: 0;
  margin: var(--space-5) auto 0;
  padding: var(--space-3) var(--space-4);
  border-left: var(--accent-width) solid var(--udinus-blue);
  background-color: var(--udinus-paper);
  color: var(--udinus-ink);
}

.visual-panel--consent .accent-rule {
  display: none;
}

.visual-panel--consent .visual-panel__title {
  font-size: 15px;
  font-weight: var(--font-weight-subheading);
  color: var(--udinus-ink);
}

.visual-panel--consent .visual-panel__caption {
  color: var(--udinus-ink);
  font-size: 13px;
  line-height: 1.5;
}

/* Consent is the only shell page whose column is taller than the viewport on
   a 1366x768 laptop. Trimming the shell inset here (and only here) lifts the
   decision without touching the measured positions on every other page. */
@media (min-width: 1024px) {
  .auth-layout__form:has(.consent-body) {
    padding-block: var(--space-6);
  }

  /* On desktop, restore the regular visual-panel presentation. These
     declarations override the compact fallback without duplicating markup. */
  .visual-panel--consent {
    width: auto;
    max-width: none;
    min-height: 520px;
    margin: 0;
    padding: var(--space-7) var(--shell-inset) var(--space-8);
    border-left: 0;
    background-color: var(--udinus-paper);
    color: var(--udinus-muted);
  }

  .visual-panel--consent .accent-rule {
    display: block;
  }

  .visual-panel--consent .visual-panel__title {
    font-size: 28px;
    font-weight: var(--font-weight-heading);
    color: var(--udinus-blue);
  }

  .visual-panel--consent .visual-panel__caption {
    color: var(--udinus-muted);
    font-size: 16px;
    line-height: 1.5;
  }
}

/* --------------------------------------------------------------------------
 * Responsive behavior.
 * -------------------------------------------------------------------------- */

/* Mobile: top bar hidden, compact lockup, full-width CTAs. */
@media (max-width: 639.98px) {
  .site-header__top-bar {
    display: none;
  }

  .form-actions .button {
    width: 100%;
  }

  /* Secondary account switch matches the stacked full-width action rhythm. */
  .consent-switch {
    align-self: stretch;
    width: 100%;
  }
}

/* Very narrow viewports (200% zoom on small phones): the issuer URL in the
 * header cannot shrink below its content width and forces horizontal scroll.
 * The same address is shown by the anti-phishing notice on every page body,
 * so the header copy is dropped here instead (reflow, WCAG 1.4.10). The
 * threshold also covers the production issuer string ("https://…dinus.ac.id")
 * which is wider than local QA hosts. */
@media (max-width: 299px) {
  .site-header__actions {
    display: none;
  }
}

@media (max-width: 379px) {
  :root {
    --gutter: 16px;
  }

  .site-header__logo {
    height: 34px;
  }

  .site-header__name {
    font-size: 16px;
  }
}

/* --------------------------------------------------------------------------
 * Reduced motion: disable transitions and animations. The pending spinner
 * falls back to a static ring; layout is unaffected. Declarations carry
 * !important because component rules set durations through the shorthand
 * `transition`/`animation` properties at higher specificity (class
 * selectors beat the universal selector), which silently kept the button,
 * skip-link, and spinner animated for reduced-motion users.
 * -------------------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    transition-delay: 0ms !important;
    scroll-behavior: auto !important;
  }
}
