/* ======================================================================
 * BdP skin for the Keycloak account console
 *
 * The console is a compiled React/PatternFly v5 app, so this file cannot
 * change its markup — only its tokens. That turns out to be enough: PatternFly
 * derives every component from a small set of `--pf-v5-global--*` custom
 * properties, so re-pointing those at the BdP palette carries the brand into
 * pages this file never mentions.
 *
 * The target look is the report-engine frontend
 * (report-engine/frontend/src/public/style.css): white ground, Pfadiblau for
 * links/buttons/headings, Wölflingsgelb as the accent, a zinc ramp for form
 * chrome, Jost throughout, 6px radii. Values are copied from there rather than
 * re-derived so the two services don't drift apart.
 * ====================================================================== */

@font-face {
  font-family: 'Jost';
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src:
    url('../fonts/jost-latin.woff2') format('woff2-variations'),
    url('../fonts/jost-latin.woff2') format('woff2');
}

:root {
  /* --- BdP Primärfarben ------------------------------------------- */
  --bdp-blue: #0e4278; /* Pfadiblau */
  --bdp-yellow: #ffd208; /* Wölflingsgelb */
  --bdp-red: #971b2f; /* R*R-Rot */

  /* --- Sekundärfarben ---------------------------------------------- */
  --bdp-blue-light: #a9bbce;
  --bdp-yellow-light: #ffe894;
  --bdp-kluft: #0b2341; /* Pfadiblau Dunkel — hover/active */
  --bdp-red-dark: #52111b;
  --bdp-green: #006c55; /* Waldgrün */

  /* Neutral surface ramp — the frontend puts form chrome on this rather than
     on Pfadiblau, which is what stops labels competing with the blue. */
  --bdp-surface-50: #fafafa;
  --bdp-surface-100: #f4f4f5;
  --bdp-surface-200: #e4e4e7;
  --bdp-surface-300: #d4d4d8;
  --bdp-surface-400: #a1a1aa;
  --bdp-surface-500: #71717a;
  --bdp-surface-700: #3f3f46;

  --bdp-font: 'Jost', -apple-system, system-ui, BlinkMacSystemFont, 'Segoe UI', Ubuntu, 'Helvetica Neue', sans-serif;
  --bdp-radius: 6px;

  /* Brand bar above the masthead. Geometry is copied verbatim from the
     Hitobito BdP wagon (hitobito_bdp/app/assets/stylesheets/hitobito/
     customizable/_variables.scss — $top-bar-height, $top-bar-split,
     $top-bar-slant), not re-derived, for the same reason the palette is: the
     two services have to render the same bar or the seam shows when a user
     moves between them. px, not rem, because the wagon uses px — the slant is
     a fixed 12px run over 15px, and matching the angle matters more here than
     scaling with the root font size. */
  --bdp-topbar-height: 15px;
  --bdp-topbar-split: 70%;
  --bdp-topbar-slant: 6px;

  /* ---------------------------------------------------------------- *
   * PatternFly v5 globals
   * ---------------------------------------------------------------- */
  --pf-v5-global--FontFamily--text: var(--bdp-font);
  --pf-v5-global--FontFamily--heading: var(--bdp-font);
  --pf-v5-global--FontFamily--text--vf: var(--bdp-font);
  --pf-v5-global--FontFamily--heading--vf: var(--bdp-font);

  --pf-v5-global--primary-color--100: var(--bdp-blue);
  --pf-v5-global--primary-color--200: var(--bdp-kluft);
  --pf-v5-global--primary-color--300: var(--bdp-blue);
  --pf-v5-global--primary-color--dark-100: var(--bdp-blue);

  --pf-v5-global--link--Color: var(--bdp-blue);
  --pf-v5-global--link--Color--dark: var(--bdp-blue);
  --pf-v5-global--link--Color--hover: var(--bdp-kluft);
  --pf-v5-global--link--Color--dark--hover: var(--bdp-kluft);
  --pf-v5-global--link--Color--visited: var(--bdp-blue);

  --pf-v5-global--active-color--100: var(--bdp-blue);

  --pf-v5-global--danger-color--100: var(--bdp-red);
  --pf-v5-global--danger-color--200: var(--bdp-red-dark);
  --pf-v5-global--success-color--100: var(--bdp-green);
  --pf-v5-global--warning-color--100: var(--bdp-yellow);

  --pf-v5-global--Color--100: var(--bdp-surface-700);
  --pf-v5-global--Color--200: var(--bdp-surface-500);
  --pf-v5-global--Color--dark-100: var(--bdp-surface-700);
  --pf-v5-global--Color--dark-200: var(--bdp-surface-500);
  --pf-v5-global--BorderColor--100: var(--bdp-surface-200);
  --pf-v5-global--BorderColor--dark-100: var(--bdp-surface-200);
  --pf-v5-global--BackgroundColor--200: var(--bdp-surface-100);

  --pf-v5-global--BorderRadius--sm: var(--bdp-radius);
}

