/* ============================================================
 * NextGen MIS — Profile / Detail view
 * ------------------------------------------------------------
 * The shared pattern behind the record-profile screens:
 *   - Beneficiary profile  (/beneficiary/detail/{regNo})
 *   - Applicant  profile   (/registration/applicant/{regNo})
 *   - Beneficiary update    (/update/details/{code})
 *
 * Three primitives:
 *   1. .ng-profile-banner — the hero that names the record and,
 *      crucially, makes the record TYPE unmistakable. Brand GREEN =
 *      Beneficiary (approved / enrolled — a positive, "you're in"
 *      state), amber/ochre = Applicant (still under review), navy =
 *      Beneficiary update (an administrative record change). Same
 *      shape, semantic colour story. It stacks flush onto the card
 *      directly below it, reading as one unit (header + body).
 *   2. .ng-status-pill — a reusable status chip (tone = success /
 *      warning / danger / info / neutral). An --on-banner variant
 *      sits on the coloured banner.
 *   3. .ng-detail-grid — the responsive label/value description
 *      grid that replaces the legacy 4-column <table.table-wh>.
 *
 * All white-on-colour text in the banner clears WCAG 2.2 AA:
 *   - sage-700 (lightest beneficiary stop) → white ~6.7:1
 *   - amber-700 (lightest applicant stop)  → white ~5.6:1
 * ============================================================ */

/* ---------- PROFILE BANNER ---------- */
.ng-profile-banner {
  position: relative;
  overflow: hidden;                       /* clip the decorative motif watermark */
  display: flex;
  align-items: center;
  gap: var(--space-5);
  padding: var(--space-6) var(--space-7);
  margin-bottom: var(--content-padding);  /* same rhythm as the cards below it */
  border-radius: var(--banner-radius);
  color: var(--color-text-inverse);
  background: var(--banner-bg);           /* set per-variant below */
}

/* Integrate the banner with the card directly beneath it: drop the gap and
   square the shared edge so they read as one rounded unit (banner = header,
   card = body). :has() so a standalone banner keeps its full rounding. */
.ng-profile-banner:has(+ .portlet) {
  margin-bottom: 0;
  border-bottom-left-radius: 0;
  border-bottom-right-radius: 0;
}
.ng-profile-banner + .portlet {
  margin-top: 0;
  /* defeat _cards.css `.portlet.light { border-radius: var(--card-radius) !important }`
     so the card's TOP corners square off and it reads as the banner's body. */
  border-top-left-radius: 0 !important;
  border-top-right-radius: 0 !important;
}

/* Page toolbar — back link left, optional Actions menu right (same row as the
   applicant profile's Edit / Validate overflow). Spacing lives on the toolbar
   so the row clears the banner below. */
.ng-page-toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  margin-bottom: var(--space-4);
}
.ng-page-toolbar > .ng-back-link {
  margin-bottom: 0;
}
.ng-page-toolbar__actions {
  flex-shrink: 0;
}

/* Back link — uses the DS secondary outline button (.btn.btn-default); this just
   handles placement above the banner + icon sizing. Standalone (no toolbar)
   keeps its own bottom margin for pages that haven't adopted the toolbar yet. */
.ng-back-link {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  margin-bottom: var(--space-4);
}
.ng-back-link > i { font-size: var(--font-size-md); line-height: 1; }

/* Variant fills — diagonal gradient, both stops kept dark enough for AA white text */
.ng-profile-banner--beneficiary {
  --banner-bg: linear-gradient(135deg, var(--color-sage-700) 0%, var(--color-sage-900) 100%);
  --ng-banner-motif: url(/img/icons/phosphor/check-circle.svg);   /* positive "enrolled" motif */
}
.ng-profile-banner--applicant {
  --banner-bg: linear-gradient(135deg, var(--color-amber-700) 0%, var(--color-amber-900) 100%);
  --ng-banner-motif: url(/img/icons/phosphor/file-text.svg);
}
.ng-profile-banner--update {
  --banner-bg: linear-gradient(135deg, var(--color-navy-700) 0%, var(--color-navy-900) 100%);
  --ng-banner-motif: url(/img/icons/phosphor/note-pencil.svg);   /* "record changed" motif */
}

