/* ==========================================================================
   PIGUEN — Design System
   A premium VTU/fintech interface language.

   Visual concept: "Hairline & Sheet".
   Crisp 1px rules, restrained elevation, a neutral slate canvas, and the
   tenant's brand colour used strictly as an accent — never as a wash.

   Everything here is token-driven so a tenant's primary/secondary colour can
   swing anywhere on the wheel without the interface losing contrast or
   legibility. Neutrals are deliberately independent of the brand.

   Loaded by:  partials/pg/css.links.hbs
   Paired with: /assets/piguen/piguen.js
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. TOKENS — LIGHT (default)
   -------------------------------------------------------------------------- */
:root {
  /* Brand — seeded server-side from tenant config, refined by piguen.js.
     Never reference a literal brand colour anywhere else in this file. */
  --pg-brand:         #4F46E5;
  --pg-brand-rgb:     79, 70, 229;
  --pg-brand-hover:   #4338CA;
  --pg-brand-soft:    rgba(79, 70, 229, 0.10);
  --pg-brand-softer:  rgba(79, 70, 229, 0.05);
  --pg-brand-line:    rgba(79, 70, 229, 0.22);
  /* Foreground used on top of a solid brand fill. piguen.js flips this to a
     dark ink when the tenant picks a pale brand colour. */
  --pg-on-brand:      #FFFFFF;
  /* Brand adjusted for legibility as TEXT/ICON on a surface. piguen.js
     darkens (light theme) or lightens (dark theme) until it clears WCAG AA,
     so a pale or near-black tenant colour stays readable in links and icons.
     Use --pg-brand for fills, --pg-brand-ink for anything you must read. */
  --pg-brand-ink:     #4F46E5;

  --pg-accent:        #0EA5A4;
  --pg-accent-rgb:    14, 165, 164;

  /* Neutral canvas */
  --pg-bg:            #F6F7F9;
  --pg-surface:       #FFFFFF;
  --pg-surface-muted: #F2F4F7;
  --pg-surface-sunken: #ECEFF3;

  /* Ink */
  --pg-text:          #10151C;
  --pg-text-2:        #525B6A;
  --pg-text-3:        #8B94A3;
  --pg-text-inverse:  #FFFFFF;

  /* Lines */
  --pg-border:        #E5E8EC;
  --pg-border-strong: #D2D7DE;

  /* Status — each has a solid, a soft fill and a line tint */
  --pg-success:       #067A55;
  --pg-success-soft:  #E3F5EE;
  --pg-success-line:  #A8E0CC;

  --pg-warning:       #B45309;
  --pg-warning-soft:  #FDF2E3;
  --pg-warning-line:  #F3D3A4;

  --pg-danger:        #C62839;
  --pg-danger-soft:   #FDECEE;
  --pg-danger-line:   #F5C0C6;

  --pg-info:          #1D4ED8;
  --pg-info-soft:     #E9EFFD;
  --pg-info-line:     #BDD0F8;

  /* Money semantics */
  --pg-credit:        var(--pg-success);
  --pg-debit:         var(--pg-text);

  /* Type */
  --pg-font: 'Plus Jakarta Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI',
             Roboto, Helvetica, Arial, sans-serif;
  --pg-font-num: 'Plus Jakarta Sans', ui-monospace, 'SF Mono', monospace;

  --pg-t-display: 1.75rem;   /* 28 — balances, hero figures */
  --pg-t-h1:      1.375rem;  /* 22 */
  --pg-t-h2:      1.125rem;  /* 18 */
  --pg-t-h3:      1rem;      /* 16 */
  --pg-t-body:    0.9375rem; /* 15 */
  --pg-t-sm:      0.875rem;  /* 14 */
  --pg-t-caption: 0.8125rem; /* 13 */
  --pg-t-label:   0.75rem;   /* 12 */
  --pg-t-micro:   0.6875rem; /* 11 */

  --pg-w-regular:  400;
  --pg-w-medium:   500;
  --pg-w-semibold: 600;
  --pg-w-bold:     700;
  --pg-w-extra:    800;

  --pg-lh-tight:  1.2;
  --pg-lh-snug:   1.35;
  --pg-lh-normal: 1.5;
  --pg-lh-loose:  1.65;

  /* Spacing — strict 4px base */
  --pg-1:  4px;
  --pg-2:  8px;
  --pg-3:  12px;
  --pg-4:  16px;
  --pg-5:  20px;
  --pg-6:  24px;
  --pg-8:  32px;
  --pg-10: 40px;
  --pg-12: 48px;
  --pg-16: 64px;

  /* Radius — tighter than a typical card UI, intentionally */
  --pg-r-xs:   6px;
  --pg-r-sm:   8px;
  --pg-r-md:   12px;
  --pg-r-lg:   16px;
  --pg-r-xl:   20px;
  --pg-r-full: 999px;

  /* Elevation — near-flat; structure comes from rules, not shadows */
  --pg-shadow-xs: 0 1px 2px rgba(16, 21, 28, 0.04);
  --pg-shadow-sm: 0 1px 3px rgba(16, 21, 28, 0.06), 0 1px 2px rgba(16, 21, 28, 0.04);
  --pg-shadow-md: 0 4px 12px rgba(16, 21, 28, 0.07), 0 1px 3px rgba(16, 21, 28, 0.05);
  --pg-shadow-lg: 0 12px 32px rgba(16, 21, 28, 0.10), 0 2px 8px rgba(16, 21, 28, 0.05);
  --pg-shadow-sheet: 0 -8px 32px rgba(16, 21, 28, 0.14);

  /* Motion */
  --pg-fast:  140ms;
  --pg-base:  200ms;
  --pg-slow:  280ms;
  --pg-ease:  cubic-bezier(0.4, 0, 0.2, 1);
  --pg-ease-out: cubic-bezier(0.16, 1, 0.3, 1);

  /* Layout */
  --pg-canvas:    1120px;
  --pg-gutter:    16px;
  --pg-topbar-h:  60px;
  --pg-bottomnav-h: 64px;

  /* ----------------------------------------------------------------------
     Bridge tokens.
     toast.js and txmodal.js are shared, template-agnostic modules that theme
     themselves off --sd-* variables. Aliasing them onto PIGUEN tokens lets
     both templates reuse the exact same JS — including in dark mode — with
     no forking and no duplicated markup.
     ---------------------------------------------------------------------- */
  --sd-surface:      var(--pg-surface);
  --sd-surface-3:    var(--pg-surface-muted);
  --sd-text-primary: var(--pg-text);
  --sd-text-muted:   var(--pg-text-2);
  --sd-border:       var(--pg-border);
  --sd-success:      var(--pg-success);
  --sd-warning:      var(--pg-warning);
  --sd-danger:       var(--pg-danger);
  --sd-info:         var(--pg-info);
}