body {
  font-family: var(--bdp-font);
  color: var(--bdp-surface-700);
}

/* ======================================================================
 * Masthead
 *
 * The frontend's header is a thin Pfadiblau meta bar above a white masthead
 * carrying the logo. PatternFly's masthead is dark-on-light-text by default,
 * so it is flipped to white here and the blue is kept as a top rule — the meta
 * bar's role, minus its links, which this app doesn't have.
 * ====================================================================== */

/* The modifier selectors are repeated deliberately. PatternFly sets
   --pf-v5-c-masthead--BackgroundColor again under `.pf-v5-c-masthead.pf-m-light`
   (and .pf-m-light-200), which out-specifies a bare `.pf-v5-c-masthead` — so if
   the console ever renders the masthead with one of those modifiers, a
   single-class override here would silently lose. Matching their specificity
   and winning on source order makes this hold either way. */
.pf-v5-c-masthead,
.pf-v5-c-masthead.pf-m-light,
.pf-v5-c-masthead.pf-m-light-200 {
  --pf-v5-c-masthead--BackgroundColor: #fff;
  --pf-v5-c-masthead--m-light--BackgroundColor: #fff;
  --pf-v5-c-masthead--m-light-200--BackgroundColor: #fff;

  /* PatternFly hands masthead children these tokens for "text on a dark
     masthead". Re-pointing them inside the masthead's scope flips the toggle,
     the user dropdown and the sign-out control to dark text in one move,
     rather than chasing each control's own selector. */
  --pf-v5-global--Color--100: var(--bdp-surface-700);
  --pf-v5-global--Color--light-100: var(--bdp-surface-700);
  --pf-v5-global--Color--light-200: var(--bdp-surface-500);

  /* PatternFly re-points these to their *light-ground* variants inside the
     masthead and the sidebar, because both used to be near-black. On a white
     ground they have to go back, or Pfadiblau elements render in the pale blue
     meant for dark surfaces — which is exactly what the nav's loading spinner
     did. Restated as a group because they are one decision, not seven. */
  --pf-v5-global--primary-color--100: var(--bdp-blue);
  --pf-v5-global--link--Color: var(--bdp-blue);
  --pf-v5-global--link--Color--hover: var(--bdp-kluft);
  --pf-v5-global--BorderColor--100: var(--bdp-surface-200);
  --pf-v5-global--BackgroundColor--100: #fff;
  --pf-v5-global--icon--Color--light: var(--bdp-surface-400);
  --pf-v5-global--icon--Color--dark: var(--bdp-surface-500);

  /* The blue half of the brand bar. Using a border rather than a pseudo-element
     is what reserves the space: the masthead's own height is untouched and
     nothing below it shifts. The yellow wedge is then painted over this border
     by ::before. */
  border-block-start: var(--bdp-topbar-height) solid var(--bdp-blue);
  border-bottom: 1px solid var(--bdp-surface-200);
  color: var(--bdp-surface-700);
}