/* Oversized translucent motif watermark, bleeding off the right edge —
   visual interest without competing with the content. */
.ng-profile-banner::after {
  content: "";
  position: absolute;
  top: 50%;
  right: -28px;
  width: 196px;
  height: 196px;
  transform: translateY(-50%) rotate(-8deg);
  opacity: 0.13;                          /* more apparent positive motif */
  background-color: #fff;
  -webkit-mask: var(--ng-banner-motif) center / contain no-repeat;
          mask: var(--ng-banner-motif) center / contain no-repeat;
  pointer-events: none;
}

/* Monogram figure — initials on a translucent disc. When an ID photo is passed
   it overlays the disc; the initials stay underneath as the fallback, so an
   image that 404s (hidden by its onerror handler) reveals them again. */
.ng-profile-banner__figure {
  position: relative;
  overflow: hidden;
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 64px;
  height: 64px;
  border-radius: var(--radius-full);
  background: rgba(255, 255, 255, 0.14);
  border: 1px solid rgba(255, 255, 255, 0.30);
  font-family: var(--font-family-display);
  font-weight: var(--font-weight-bold);
  font-size: var(--font-size-2xl);
  line-height: 1;
  letter-spacing: 0.01em;
  color: var(--color-text-inverse);
}
.ng-profile-banner__figure-link {
  position: absolute;
  inset: 0;
  display: block;
}
.ng-profile-banner__figure-img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.ng-profile-banner__body {
  position: relative;   /* sit above the ::after watermark */
  z-index: 1;
  min-width: 0;         /* allow the meta row to wrap/ellipsis inside flex */
  flex: 1 1 auto;
}

/* Top line — eyebrow + status pill, sitting together on the left. */
.ng-profile-banner__topline {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2) var(--space-3);
  margin-bottom: var(--space-2);
}

/* Eyebrow — the record-type label + a small leading motif icon */
.ng-profile-banner__eyebrow {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  margin-bottom: 0;
  font-family: var(--font-family-ui);
  font-size: var(--font-size-xs);
  font-weight: var(--font-weight-bold);
  text-transform: uppercase;
  letter-spacing: var(--letter-spacing-uppercase);
  color: var(--color-text-inverse-muted);
}
.ng-profile-banner__eyebrow > i { font-size: var(--font-size-md); }

.ng-profile-banner__name {
  margin: 0;
  font-family: var(--font-family-display);
  font-weight: var(--font-weight-bold);
  font-size: var(--font-size-3xl);
  line-height: var(--line-height-tight);
  color: var(--color-text-inverse);
}

/* Meta — Reg No · location · ID, separated by mid-dots */
.ng-profile-banner__meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-1) var(--space-3);
  margin-top: var(--space-2);
  font-size: var(--font-size-sm);
  color: var(--color-text-inverse-muted);
}
.ng-profile-banner__meta-item { display: inline-flex; align-items: baseline; gap: 6px; }
.ng-profile-banner__meta-item + .ng-profile-banner__meta-item::before {
  content: "·";
  margin-right: var(--space-3);
  color: rgba(255, 255, 255, 0.45);
}
/* IDs / reg numbers in the data font for legibility */
.ng-profile-banner__meta-value {
  font-family: var(--font-family-data);
  color: var(--color-text-inverse);
}

/* Right-hand rail — status pill stacked over optional actions */
.ng-profile-banner__aside {
  position: relative;
  z-index: 1;
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: var(--space-3);
  margin-left: auto;
  text-align: right;
}
.ng-profile-banner__actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: var(--space-2);
}
/* Ghost-on-dark action buttons — the quiet .btn-default outline vanishes on the
   coloured fill, so re-skin any action button to read against navy / amber.
   !important defeats _buttons.css's `.btn.btn-default { color/background/border
   !important }` (which itself defeats Metronic's `!important` button colours). */