/* --------------------------------------------------------------------------
   2. TOKENS — DARK
   Purpose-built surfaces, not an inversion. Borders lift rather than darken,
   and soft status fills are rebuilt at low alpha so they read on near-black.
   -------------------------------------------------------------------------- */
[data-theme="dark"] {
  --pg-bg:            #0A0C10;
  --pg-surface:       #13171E;
  --pg-surface-muted: #1A1F27;
  --pg-surface-sunken: #0E1116;

  --pg-text:          #EEF1F5;
  --pg-text-2:        #9BA4B2;
  --pg-text-3:        #69727F;

  --pg-border:        #242A33;
  --pg-border-strong: #333B46;

  --pg-success:       #34D399;
  --pg-success-soft:  rgba(52, 211, 153, 0.13);
  --pg-success-line:  rgba(52, 211, 153, 0.30);

  --pg-warning:       #FBBF24;
  --pg-warning-soft:  rgba(251, 191, 36, 0.13);
  --pg-warning-line:  rgba(251, 191, 36, 0.30);

  --pg-danger:        #F87171;
  --pg-danger-soft:   rgba(248, 113, 113, 0.13);
  --pg-danger-line:   rgba(248, 113, 113, 0.30);

  --pg-info:          #60A5FA;
  --pg-info-soft:     rgba(96, 165, 250, 0.13);
  --pg-info-line:     rgba(96, 165, 250, 0.30);

  --pg-debit:         var(--pg-text);

  --pg-shadow-xs: 0 1px 2px rgba(0, 0, 0, 0.4);
  --pg-shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.45);
  --pg-shadow-md: 0 4px 12px rgba(0, 0, 0, 0.5);
  --pg-shadow-lg: 0 12px 32px rgba(0, 0, 0, 0.6);
  --pg-shadow-sheet: 0 -8px 32px rgba(0, 0, 0, 0.6);
}

/* --------------------------------------------------------------------------
   3. RESET & BASE
   -------------------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }

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

body {
  margin: 0;
  font-family: var(--pg-font);
  font-size: var(--pg-t-body);
  line-height: var(--pg-lh-normal);
  color: var(--pg-text);
  background: var(--pg-bg);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: hidden;
  /* Never let a horizontal scrollbar appear on small screens */
  max-width: 100vw;
}