/* The yellow half, sliced off at an angle — the Hitobito header's signature.
 *
 * PatternFly already sets `position: relative` on .pf-v5-c-masthead and uses
 * neither of its pseudo-elements, so this needs no positioning changes and
 * introduces no stacking context of its own.
 *
 * Two details make it land correctly:
 *
 *   - `top` is *negative*. An absolutely positioned box is laid out against its
 *     ancestor's PADDING box, so `top: 0` would sit just below the border the
 *     bar is drawn on. Pulling it up by the bar's height puts it exactly over
 *     that border.
 *
 *   - The inline insets are negative too, cancelling the masthead's own
 *     horizontal padding so the bar is full-bleed and the 70% split is measured
 *     against the real header width, as it is in the wagon. This mirrors what
 *     PatternFly does for .pf-v5-c-masthead__main::before, which cancels the
 *     same inset the same way.
 *
 * The masthead is `display: grid`; an absolutely positioned pseudo-element is
 * out of flow, so it never becomes a grid item. */
.pf-v5-c-masthead::before {
  content: '';
  position: absolute;
  z-index: 0;
  top: calc(var(--bdp-topbar-height) * -1);
  left: calc(var(--pf-v5-c-masthead--PaddingLeft, 1rem) * -1);
  right: calc(var(--pf-v5-c-masthead--PaddingRight, 1rem) * -1);
  height: var(--bdp-topbar-height);
  background-color: var(--bdp-yellow);
  clip-path: polygon(
    calc(var(--bdp-topbar-split) - var(--bdp-topbar-slant)) 0,
    100% 0,
    100% 100%,
    calc(var(--bdp-topbar-split) + var(--bdp-topbar-slant)) 100%
  );
}

/* Belt and braces for the controls that sit in the masthead. On a white ground
   dark text is unconditionally correct, so this cannot make anything worse —
   it only catches any control that reads its colour from somewhere other than
   the tokens flipped above. */
.pf-v5-c-masthead a,
.pf-v5-c-masthead .pf-v5-c-button.pf-m-plain,
.pf-v5-c-masthead .pf-v5-c-menu-toggle {
  color: var(--bdp-surface-700);
}

/* The mark is the Wort-Bild-Marke (bdp-wbm.svg): klilie plus "BdP", without the
   "Bund der Pfadfinder*innen" subline the full lockup carries. It reads better
   at masthead size, where that subline would be too small to resolve anyway.
   The lockup is fixed — the corporate design forbids redrawing it, so it is
   only ever scaled, which is why only the height is set here.

   2.5rem, down from the 2.75rem the full lockup used. The WBM's circle fills
   its whole viewBox (265.73x85.04) where the full lockup's filled 77% of a
   taller one, so at an unchanged height the klilie would have jumped about a
   third larger. This lands it back at roughly its previous optical size and
   matches the admin theme, which now uses the same value. */
.pf-v5-c-masthead__brand img,
.pf-v5-c-masthead__brand svg {
  height: 2.5rem;
  width: auto;
  max-height: 2.5rem;
}

/* ======================================================================
 * Page frame
 * ====================================================================== */

/* Both the variable and the property: the variable is PatternFly's intended
   hook, the property covers the case where a section carries a modifier that
   re-sets the background at a higher specificity than a bare class. */
.pf-v5-c-page__main,
.pf-v5-c-page__main-section {
  --pf-v5-c-page__main-section--BackgroundColor: none;

  background-color: var(--pf-v5-c-page__main-section--BackgroundColor);
}