.ng-profile-banner__actions .btn,
.ng-profile-banner__actions .btn.btn-default {
  background: rgba(255, 255, 255, 0.12) !important;
  border: 1px solid rgba(255, 255, 255, 0.45) !important;
  color: var(--color-text-inverse) !important;
}
.ng-profile-banner__actions .btn:hover,
.ng-profile-banner__actions .btn:focus,
.ng-profile-banner__actions .btn.btn-default:hover,
.ng-profile-banner__actions .btn.btn-default:focus {
  background: rgba(255, 255, 255, 0.22) !important;
  border-color: rgba(255, 255, 255, 0.78) !important;
  color: var(--color-text-inverse) !important;
}

/* ---------- MINI BANNER ----------
   The same hero, scaled to sit inside a column rather than across the page —
   used where a record is rendered as a *mini profile*: the duplicate-review
   compare panels (/admin/duplicates/{id}), where two records sit side by side
   and each is a small version of its own profile screen. Colour story, motif
   and parts are identical; only the scale changes, so the record type reads
   the same in both places. */
.ng-profile-banner--mini {
  gap: var(--space-4);
  padding: var(--space-4) var(--space-5);
  border-radius: var(--card-radius);   /* matches the card it sits on, not the page hero */
}
.ng-profile-banner--mini::after {
  right: -22px;
  width: 132px;
  height: 132px;
}
.ng-profile-banner--mini .ng-profile-banner__figure {
  width: 48px;
  height: 48px;
  font-size: var(--font-size-lg);
}
.ng-profile-banner--mini .ng-profile-banner__name {
  font-size: var(--font-size-xl);
}
.ng-profile-banner--mini .ng-profile-banner__meta {
  margin-top: var(--space-1);
  font-size: var(--font-size-xs);
}
/* The pill is the record's status; at mini scale the page-hero size crowds the
   eyebrow beside it, so step it back down to the base chip metrics. */
.ng-profile-banner--mini .ng-status-pill--on-banner {
  font-size: var(--font-size-xs);
  padding: 4px var(--space-3);
}

/* ---------- STATUS PILL (reusable) ----------
   Tonal chip: a soft <tone>-50 fill with <tone>-700 text + a solid dot.
   Mirrors the showcase .ds-badge convention so list/table/detail status
   reads consistently. */
.ng-status-pill {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: 5px var(--space-3);
  border-radius: var(--radius-full);
  font-family: var(--font-family-ui);
  font-size: var(--font-size-xs);
  font-weight: var(--font-weight-semibold);
  line-height: 1.4;
  white-space: nowrap;
  background: var(--color-bg-sunken);
  color: var(--color-text-muted);
}
.ng-status-pill::before {
  content: "";
  width: 8px;
  height: 8px;
  border-radius: var(--radius-full);
  background: currentColor;
  flex: 0 0 auto;
}
/* Tones ride the semantic --color-feedback-* pair, not the raw <tone>-50/-700
   scale: only the semantic tokens flip in dark mode, so the scale values left
   the pill glaring as a light patch on the dark page. Same values in light. */
.ng-status-pill--success { background: var(--color-feedback-success-bg); color: var(--color-feedback-success); }
.ng-status-pill--warning { background: var(--color-feedback-warning-bg); color: var(--color-feedback-warning); }
.ng-status-pill--danger  { background: var(--color-feedback-danger-bg);  color: var(--color-feedback-danger); }
.ng-status-pill--info    { background: var(--color-feedback-info-bg);    color: var(--color-feedback-info); }
.ng-status-pill--neutral { background: var(--color-bg-sunken);           color: var(--color-text-muted); }

/* Tag variant — same tonal chip, no leading dot.
   The ::before dot reads as "this is a live state you might see change".
   Where the chip is a *classification* that cannot change under the
   operator — a role name, an audit event verb, a duplicate match signal,
   a "System"/"Custom" kind — the dot signifies nothing and just adds
   noise to a column of them. Tone + label carry the meaning on their own.
   Use --tag there; keep the dot for anything that is genuinely a status. */
.ng-status-pill--tag::before {
  content: none;
}