h1, h2, h3, h4, h5, h6, p, figure, blockquote, dl, dd { margin: 0; }
ul, ol { margin: 0; padding: 0; list-style: none; }

img, svg, video { display: block; max-width: 100%; }
svg { flex-shrink: 0; }

a { color: inherit; text-decoration: none; }

button, input, select, textarea {
  font: inherit;
  color: inherit;
  margin: 0;
}
button { background: none; border: none; padding: 0; cursor: pointer; }

/* Kill the iOS tap flash — we provide our own press states */
a, button, [role="button"], label, input, select, textarea {
  -webkit-tap-highlight-color: transparent;
}

/* Accessible focus. Visible on keyboard, suppressed on pointer. */
:focus { outline: none; }
:focus-visible {
  outline: 2px solid var(--pg-brand);
  outline-offset: 2px;
  border-radius: var(--pg-r-xs);
}

::selection {
  background: var(--pg-brand-soft);
  color: var(--pg-text);
}

/* Scrollbars — slim and neutral */
* { scrollbar-width: thin; scrollbar-color: var(--pg-border-strong) transparent; }
::-webkit-scrollbar { width: 8px; height: 8px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
  background: var(--pg-border-strong);
  border-radius: var(--pg-r-full);
}

/* --------------------------------------------------------------------------
   4. UTILITY SHIMS
   PIGUEN does not load Bootstrap. Validator.js toggles `.d-none` on error
   slots and some shared markup uses `.text-danger`, so those two contracts
   are honoured here rather than by pulling in a 200KB stylesheet.
   -------------------------------------------------------------------------- */
.d-none { display: none !important; }
.text-danger { color: var(--pg-danger) !important; }

.pg-sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.pg-truncate {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
}

/* --------------------------------------------------------------------------
   5. TYPOGRAPHY
   -------------------------------------------------------------------------- */
.pg-display {
  font-size: var(--pg-t-display);
  font-weight: var(--pg-w-extra);
  line-height: var(--pg-lh-tight);
  letter-spacing: -0.025em;
}
.pg-h1 {
  font-size: var(--pg-t-h1);
  font-weight: var(--pg-w-bold);
  line-height: var(--pg-lh-tight);
  letter-spacing: -0.02em;
}
.pg-h2 {
  font-size: var(--pg-t-h2);
  font-weight: var(--pg-w-bold);
  line-height: var(--pg-lh-snug);
  letter-spacing: -0.015em;
}
.pg-h3 {
  font-size: var(--pg-t-h3);
  font-weight: var(--pg-w-semibold);
  line-height: var(--pg-lh-snug);
  letter-spacing: -0.01em;
}
.pg-body   { font-size: var(--pg-t-body); line-height: var(--pg-lh-normal); }
.pg-sm     { font-size: var(--pg-t-sm); line-height: var(--pg-lh-normal); }
.pg-caption{ font-size: var(--pg-t-caption); line-height: var(--pg-lh-snug); color: var(--pg-text-2); }
.pg-micro  { font-size: var(--pg-t-micro); line-height: var(--pg-lh-snug); color: var(--pg-text-3); }

.pg-label {
  font-size: var(--pg-t-label);
  font-weight: var(--pg-w-semibold);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--pg-text-3);
}

.pg-muted   { color: var(--pg-text-2); }
.pg-subtle  { color: var(--pg-text-3); }

/* Financial figures. Tabular numerals keep columns of money aligned and stop
   digits jittering when a balance updates. */
.pg-num {
  font-family: var(--pg-font-num);
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1, "lnum" 1;
  letter-spacing: -0.01em;
}
.pg-amount {
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
  font-weight: var(--pg-w-bold);
  letter-spacing: -0.015em;
  white-space: nowrap;
}
.pg-amount--credit { color: var(--pg-credit); }
.pg-amount--debit  { color: var(--pg-debit); }

/* --------------------------------------------------------------------------
   6. LAYOUT — the PIGUEN shell
   Mobile: content column + fixed bottom tab bar.
   Desktop: top command bar over a centred canvas. No sidebar, by design.
   -------------------------------------------------------------------------- */
.pg-app {
  min-height: 100vh;
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
  background: var(--pg-bg);
}

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

.pg-main {
  flex: 1;
  padding-block: var(--pg-5) var(--pg-8);
  /* Clear the fixed bottom nav plus the iOS home indicator */
  padding-bottom: calc(var(--pg-bottomnav-h) + var(--pg-8) + env(safe-area-inset-bottom));
}
/* Purchase pages swap the tab bar for a sticky action bar, which is taller.
   Reserve for that instead, or the last field sits under the pay button. */