/* ======================================================================
 * Sidebar
 *
 * PatternFly's page sidebar is near-black by default, which read as a leftover
 * once the masthead above it turned white. It is flipped to match — the same
 * change the admin theme makes, for the same reason.
 *
 * This is more than a background swap, and the reason is worth stating. The
 * console renders <PageSidebar> with no `theme` prop and PatternFly's default
 * is "dark", so no .pf-m-light class is emitted and the whole nav is built for
 * a dark ground. Its defaults are
 *
 *     --pf-v5-c-page__sidebar--BackgroundColor    BackgroundColor--dark-300
 *     --pf-v5-c-nav__link--Color                   Color--light-100  (white)
 *     --pf-v5-c-nav__link--hover--BackgroundColor  BackgroundColor--dark-200
 *     --pf-v5-c-nav__link--m-current--Background   BackgroundColor--dark-400
 *
 * and PatternFly separately re-points --pf-v5-global--Color--100/200 to their
 * *light* values inside .pf-v5-c-page__sidebar. Changing only the background
 * would leave white labels on a white sidebar. So every token that assumes a
 * dark ground is restated here — that is what the length of this block is.
 *
 * Unlike the admin theme's copy, none of this is wrapped in a light-mode
 * guard: this theme sets darkMode=false, so index.ftl never emits the class
 * that switches PatternFly to its dark theme, and there is no second mode to
 * protect.
 * ====================================================================== */

.pf-v5-c-page__sidebar,
.pf-v5-c-page__sidebar.pf-m-light {
  --pf-v5-c-page__sidebar--BackgroundColor: #fff;
  --pf-v5-c-page__sidebar--m-light--BackgroundColor: #fff;

  /* PatternFly flips these to light text for the dark sidebar. Flip them back. */
  --pf-v5-global--Color--100: var(--bdp-surface-700);
  --pf-v5-global--Color--200: var(--bdp-surface-500);

  /* PatternFly re-points these to their *light-ground* variants inside the
     masthead and the sidebar, because both used to be near-black. On a white
     ground they have to go back, or Pfadiblau elements render in the pale blue
     meant for dark surfaces — which is exactly what the nav's loading spinner
     did. Restated as a group because they are one decision, not seven. */
  --pf-v5-global--primary-color--100: var(--bdp-blue);
  --pf-v5-global--link--Color: var(--bdp-blue);
  --pf-v5-global--link--Color--hover: var(--bdp-kluft);
  --pf-v5-global--BorderColor--100: var(--bdp-surface-200);
  --pf-v5-global--BackgroundColor--100: #fff;
  --pf-v5-global--icon--Color--light: var(--bdp-surface-400);
  --pf-v5-global--icon--Color--dark: var(--bdp-surface-500);

  /* Without a rule the white sidebar and the page ground merge into one
     surface, and the nav loses its edge. */
  border-inline-end: 1px solid var(--bdp-surface-200);
  color: var(--bdp-surface-700);
}

/* The "menu" sidebar body variant is hard-coded to black-900 rather than
   token-driven, so it needs saying explicitly or it stays a black block. This
   console currently renders <PageSidebarBody> without the modifier, so the
   rule is defensive rather than load-bearing — it costs one selector and stops
   a future Keycloak that adds the modifier from reintroducing the black. */
.pf-v5-c-page__sidebar-body.pf-m-menu {
  background-color: #fff;
}

.pf-v5-c-page__sidebar .pf-v5-c-nav {
  /* Resting, hover, focus, active, current. */
  --pf-v5-c-nav__link--Color: var(--bdp-surface-700);
  --pf-v5-c-nav__link--hover--Color: var(--bdp-blue);
  --pf-v5-c-nav__link--focus--Color: var(--bdp-blue);
  --pf-v5-c-nav__link--active--Color: var(--bdp-blue);
  --pf-v5-c-nav__link--m-current--Color: var(--bdp-blue);

  --pf-v5-c-nav__link--hover--BackgroundColor: var(--bdp-surface-100);
  --pf-v5-c-nav__link--focus--BackgroundColor: var(--bdp-surface-100);
  --pf-v5-c-nav__link--active--BackgroundColor: var(--bdp-surface-100);
  --pf-v5-c-nav__link--m-current--BackgroundColor: var(--bdp-surface-100);
  --pf-v5-c-nav__item--m-current--not--m-expanded__link--BackgroundColor: var(--bdp-surface-100);

  /* Separators, which otherwise stay dark-200 and vanish on white. */
  --pf-v5-c-nav__link--before--BorderColor: var(--bdp-surface-200);
  --pf-v5-c-nav__item--before--BorderColor: var(--bdp-surface-200);

  /* Section headings and the scroll affordances on a narrow viewport. */
  --pf-v5-c-nav__section-title--Color: var(--bdp-surface-500);
  --pf-v5-c-nav__section-title--BorderBottomColor: var(--bdp-surface-200);
  --pf-v5-c-nav__scroll-button--Color: var(--bdp-surface-700);
  --pf-v5-c-nav__scroll-button--before--BorderColor: var(--bdp-surface-200);

  /* The flyout submenu is its own dark surface when the sidebar is collapsed. */
  --pf-v5-c-nav__item--m-flyout--c-menu--BackgroundColor: #fff;
  --pf-v5-c-nav__item--m-flyout--c-menu__item-description--Color: var(--bdp-surface-500);
  --pf-v5-c-nav__item--m-flyout--active__link--BackgroundColor: var(--bdp-surface-100);
  --pf-v5-c-nav__item--m-flyout--hover__link--BackgroundColor: var(--bdp-surface-100);
  --pf-v5-c-nav__item--m-flyout--focus__link--BackgroundColor: var(--bdp-surface-100);
}