/* Compact scale — for a chip that sits inline inside a form label or a
   checkbox row, where the base chip's padding breaks the text baseline.
   Padding only: the font size stays at --font-size-xs, the smallest step
   on the type scale. (This replaces hand-rolled inline `font-size: 9px`
   badges, which were unreadable and off-scale in both themes.) */
.ng-status-pill--xs {
  gap: var(--space-1);
  padding: 1px var(--space-2);
}
.ng-status-pill--xs::before {
  width: 6px;
  height: 6px;
}

/* Inside a portlet caption (section-check badges, #769): sit beside the
   uppercase bold title on its baseline. Failure reasons render as
   `.ng-section-check-note` in the portlet body — not a tooltip. */
.ng-status-pill--caption {
  margin-left: var(--space-2);
  vertical-align: middle;
}

/* The caption badge swaps the base pill's status dot for the SAME phosphor
   glyph set `.ng-criteria__mark` masks on the registry lists — check-circle /
   warning / minus. One assessment then reads with one vocabulary wherever it
   appears: a tick in the Checks column, a tick in the section header.

   The dot is right for a pill whose tone is one of many live states; here the
   tone is a three-way verdict, and a shape says which one at a glance without
   reading the label. That is belt-and-braces for WCAG 1.4.1 — the text label
   already carries the state — but it is what makes a passing section scannable
   as a green tick down a long profile.

   `--unknown` is the fallback glyph, so a tone this modifier does not name
   (a caller reaching for `--info`/`--danger`) degrades to the neutral minus
   rather than to an empty box. */
.ng-status-pill--caption::before {
  --ng-criteria-glyph: url(/img/icons/phosphor/minus.svg);
  width: 13px;
  height: 13px;
  border-radius: 0;
  background-color: currentColor;
  -webkit-mask: var(--ng-criteria-glyph) center / contain no-repeat;
          mask: var(--ng-criteria-glyph) center / contain no-repeat;
}
.ng-status-pill--caption.ng-status-pill--success::before {
  --ng-criteria-glyph: url(/img/icons/phosphor/check-circle.svg);
}
.ng-status-pill--caption.ng-status-pill--warning::before {
  --ng-criteria-glyph: url(/img/icons/phosphor/warning.svg);
}

/* The badge is `tabindex="0"` (it carries the tooltip), so it needs a visible
   focus stop of its own — the base pill is not focusable and has none. */
.ng-status-pill--caption:focus-visible {
  outline: var(--focus-ring-width) solid var(--focus-ring-color);
  outline-offset: 2px;
}

/* Section-check failure note (#769): sits at the top of `.portlet-body`,
   between the caption badge and the section data. Reuses Feedback alert
   colours; flex so the warning icon + reason share a line. */
.ng-section-check-note {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  margin: 0 0 var(--space-4);
  padding: var(--space-3) var(--space-4);
}
.ng-section-check-note > .fa {
  margin-top: 2px;
  flex-shrink: 0;
}
.ng-section-check-note__body {
  flex: 1;
  min-width: 0;
  white-space: pre-line; /* bank notes stack status + returned name/phone */
}
.ng-section-check-note__link {
  flex-shrink: 0;
  white-space: nowrap;
}

/* On the coloured banner: a crisp white pill so the tone reads against
   navy / amber. The tone now lives in the text + dot only.

   These two values are deliberately the RAW neutral scale, not the semantic
   --color-bg-surface / --color-text-default: this pill sits on the banner's
   gradient, and that gradient is a FIXED dark fill (sage/amber/navy 700→900)
   in both themes. The semantic tokens flip, so in dark mode they turned the
   pill into dark-on-dark (#211f1c fill under #1f5c33 text — about 1.4:1, far
   under AA) while the fill behind it stayed dark green. The scale tokens don't
   flip, which is exactly right here: the backdrop doesn't either. The tone
   colours below are already scale values for the same reason. */