.pg-main--sticky {
  padding-bottom: calc(84px + var(--pg-8) + env(safe-area-inset-bottom));
}

.pg-stack   { display: flex; flex-direction: column; gap: var(--pg-5); }
.pg-stack-4 { display: flex; flex-direction: column; gap: var(--pg-4); }
.pg-stack-3 { display: flex; flex-direction: column; gap: var(--pg-3); }
.pg-stack-2 { display: flex; flex-direction: column; gap: var(--pg-2); }
.pg-row     { display: flex; align-items: center; gap: var(--pg-3); }
.pg-row-between { display: flex; align-items: center; justify-content: space-between; gap: var(--pg-3); }
.pg-spacer  { flex: 1; }

@media (min-width: 900px) {
  :root { --pg-gutter: 32px; }
  .pg-main {
    padding-block: var(--pg-8) var(--pg-16);
    padding-bottom: var(--pg-16);
  }
}

/* --------------------------------------------------------------------------
   7. SECTION HEADING
   -------------------------------------------------------------------------- */
.pg-section__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--pg-3);
  margin-bottom: var(--pg-3);
}
.pg-section__title {
  font-size: var(--pg-t-h3);
  font-weight: var(--pg-w-bold);
  letter-spacing: -0.01em;
  color: var(--pg-text);
}
.pg-section__action {
  font-size: var(--pg-t-sm);
  font-weight: var(--pg-w-semibold);
  color: var(--pg-brand-ink);
  display: inline-flex;
  align-items: center;
  gap: var(--pg-1);
  /* Text-sized links are ~21px tall, under the 24px minimum target size.
     Pad the hit area out without moving the text off the heading baseline. */
  min-height: 32px;
  padding-inline: var(--pg-1);
  margin-inline: calc(var(--pg-1) * -1);
  border-radius: var(--pg-r-xs);
  transition: opacity var(--pg-fast) var(--pg-ease);
}
.pg-section__action:hover { opacity: 0.72; }

/* --------------------------------------------------------------------------
   8. SURFACES
   The core PIGUEN surface is a bordered sheet with almost no shadow.
   Grouped content uses internal hairlines rather than a card per item.
   -------------------------------------------------------------------------- */
.pg-sheet {
  background: var(--pg-surface);
  border: 1px solid var(--pg-border);
  border-radius: var(--pg-r-lg);
  overflow: hidden;
}
.pg-sheet--pad    { padding: var(--pg-5); }
.pg-sheet--raised { box-shadow: var(--pg-shadow-sm); }
.pg-sheet--flush  { border-radius: 0; border-inline: 0; }

/* Grouped rows separated by hairlines — PIGUEN's primary list idiom */
.pg-group > * + * { border-top: 1px solid var(--pg-border); }

.pg-rowitem {
  display: flex;
  align-items: center;
  gap: var(--pg-3);
  padding: var(--pg-4) var(--pg-5);
  width: 100%;
  text-align: left;
  transition: background-color var(--pg-fast) var(--pg-ease);
}
a.pg-rowitem:hover,
button.pg-rowitem:hover { background: var(--pg-surface-muted); }
a.pg-rowitem:active,
button.pg-rowitem:active { background: var(--pg-surface-sunken); }