/* Current nav item: blue label, Wölflingsgelb marker — the corporate design's
   signature pairing. The marker is decorative only; the current item is also
   flagged with aria-current, so nothing rests on the colour alone.
 *
 * The marker colour is set on the nav container rather than on the current
 * link, because PatternFly marks "current" on either the link or its parent
 * item depending on how the nav is built, and its ::after reads the variable
 * off whichever element ends up carrying it. Setting it on the container lets
 * it inherit down to both shapes. */
.pf-v5-c-nav {
  --pf-v5-c-nav__link--m-current--after--BorderColor: var(--bdp-yellow);
  --pf-v5-c-nav__link--m-current--after--BorderLeftWidth: 4px;
}

.pf-v5-c-nav__link.pf-m-current,
.pf-v5-c-nav__item.pf-m-current > .pf-v5-c-nav__link,
.pf-v5-c-nav__link[aria-current='page'] {
  color: var(--bdp-blue);
  font-weight: 600;
}

.pf-v5-c-nav__link:hover {
  color: var(--bdp-blue);
}

/* ======================================================================
 * Headings
 * ====================================================================== */

.pf-v5-c-title,
h1,
h2,
h3 {
  color: var(--bdp-blue);
}

.pf-v5-c-title.pf-m-2xl,
.pf-v5-c-title.pf-m-3xl,
.pf-v5-c-title.pf-m-4xl {
  font-weight: 700;
}

/* ======================================================================
 * Cards
 * ====================================================================== */

.pf-v5-c-card {
  border: 1px solid var(--bdp-surface-200);
  border-radius: var(--bdp-radius);
  box-shadow: 0 1px 2px rgb(18 18 23 / 5%);
}

/* ======================================================================
 * Controls
 *
 * Same geometry and focus treatment as the frontend's inputs and buttons, so a
 * user moving between the report app and this console doesn't cross a seam.
 * ====================================================================== */

.pf-v5-c-form-control {
  border-radius: var(--bdp-radius);
}

.pf-v5-c-form-control:focus-within {
  box-shadow: 0 0 0 0.2rem rgb(14 66 120 / 25%);
}

.pf-v5-c-form__label-text {
  font-weight: 500;
}

.pf-v5-c-button {
  border-radius: var(--bdp-radius);
  font-weight: 500;
}

.pf-v5-c-button.pf-m-primary:hover,
.pf-v5-c-button.pf-m-primary:focus {
  background-color: var(--bdp-kluft);
}

.pf-v5-c-button.pf-m-secondary {
  border-color: var(--bdp-blue);
  color: var(--bdp-blue);
}

.pf-v5-c-button.pf-m-secondary:hover,
.pf-v5-c-button.pf-m-secondary:focus {
  border-color: var(--bdp-kluft);
  color: var(--bdp-kluft);
  background-color: var(--bdp-surface-100);
}