.ng-status-pill--on-banner {
  background: var(--color-neutral-0);
  box-shadow: var(--shadow-sm);
  font-size: var(--font-size-sm);
  padding: 6px var(--space-4);
}
.ng-status-pill--on-banner.ng-status-pill--success { color: var(--color-success-700); }
.ng-status-pill--on-banner.ng-status-pill--warning { color: var(--color-warning-700); }
.ng-status-pill--on-banner.ng-status-pill--danger  { color: var(--color-danger-700); }
.ng-status-pill--on-banner.ng-status-pill--info     { color: var(--color-info-700); }
.ng-status-pill--on-banner.ng-status-pill--neutral { color: var(--color-neutral-900); }

/* Submitted application: key the lozenge text + icon to the amber applicant
   banner (the default info/blue clashes). The paper-plane icon follows via
   currentColor. */
.ng-profile-banner--applicant .ng-status-pill--on-banner.ng-status-pill--info {
  color: var(--color-warning-700);
}

/* On the banner, the approved/success pill leads with a CHECK rather than the
   generic dot — the dot signified nothing; the check reads as "approved". */
.ng-profile-banner .ng-status-pill--success::before {
  width: 13px;
  height: 13px;
  border-radius: 0;
  background: currentColor;
  -webkit-mask: url(/img/icons/phosphor/check.svg) center / contain no-repeat;
          mask: url(/img/icons/phosphor/check.svg) center / contain no-repeat;
}
/* Submitted / in-review (applicant) → a paper-plane "submitted" icon. */
.ng-profile-banner .ng-status-pill--info::before {
  width: 13px;
  height: 13px;
  border-radius: 0;
  background: currentColor;
  -webkit-mask: url(/img/icons/phosphor/paper-plane-tilt.svg) center / contain no-repeat;
          mask: url(/img/icons/phosphor/paper-plane-tilt.svg) center / contain no-repeat;
}

/* ---------- DETAIL GRID (label / value description grid) ----------
   The canonical way to render a record's fields inside a .portlet —
   replaces the legacy 4-column <table.table-wh>. Auto-fills 2–3 columns
   on desktop, collapses to one on mobile. Each track's minimum is the
   larger of 260px and a third of the row (minus the two column gaps), so
   wide viewports never fit a 4th column. */
.ng-detail-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(max(260px, calc((100% - 2 * var(--space-6)) / 3)), 1fr));
  gap: var(--space-2) var(--space-6);
}
.ng-detail-grid__item {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: var(--space-2) 0;
  border-bottom: 1px solid var(--color-border-subtle);
  min-width: 0;
}
/* A field that should span the full grid width (e.g. an address). */
.ng-detail-grid__item--full { grid-column: 1 / -1; }

.ng-detail-grid__label {
  font-family: var(--font-family-ui);
  font-size: var(--font-size-xs);
  font-weight: var(--font-weight-medium);
  text-transform: uppercase;
  letter-spacing: var(--letter-spacing-wide);
  color: var(--color-text-muted);
}
.ng-detail-grid__value {
  font-family: var(--font-family-ui);
  font-size: var(--font-size-md);
  font-weight: var(--font-weight-medium);
  color: var(--color-text-default);
  line-height: var(--line-height-snug);
  overflow-wrap: anywhere;          /* long IDs / emails never blow out the column */
  min-height: 21px;                 /* keep empty values from collapsing the row */
}
/* IDs, reg numbers, phone, money → data font (Atkinson) for legibility */
.ng-detail-grid__value--data {
  font-family: var(--font-family-data);
}
.ng-detail-grid__value--muted { color: var(--color-text-faint); }
/* An update field whose new value differs from the previous record. The whole
   cell is tinted with a left accent so changed fields read at a glance — not
   only by the red value text. */
.ng-detail-grid__item--changed {
  padding-left: var(--space-3);
  padding-right: var(--space-3);
  border-bottom-color: transparent;
  border-left: 3px solid var(--color-feedback-danger);
  border-radius: 0 var(--radius-md) var(--radius-md) 0;
  background: var(--color-feedback-danger-bg);
}
.ng-detail-grid__value--changed {
  color: var(--color-feedback-danger);
  font-weight: var(--font-weight-semibold);
}
/* Intent-coloured variants of the changed-cell treatment, for cells that
   surface a live operation result (e.g. the payment section's bank
   verification row). Same geometry as --changed, hue from the feedback
   intent. */