.pg-rowitem__body  { flex: 1; min-width: 0; }
.pg-rowitem__title {
  font-size: var(--pg-t-sm);
  font-weight: var(--pg-w-semibold);
  color: var(--pg-text);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.pg-rowitem__meta {
  font-size: var(--pg-t-caption);
  color: var(--pg-text-3);
  margin-top: 1px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.pg-rowitem__end { text-align: right; flex-shrink: 0; }

/* Icon tile used across rows, services and empty states */
.pg-tile {
  width: 40px; height: 40px;
  border-radius: var(--pg-r-md);
  display: grid;
  place-items: center;
  flex-shrink: 0;
  background: var(--pg-surface-muted);
  color: var(--pg-text-2);
}
.pg-tile--brand   { background: var(--pg-brand-soft);   color: var(--pg-brand-ink); }
.pg-tile--success { background: var(--pg-success-soft); color: var(--pg-success); }
.pg-tile--warning { background: var(--pg-warning-soft); color: var(--pg-warning); }
.pg-tile--danger  { background: var(--pg-danger-soft);  color: var(--pg-danger); }
.pg-tile--info    { background: var(--pg-info-soft);    color: var(--pg-info); }
.pg-tile--lg { width: 48px; height: 48px; border-radius: var(--pg-r-lg); }
.pg-tile--sm { width: 32px; height: 32px; border-radius: var(--pg-r-sm); }

/* --------------------------------------------------------------------------
   9. BUTTONS
   Loading never changes the button's box — the label is swapped in place and
   the element keeps its width, so nothing shifts under the user's finger.
   -------------------------------------------------------------------------- */
.pg-btn {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--pg-2);
  height: 48px;
  padding-inline: var(--pg-5);
  border-radius: var(--pg-r-md);
  font-size: var(--pg-t-sm);
  font-weight: var(--pg-w-semibold);
  letter-spacing: -0.005em;
  white-space: nowrap;
  border: 1px solid transparent;
  cursor: pointer;
  transition: background-color var(--pg-fast) var(--pg-ease),
              border-color var(--pg-fast) var(--pg-ease),
              color var(--pg-fast) var(--pg-ease),
              opacity var(--pg-fast) var(--pg-ease),
              transform var(--pg-fast) var(--pg-ease);
}
.pg-btn:active:not(:disabled) { transform: scale(0.985); }

.pg-btn--block { width: 100%; }
.pg-btn--sm { height: 38px; padding-inline: var(--pg-4); font-size: var(--pg-t-caption); border-radius: var(--pg-r-sm); }
.pg-btn--lg { height: 54px; padding-inline: var(--pg-6); font-size: var(--pg-t-body); }

.pg-btn--primary {
  background: var(--pg-brand);
  color: var(--pg-on-brand);
}
.pg-btn--primary:hover:not(:disabled) { background: var(--pg-brand-hover); }

.pg-btn--secondary {
  background: var(--pg-surface);
  color: var(--pg-text);
  border-color: var(--pg-border-strong);
}
.pg-btn--secondary:hover:not(:disabled) { background: var(--pg-surface-muted); }

.pg-btn--ghost { background: transparent; color: var(--pg-text-2); }
.pg-btn--ghost:hover:not(:disabled) { background: var(--pg-surface-muted); color: var(--pg-text); }

.pg-btn--soft { background: var(--pg-brand-soft); color: var(--pg-brand-ink); }
.pg-btn--soft:hover:not(:disabled) { background: var(--pg-brand-softer); }

.pg-btn--success { background: var(--pg-success); color: #fff; }
.pg-btn--danger  { background: var(--pg-danger);  color: #fff; }
.pg-btn--danger-soft { background: var(--pg-danger-soft); color: var(--pg-danger); }

.pg-btn:disabled,
.pg-btn[aria-disabled="true"] {
  opacity: 0.5;
  cursor: not-allowed;
  transform: none;
}

/* Loading: swap label for a spinner without resizing the button */
.pg-btn[data-loading="true"] { pointer-events: none; }
.pg-btn[data-loading="true"] .pg-btn__label { visibility: hidden; }
.pg-btn[data-loading="true"]::after {
  content: "";
  position: absolute;
  inset: 0;
  margin: auto;
  width: 18px; height: 18px;
  border-radius: 50%;
  border: 2px solid currentColor;
  border-top-color: transparent;
  animation: pg-spin 0.6s linear infinite;
}
@keyframes pg-spin { to { transform: rotate(360deg); } }

/* --------------------------------------------------------------------------
   10. FORMS
   -------------------------------------------------------------------------- */
.pg-field { display: flex; flex-direction: column; gap: var(--pg-2); }

.pg-field__label {
  font-size: var(--pg-t-caption);
  font-weight: var(--pg-w-semibold);
  color: var(--pg-text-2);
  display: flex;
  align-items: center;
  gap: var(--pg-1);
}
.pg-field__req { color: var(--pg-danger); }

/* The hint and the .field-invalid slot live INSIDE this wrap, because
   Validator.js resolves the error node via input.parentElement (see
   partials/pg/field.hbs). So the wrap must stack its children, not lay them
   out in a row — and the absolutely-positioned prefix/suffix must be pinned
   to the input's own box rather than relying on flex centring, or they drift
   down as the hint and error appear beneath it. */
.pg-field__wrap { position: relative; display: block; }

.pg-input,
.pg-select,
.pg-textarea {
  width: 100%;
  min-height: 48px;
  padding: 13px var(--pg-4);
  background: var(--pg-surface);
  border: 1px solid var(--pg-border-strong);
  border-radius: var(--pg-r-md);
  font-size: var(--pg-t-body);
  color: var(--pg-text);
  transition: border-color var(--pg-fast) var(--pg-ease),
              box-shadow var(--pg-fast) var(--pg-ease),
              background-color var(--pg-fast) var(--pg-ease);
}
.pg-textarea { min-height: 104px; resize: vertical; line-height: var(--pg-lh-normal); }

.pg-input::placeholder,
.pg-textarea::placeholder { color: var(--pg-text-3); }

.pg-input:hover:not(:disabled),
.pg-select:hover:not(:disabled),
.pg-textarea:hover:not(:disabled) { border-color: var(--pg-text-3); }

.pg-input:focus,
.pg-select:focus,
.pg-textarea:focus {
  outline: none;
  border-color: var(--pg-brand);
  box-shadow: 0 0 0 3px var(--pg-brand-soft);
}

.pg-input:disabled,
.pg-select:disabled,
.pg-textarea:disabled {
  background: var(--pg-surface-muted);
  color: var(--pg-text-3);
  cursor: not-allowed;
}

/* Error / success states. Communicated by icon + text too, never colour alone. */
.pg-input.is-invalid,
.pg-select.is-invalid,
.pg-textarea.is-invalid { border-color: var(--pg-danger); }
.pg-input.is-invalid:focus { box-shadow: 0 0 0 3px var(--pg-danger-soft); }
.pg-input.is-valid { border-color: var(--pg-success-line); }

/* Validator.js writes messages into `.field-invalid` and removes `d-none` */
.pg-field .field-invalid,
.field-invalid {
  font-size: var(--pg-t-caption);
  font-weight: var(--pg-w-medium);
  color: var(--pg-danger);
  display: flex;
  align-items: flex-start;
  gap: var(--pg-1);
  margin: 0;
}
/* Inside a field wrap these sit under the input, so they need their own
   spacing — the wrap no longer supplies a flex gap. */
.pg-field__wrap > .field-invalid { margin-top: var(--pg-2); }
.pg-field__hint {
  font-size: var(--pg-t-caption);
  color: var(--pg-text-3);
  line-height: var(--pg-lh-snug);
}
.pg-field__wrap > .pg-field__hint { display: block; margin-top: var(--pg-2); }

/* Affixes.
   Pinned to the top of the wrap and given the input's own height so they
   stay centred on the input even when a hint or error renders below it. */
.pg-field__prefix,
.pg-field__suffix {
  position: absolute;
  top: 0;
  height: 48px;
  display: flex;
  align-items: center;
  color: var(--pg-text-3);
  pointer-events: none;
  font-size: var(--pg-t-body);
  z-index: 1;
}
.pg-field__prefix { left: var(--pg-4); }
.pg-field__suffix { right: var(--pg-4); }
.pg-input--has-prefix { padding-left: 40px; }
.pg-input--has-suffix { padding-right: 44px; }
.pg-field__suffix--action { pointer-events: auto; cursor: pointer; }
.pg-field__suffix--action:hover { color: var(--pg-text); }

/* Native select chevron */
.pg-select {
  appearance: none;
  -webkit-appearance: none;
  padding-right: 40px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%238B94A3' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right var(--pg-4) center;
}

/* Numeric / OTP style boxes */
.pg-otp {
  display: flex;
  gap: var(--pg-2);
  justify-content: center;
  width: 100%;
}
/* Six fixed 48px boxes plus gaps overflow a 320px screen, so they shrink to
   fit and only cap at 48px once there is room. */
.pg-otp__box {
  flex: 1 1 0;
  min-width: 0;
  max-width: 48px;
  height: 56px;
  text-align: center;
  font-size: var(--pg-t-h1);
  font-weight: var(--pg-w-bold);
  font-variant-numeric: tabular-nums;
  border: 1px solid var(--pg-border-strong);
  border-radius: var(--pg-r-md);
  background: var(--pg-surface);
  color: var(--pg-text);
  padding: 0;
}
.pg-otp__box:focus {
  outline: none;
  border-color: var(--pg-brand);
  box-shadow: 0 0 0 3px var(--pg-brand-soft);
}

/* --------------------------------------------------------------------------
   11. STATUS BADGE
   Always icon + label. Colour is reinforcement, never the sole signal — this
   matters for colour-blind users and for the success/failed distinction.
   -------------------------------------------------------------------------- */
.pg-status {
  display: inline-flex;
  align-items: center;
  gap: var(--pg-1);
  padding: 3px var(--pg-2) 3px 6px;
  border-radius: var(--pg-r-full);
  font-size: var(--pg-t-micro);
  font-weight: var(--pg-w-semibold);
  letter-spacing: 0.01em;
  border: 1px solid transparent;
  white-space: nowrap;
}
.pg-status--success { background: var(--pg-success-soft); color: var(--pg-success); border-color: var(--pg-success-line); }
.pg-status--failed  { background: var(--pg-danger-soft);  color: var(--pg-danger);  border-color: var(--pg-danger-line); }
.pg-status--pending { background: var(--pg-warning-soft); color: var(--pg-warning); border-color: var(--pg-warning-line); }
.pg-status--info    { background: var(--pg-info-soft);    color: var(--pg-info);    border-color: var(--pg-info-line); }
.pg-status--neutral { background: var(--pg-surface-muted); color: var(--pg-text-2); border-color: var(--pg-border); }

/* The processing badge pulses gently so "in flight" reads as alive, not stuck.
   Deliberately distinct from the failed state. */
.pg-status--pending .pg-status__dot { animation: pg-pulse 1.8s var(--pg-ease) infinite; }
@keyframes pg-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.35; } }

/* --------------------------------------------------------------------------
   12. SKELETON LOADERS
   Layout-stable placeholders — same box as the real content, so nothing
   reflows when data lands.
   -------------------------------------------------------------------------- */
.pg-skel {
  position: relative;
  overflow: hidden;
  background: var(--pg-surface-muted);
  border-radius: var(--pg-r-sm);
}
.pg-skel::after {
  content: "";
  position: absolute;
  inset: 0;
  transform: translateX(-100%);
  background: linear-gradient(
    90deg,
    transparent,
    rgba(255, 255, 255, 0.45),
    transparent
  );
  animation: pg-shimmer 1.4s infinite;
}
[data-theme="dark"] .pg-skel::after {
  background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.06), transparent);
}
@keyframes pg-shimmer {100% { transform: translateX(100%); } }