/* Destructive actions ("Konto löschen", revoking a device) carry R*R-Rot. */
.pf-v5-c-button.pf-m-danger {
  background-color: var(--bdp-red);
}

.pf-v5-c-button.pf-m-danger:hover,
.pf-v5-c-button.pf-m-danger:focus {
  background-color: var(--bdp-red-dark);
}

/* ======================================================================
 * Loading states
 *
 * Five spinners appear in this console and only one of them centres itself.
 * They are listed individually below because the fix differs by where each
 * one lands, and the markup comes from a compiled bundle that no stylesheet
 * can reshape — the DOM position is the only handle available.
 *
 * Positions were read out of the shipped bundle rather than guessed, and
 * confirmed by rendering the real markup against the real stylesheet.
 * ====================================================================== */

/* 1. The boot screen, before any JavaScript has run
 *    (.keycloak__loading-container, in index.ftl). index.ftl centres this
 *    itself in an inline <style>; it is restated here so it keeps working
 *    regardless of what loads in between, and with dvh so it is honestly
 *    centred on mobile, where vh ignores the browser chrome. */
.keycloak__loading-container {
  display: flex;
  min-height: 100vh;
  min-height: 100dvh;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  margin: 0;
}

/* 2. The init spinner — the one that is actually visible on every cold load.
 *
 *    Until authentication resolves, the app renders a BARE <Spinner> as its
 *    entire output: no Page, no masthead, no Bullseye, nothing. So it is a
 *    direct child of #app, an ordinary block-level box at the start of an
 *    empty document, and it lands hard in the top-left corner.
 *
 *    `position: fixed` with `inset: 0` and `margin: auto` is what centres it,
 *    and it is the right tool here precisely because it needs nothing from its
 *    surroundings: no flex parent, no resolved percentage height, no :has().
 *    The spinner already has a definite width and height from its size
 *    modifier, which is the one precondition auto margins need. There is
 *    nothing else on screen at this point, so taking it out of flow costs
 *    nothing. */
#app > .pf-v5-c-spinner {
  position: fixed;
  inset: 0;
  margin: auto;
}

/* 3. The route-level Suspense fallback, which lands as a direct child of
 *    .pf-v5-c-page__main — the region beside the sidebar and below the
 *    masthead.
 *
 *    PatternFly already makes that element `display: flex; flex-direction:
 *    column`, and it is the `1fr` row of a `height: 100dvh` grid, so it has a
 *    definite height. That is the whole reason `margin: auto` is enough: on a
 *    flex item, auto margins absorb the free space on both axes. No height of
 *    our own, no :has(), no positioning. */
.pf-v5-c-page__main > .pf-v5-c-spinner {
  margin: auto;
}

/* 4. Spinners that DO arrive wrapped in a Bullseye. PatternFly centres a
 *    Bullseye with `height: 100%`, and a percentage height only resolves when
 *    the parent has a definite one — true inside the page frame, false inside
 *    a content-sized card or section, where the Bullseye collapses to the
 *    spinner's own height and align-items has nothing to centre within.
 *    A floor of its own fixes the collapsing case and changes nothing in the
 *    case that already worked.
 *
 *    The :has() qualifier keeps this to a Bullseye whose only child is a
 *    spinner. Bullseye is also PatternFly's wrapper for genuinely centred
 *    empty states, and those must keep their own height. A browser without
 *    :has() simply drops the rule — stock behaviour, not a broken layout. */
.pf-v5-l-bullseye:has(> .pf-v5-c-spinner:only-child) {
  /* Not 100vh: this usually sits below the masthead, so a full viewport
     height would overflow and add a scrollbar mid-load. */
  min-height: 60vh;
}

/* 5. The sidebar's own Suspense fallback, while the nav items load. Also a
 *    bare spinner, but deliberately NOT centred in the viewport: it belongs to
 *    the sidebar, and blowing it up to the middle of the screen would misreport
 *    what is still loading. It only needs to stop hugging the left edge. */
.pf-v5-c-nav > .pf-v5-c-spinner {
  display: block;
  margin: 1.5rem auto;
}