.ng-detail-grid__item--flag-success,
.ng-detail-grid__item--flag-warning,
.ng-detail-grid__item--flag-danger {
  padding-left: var(--space-3);
  padding-right: var(--space-3);
  border-bottom-color: transparent;
  border-left: 3px solid var(--flag-color);
  border-radius: 0 var(--radius-md) var(--radius-md) 0;
  background: var(--flag-bg);
}
.ng-detail-grid__item--flag-success { --flag-color: var(--color-feedback-success); --flag-bg: var(--color-feedback-success-bg); }
.ng-detail-grid__item--flag-warning { --flag-color: var(--color-feedback-warning); --flag-bg: var(--color-feedback-warning-bg); }
.ng-detail-grid__item--flag-danger  { --flag-color: var(--color-feedback-danger);  --flag-bg: var(--color-feedback-danger-bg); }
/* "Updated" pill rendered inline after a changed value. */
.ng-detail-grid__tag {
  display: inline-block;
  margin-left: var(--space-2);
  padding: 1px 7px;
  border-radius: var(--radius-full);
  background: var(--color-feedback-danger);
  color: var(--color-text-inverse);
  font-family: var(--font-family-ui);
  font-size: var(--font-size-xs);
  font-weight: var(--font-weight-semibold);
  text-transform: uppercase;
  letter-spacing: var(--letter-spacing-wide);
  line-height: 1.5;
  vertical-align: middle;
}
/* Intent-coloured tag pills for the flag cells above. Tag text uses
   --color-bg-surface, not --color-text-inverse: the dark theme brightens the
   feedback colours, so the readable text on the pill is the theme's surface
   colour in both modes (white-on-dark pill in light, dark-on-light in dark). */
.ng-detail-grid__tag--success { background: var(--color-feedback-success); color: var(--color-bg-surface); }
.ng-detail-grid__tag--warning { background: var(--color-feedback-warning); color: var(--color-bg-surface); }
.ng-detail-grid__tag--danger  { background: var(--color-feedback-danger);  color: var(--color-bg-surface); }
/* Quiet result for a corroborating check. Matches stay mark-only; mismatches
   that need attention still pair a danger mark with `__item--flag-danger`. */
.ng-detail-grid__verification-mark {
  display: inline-block;
  margin-left: var(--space-2);
  font-size: var(--font-size-md);
  line-height: 1;
  vertical-align: -0.1em;
}
.ng-detail-grid__verification-mark--success { color: var(--color-feedback-success); }
.ng-detail-grid__verification-mark--danger  { color: var(--color-feedback-danger); }
.ng-detail-grid__was {
  font-family: var(--font-family-ui);
  font-size: var(--font-size-xs);
  color: var(--color-text-muted);
}
/* A previous value that was blank — italic placeholder, not a bare dash. */
.ng-detail-grid__empty {
  font-style: italic;
  color: var(--color-text-faint);
}

/* Empty state for a section with no records */
.ng-detail-empty {
  margin: 0;
  padding: var(--space-2) 0;
  color: var(--color-text-faint);
  font-size: var(--font-size-md);
}

/* ---------- APPEARANCE TAB (/profile) ----------
   Hosts the dark-mode .ng-switch. Stack the hint above the switch with
   the standard rhythm; cap the hint measure so it reads as guidance. */
.ng-appearance {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-4);
}
.ng-appearance > p {
  margin: 0;
  max-width: 60ch;
  color: var(--color-text-muted);
}

/* ---------- RESPONSIVE ---------- */
@media (max-width: 575px) {
  .ng-profile-banner {
    flex-wrap: wrap;
    padding: var(--space-5);
    gap: var(--space-4);
  }
  .ng-profile-banner__aside {
    align-items: flex-start;
    text-align: left;
    width: 100%;
    margin-left: 0;
  }
  .ng-profile-banner__name { font-size: var(--font-size-2xl); }
}