.pg-skel--text  { height: 12px; border-radius: var(--pg-r-xs); }
.pg-skel--title { height: 16px; border-radius: var(--pg-r-xs); }
.pg-skel--line  { height: 12px; border-radius: var(--pg-r-xs); width: 60%; }
.pg-skel--tile  { width: 40px; height: 40px; border-radius: var(--pg-r-md); }
.pg-skel--block { height: 72px; border-radius: var(--pg-r-md); }

/* --------------------------------------------------------------------------
   13. EMPTY & ERROR STATES
   -------------------------------------------------------------------------- */
.pg-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  padding: var(--pg-12) var(--pg-5);
  gap: var(--pg-2);
}
.pg-empty__icon {
  width: 56px; height: 56px;
  border-radius: var(--pg-r-lg);
  display: grid;
  place-items: center;
  background: var(--pg-surface-muted);
  color: var(--pg-text-3);
  margin-bottom: var(--pg-2);
}
.pg-empty__title {
  font-size: var(--pg-t-h3);
  font-weight: var(--pg-w-bold);
  color: var(--pg-text);
}
.pg-empty__text {
  font-size: var(--pg-t-sm);
  color: var(--pg-text-2);
  line-height: var(--pg-lh-normal);
  max-width: 34ch;
}
.pg-empty__action { margin-top: var(--pg-4); }

/* --------------------------------------------------------------------------
   14. NOTICE / INLINE ALERT
   -------------------------------------------------------------------------- */
.pg-notice {
  display: flex;
  gap: var(--pg-3);
  padding: var(--pg-3) var(--pg-4);
  border-radius: var(--pg-r-md);
  border: 1px solid var(--pg-border);
  background: var(--pg-surface-muted);
  font-size: var(--pg-t-caption);
  line-height: var(--pg-lh-normal);
  color: var(--pg-text-2);
}
.pg-notice__icon { flex-shrink: 0; margin-top: 1px; }
.pg-notice strong { color: var(--pg-text); font-weight: var(--pg-w-semibold); }
.pg-notice--success { background: var(--pg-success-soft); border-color: var(--pg-success-line); color: var(--pg-success); }
.pg-notice--warning { background: var(--pg-warning-soft); border-color: var(--pg-warning-line); color: var(--pg-warning); }
.pg-notice--danger  { background: var(--pg-danger-soft);  border-color: var(--pg-danger-line);  color: var(--pg-danger); }
.pg-notice--info    { background: var(--pg-info-soft);    border-color: var(--pg-info-line);    color: var(--pg-info); }
.pg-notice--success strong,
.pg-notice--warning strong,
.pg-notice--danger strong,
.pg-notice--info strong { color: inherit; }

/* --------------------------------------------------------------------------
   14b. BRAND LOCKUP
   Lives in the core sheet, not the app shell, because the auth screens use it
   too and they deliberately do not load piguen-app.css.
   -------------------------------------------------------------------------- */
.pg-brand { display: flex; align-items: center; gap: var(--pg-2); min-width: 0; }
.pg-brand__mark {
  width: 32px; height: 32px;
  border-radius: var(--pg-r-sm);
  overflow: hidden;
  flex-shrink: 0;
  background: var(--pg-brand);
  color: var(--pg-on-brand);
  display: grid;
  place-items: center;
  font-size: var(--pg-t-caption);
  font-weight: var(--pg-w-bold);
  letter-spacing: -0.02em;
}
.pg-brand__mark img { width: 100%; height: 100%; object-fit: cover; }
.pg-brand__name {
  font-size: var(--pg-t-body);
  font-weight: var(--pg-w-bold);
  letter-spacing: -0.02em;
  color: var(--pg-text);
  /* Long tenant names must never push the bar out of shape */
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 42vw;
}
@media (min-width: 900px) { .pg-brand__name { max-width: 260px; } }

/* --------------------------------------------------------------------------
   14c. AUTH LAYOUT
   Split canvas: brand story panel beside the form on wide screens, form only
   on mobile. Deliberately not a centred floating card.
   -------------------------------------------------------------------------- */
/* minmax(0, …) rather than 1fr: a grid item defaults to min-width:auto, so it
   refuses to shrink below its content's min-content width. With six OTP boxes
   in the column that floor is ~360px, which overflows a 320px phone. */
.pg-auth { min-height: 100vh; min-height: 100dvh; display: grid; grid-template-columns: minmax(0, 1fr); background: var(--pg-bg); }
@media (min-width: 960px) { .pg-auth { grid-template-columns: 1.05fr minmax(0, 1fr); } }

.pg-auth__aside {
  display: none;
  position: relative;
  overflow: hidden;
  background: var(--pg-brand);
  color: var(--pg-on-brand);
  padding: var(--pg-16) var(--pg-12);
  flex-direction: column;
  justify-content: space-between;
}
@media (min-width: 960px) { .pg-auth__aside { display: flex; } }
.pg-auth__aside::after {
  content: "";
  position: absolute;
  bottom: -30%; left: -15%;
  width: 460px; height: 460px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.06);
  pointer-events: none;
}
.pg-auth__aside > * { position: relative; z-index: 1; }

.pg-auth__panel {
  display: flex;
  flex-direction: column;
  justify-content: center;
  min-width: 0;                 /* see the grid note above */
  padding: var(--pg-8) var(--pg-gutter) var(--pg-12);
  padding-top: calc(var(--pg-8) + env(safe-area-inset-top));
}
.pg-auth__inner { width: 100%; min-width: 0; max-width: 400px; margin-inline: auto; }

@media (min-width: 960px) {
  .pg-auth__panel { padding: var(--pg-16) var(--pg-12); }
  .pg-auth__inner { max-width: 420px; }
}

/* Brand lockup shown above the form on small screens only — the aside
   already carries it once it becomes visible. */
.pg-auth__mark { margin-bottom: var(--pg-8); }
@media (min-width: 960px) { .pg-auth__mark { display: none; } }

.pg-auth__title { font-size: var(--pg-t-h1); font-weight: var(--pg-w-extra); letter-spacing: -0.03em; color: var(--pg-text); }
.pg-auth__sub { font-size: var(--pg-t-sm); color: var(--pg-text-2); margin-top: var(--pg-2); line-height: var(--pg-lh-normal); }
.pg-auth__foot { margin-top: var(--pg-6); font-size: var(--pg-t-sm); color: var(--pg-text-2); text-align: center; }
.pg-auth__foot a { color: var(--pg-brand-ink); font-weight: var(--pg-w-semibold); }
.pg-auth__foot a:hover { text-decoration: underline; }

/* Feature list on the brand panel */
.pg-auth__feat { display: flex; gap: var(--pg-3); align-items: flex-start; }
.pg-auth__feat + .pg-auth__feat { margin-top: var(--pg-5); }
.pg-auth__feat-icon {
  width: 36px; height: 36px;
  border-radius: var(--pg-r-sm);
  background: rgba(255, 255, 255, 0.16);
  display: grid;
  place-items: center;
  flex-shrink: 0;
}
.pg-auth__feat-title { font-size: var(--pg-t-sm); font-weight: var(--pg-w-bold); }
.pg-auth__feat-text { font-size: var(--pg-t-caption); opacity: 0.8; margin-top: 2px; line-height: var(--pg-lh-snug); }

/* --------------------------------------------------------------------------
   15. MOTION — global reduced-motion guard
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}
