/* ==========================================================================
   St. Aldric — design system
   Generic placeholder branding only: no third-party bank names, logos or
   product marks anywhere in this file or the markup it styles.
   ========================================================================== */

/* The body already asked for Inter but nothing ever loaded it, so every machine
   without it fell back to Segoe UI. This fetches it. */
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap');
/* The display serif for the signed-out pages and the wordmark. Playfair is a
   free stand-in for the high-contrast serif the landing page uses; swapping it
   is one line here and nowhere else, because everything references the
   --font-display token rather than naming a family. */
@import url('https://fonts.googleapis.com/css2?family=Playfair+Display:wght@400;500;600&display=swap');

/* --------------------------------------------------------------------------
   Palette: deep navy on warm cream, silver for line work. No pure white
   anywhere — #FBFBF9 is as light as this interface goes. Every text pair below
   was checked against WCAG 2.1 rather than picked by eye; the ratios are in the
   comments and the check lives in the scratchpad script that generated them.
   -------------------------------------------------------------------------- */
:root {
  /* Structure. The "blue" names are kept because the whole stylesheet and the
     back office reference them; only the values moved to navy. */
  /* One palette across the whole product: the signed-out pages and the app
     behind them now share the landing's navy. The mark itself stays teal —
     it is the artwork, and it sits on white or cream everywhere it appears,
     exactly as it does on the landing's own bar. */
  --brand-blue-primary: #14415F;   /* actions: buttons, active nav */
  --brand-blue-hover: #1B5480;
  --brand-navy-hero: #0D1A2D;      /* hero bands, footers, the dark chrome */
  --brand-navy-dark: #091220;

  /* Gold, taken from the mark. Decorative only, and that is a measurement
     rather than a preference: on the cream page it is 2.0:1, nowhere near
     readable, and on the teal band 3.7:1 — enough for a rule or a large
     flourish, not for body text. It is never used to carry words. */
  --brand-gold: #C5A975;
  --brand-gold-soft: rgba(197, 169, 117, 0.35);

  /* Surfaces: cream page, lighter band sitting on top of it, tint for recessed
     areas. Sections read as bands against the page rather than as cards. */
  --bg-app: #F4F3F0;
  --bg-card: #FBFBF9;
  --bg-muted: #EBE9E4;

  /* Text — the brand's own deep navy, which happens to be an excellent text
     colour: 15.8:1 on the cream page. */
  --text-primary: #0D1A2D;
  --text-secondary: #55606E;
  --text-muted: #5C6672;
  --text-on-dark: #F4F3F0;

  /* Indicators, darkened until each one is legible as text on cream */
  --accent-green: #1B6B4A;
  --accent-red: #A32B22;
  --accent-amber: #8A5A10;

  /* Lines. --silver is decorative only (2.40:1) and must never carry text or
     bound a control; --silver-strong (3.48:1) is what borders inputs and
     buttons, where WCAG 1.4.11 wants 3:1. */
  --silver: #96A0A8;
  --silver-strong: #79838D;
  --border-soft: #DAD7D0;
  --border-strong: #C3BFB6;

  /* Elevation: none. Cards floating on soft shadows were the main reason this
     read as generated. Depth now comes from the band/page tint difference.
     --shadow-float survives for things that genuinely float over content. */
  --shadow-card: none;
  --shadow-float: 0 6px 20px rgba(18, 35, 58, 0.12);

  /* Shape: institutional means near-square. */
  --radius-sm: 3px;
  --radius-md: 4px;
  --radius-lg: 6px;
  --radius-pill: 999px;

  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --sidebar-w: 232px;
  /* Width of the customer-area content column, gutters included. 1280 sits in
     the 1200-1440 band the retail banking layouts settle on, and leaves the
     dashboard's reading column near the top of the comfortable range once the
     side rail is taken off it. */
  --shell-max: 1280px;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  font-family: 'Inter', 'Segoe UI', 'Open Sans', system-ui, -apple-system, sans-serif;
  font-size: 14px;
  line-height: 1.5;
  color: var(--text-primary);
  background: var(--bg-app);
  -webkit-font-smoothing: antialiased;
}

a { color: var(--brand-blue-hover); text-decoration: none; }
a:hover { text-decoration: underline; }

/* Restrained institutional: headings are smaller and tighter than the previous
   set, and carry their weight through tracking rather than size. The gap
   between a heading and body text is weight and colour, not scale. */
h1, h2, h3, h4 {
  margin: 0 0 12px 0;
  line-height: 1.3;
  color: var(--text-primary);
  letter-spacing: -0.015em;
}
h1 { font-size: 23px; font-weight: 700; line-height: 1.2; letter-spacing: -0.022em; }
h2 { font-size: 18px; font-weight: 700; letter-spacing: -0.018em; }
h3 { font-size: 14px; font-weight: 600; letter-spacing: -0.01em; }

/* Money lines up in a column. Proportional digits are different widths, so a
   stack of balances never aligns; tabular ones do. */
.num, .acct-hero-bal, .acct-bal, .tile-value, .bal, td.num, th.num {
  font-variant-numeric: tabular-nums;
  font-feature-settings: 'tnum' 1;
}

p { margin: 0 0 12px 0; }
small, .muted { font-size: 12px; color: var(--text-secondary); }
.muted { display: block; max-width: 78ch; }

/* The browser hides [hidden] with a rule on the element type, which any class
   that sets display outranks - so a flex container carrying the attribute
   stayed on screen. That is how the QR scanner appeared over the first step of
   the transfer flow before anyone had asked for it. The attribute has to win,
   because every page here uses it as the on/off switch for a panel. */
[hidden] { display: none !important; }

/* Shell pages ship their content as bare markup and JS moves it into #main.
   Painting that half-built state first showed a flash of stray headings and
   empty tables, so it stays hidden until the shell says it is assembled.
   Standalone pages carry a body class and are never hidden. */
body:not([class]):not(.shell-ready) { visibility: hidden; }

/* ---------------------------------------------------------------- shell -- */

#sidebar {
  position: fixed;
  left: 0; top: 0; bottom: 0;
  width: var(--sidebar-w);
  padding: 20px 14px;
  background: var(--bg-card);
  border-right: 1px solid var(--border-soft);
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.brand { display: flex; align-items: center; gap: 10px; margin-bottom: 18px; }
.brand-mark {
  width: 32px; height: 32px;
  border-radius: var(--radius-sm);
  background: linear-gradient(135deg, var(--brand-navy-hero) 0%, var(--brand-blue-primary) 100%);
  display: grid; place-items: center;
  color: #fff; font-weight: 700; font-size: 13px; letter-spacing: .5px;
  flex: none;
}
.brand-name { font-size: 14px; font-weight: 700; color: var(--text-primary); line-height: 1.2; }
.brand-sub { font-size: 11px; color: var(--text-muted); }

#sidebar nav { display: flex; flex-direction: column; gap: 2px; }
#sidebar nav a {
  display: block;
  padding: 9px 12px;
  border-radius: var(--radius-sm);
  color: var(--text-secondary);
  font-weight: 500;
  font-size: 13.5px;
  text-decoration: none;
  transition: background 150ms ease, color 150ms ease;
}
#sidebar nav a:hover { background: var(--bg-muted); color: var(--text-primary); text-decoration: none; }
#sidebar nav a.active {
  background: var(--brand-blue-primary);
  color: var(--text-on-dark);
  font-weight: 600;
}

#sidebar .who {
  margin-top: auto;
  padding-top: 14px;
  border-top: 1px solid var(--border-soft);
  font-size: 12px;
  color: var(--text-secondary);
  display: flex;
  flex-direction: column;
  gap: 6px;
}
#sidebar .who select { width: 100%; }

#main {
  margin-left: var(--sidebar-w);
  padding: 28px 32px 56px;
  max-width: none;
}

/* The customer area is held to a centred column. It used to run edge to edge on
   the reasoning that a cap "left a third of a wide monitor empty", but measured
   on a 1920 screen that gave a 1609px content column — 213 characters to a line
   against the 50-75 Baymard measured as comfortable and the 80 WCAG 1.4.8 allows
   at most. Baymard's testing found copy past 80 characters a line was skipped 41%
   more often, and testers called it "intimidating and overwhelming", which is the
   complaint here. The empty sides are not waste: they bound the page so the eye
   knows where a column starts and stops.

   Done with padding rather than max-width plus auto margins, because #main is
   already offset by the sidebar and auto margins cannot centre against that. The
   `max()` keeps the ordinary 32px gutter until the screen is wide enough to have
   room to give away, so nothing changes below ~1550px.

   The back office is deliberately excluded — dense staff tables want the width. */
.client-area #main {
  /* The sidebar has to come out by hand. A percentage inside padding resolves
     against the containing block — the body, the full window — not against
     #main, so `(100% - --shell-max) / 2` counted the sidebar's 232px twice and
     squeezed the column to 1048px. */
  padding-inline: max(32px, (100% - var(--sidebar-w) - var(--shell-max)) / 2);
}

/* --------------------------------------------------------------- panels -- */

/* Bands, not cards. Each of these is a lighter block sitting on the cream page;
   the tint difference between --bg-card and --bg-app is what separates them, so
   they need no shadow and only a hairline to crisp the edge. */
.panel, .tile, .notif, .ins, .offer, .article, .faq, .invacct {
  background: var(--bg-card);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-md);
  box-shadow: none;
  padding: 16px;
}
.panel { margin-bottom: 16px; }

.tiles {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 12px;
  margin-bottom: 20px;
}
.tile {
  transition: transform 150ms ease, box-shadow 150ms ease;
}
.tile b { display: block; font-size: 22px; font-weight: 700; margin-top: 2px; color: var(--text-primary); }
.tile > div:first-child { font-size: 12px; color: var(--text-secondary); font-weight: 500; }
.tile .muted { font-size: 11px; }

/* The two .col wrappers dissolve so their panels become grid items directly:
   on a wide screen that means four columns of panels rather than two very
   wide ones, and it still collapses to a single column on a phone. */
.cols {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(340px, 1fr));
  gap: 16px;
  align-items: start;
}
.col { display: contents; }
.cols > .panel, .cols .col > .panel, .cols .col > table { margin-bottom: 0; }
.wide { overflow-x: auto; }

/* --------------------------------------------------------------- tables -- */

/* Every table in the shell is wrapped in one of these by renderShell, so a
   table wider than a phone scrolls on its own instead of dragging the whole
   page sideways and clipping the navigation. */
.table-wrap {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  margin-bottom: 16px;
}
.table-wrap > table { margin-bottom: 0; }
.panel > .table-wrap:last-child { margin-bottom: 0; }


table {
  border-collapse: separate;
  border-spacing: 0;
  width: 100%;
  background: var(--bg-card);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-md);
  overflow: hidden;
  box-shadow: var(--shadow-card);
  margin-bottom: 16px;
  font-size: 13px;
}
th, td {
  border: none;
  border-bottom: 1px solid var(--border-soft);
  padding: 10px 12px;
  text-align: left;
  vertical-align: middle;
}
th {
  background: var(--bg-muted);
  font-weight: 600;
  font-size: 12px;
  color: var(--text-secondary);
  white-space: nowrap;
}
tbody tr:last-child td { border-bottom: none; }
tbody tr { transition: background 120ms ease; }
tbody tr:hover { background: var(--bg-muted); }
/* tables nested inside a panel shouldn't double up the chrome */
.panel table { box-shadow: none; border: 1px solid var(--border-soft); margin-bottom: 0; }

/* -------------------------------------------------------------- controls -- */

button, .btn {
  font-family: inherit;
  font-size: 13px;
  font-weight: 600;
  padding: 8px 14px;
  min-height: 36px;
  margin: 0 6px 4px 0;
  color: var(--brand-blue-hover);
  background: var(--bg-card);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  cursor: pointer;
  transition: transform 150ms ease, box-shadow 150ms ease, background 150ms ease, border-color 150ms ease;
}
/* No lift. A control that jumps 2px toward the cursor is the house style of
   generated templates; here hover is a darker edge and a tint, nothing more. */
button:hover, .btn:hover {
  border-color: var(--brand-blue-primary);
  background: var(--bg-muted);
}
button:active, .btn:active { transform: scale(0.98); box-shadow: none; }
button:focus-visible, .btn:focus-visible,
input:focus-visible, select:focus-visible, textarea:focus-visible {
  outline: 2px solid var(--brand-blue-primary);
  outline-offset: 2px;
}

button[type="submit"], .btn-primary {
  background: var(--brand-blue-primary);
  border-color: var(--brand-blue-primary);
  color: var(--text-on-dark);
  min-height: 44px;
  padding: 12px 24px;
}
button[type="submit"]:hover, .btn-primary:hover {
  background: var(--brand-blue-hover);
  border-color: var(--brand-blue-hover);
  box-shadow: var(--shadow-float);
}
button[type="submit"]:active, .btn-primary:active {
  background: var(--brand-blue-hover);
  transform: scale(0.98);
}

button:disabled, .btn:disabled, button[disabled] {
  background: #E2E8F0;
  border-color: var(--border-strong);
  color: var(--text-muted);
  cursor: not-allowed;
  transform: none;
  box-shadow: none;
}

input, select, textarea {
  /* several fields carry an HTML size/cols attribute, which on a phone makes
     them wider than the screen and drags the whole page sideways */
  max-width: 100%;
  font-family: inherit;
  font-size: 13px;
  color: var(--text-primary);
  background: var(--bg-card);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  padding: 9px 11px;
  min-height: 36px;
  margin: 0 6px 4px 0;
  transition: border-color 150ms ease, box-shadow 150ms ease;
}
input:focus, select:focus, textarea:focus {
  border-color: var(--brand-blue-primary);
  box-shadow: 0 0 0 3px rgba(18, 35, 58, 0.14);
  outline: none;
}
input::placeholder { color: var(--text-muted); }
textarea { min-height: 84px; line-height: 1.5; }
label { font-size: 13px; font-weight: 500; color: var(--text-secondary); margin-right: 10px; }
/* A checkbox is not a text field. Without this it picks up width:100%,
   min-height and padding from the rules above and renders as a huge box. */
input[type="checkbox"], input[type="radio"] {
  flex: none;
  width: 16px;
  height: 16px;
  min-height: 0;
  padding: 0;
  margin: 0 6px 0 0;
  accent-color: var(--brand-blue-primary);
}
input[type="file"] { padding: 7px; background: var(--bg-muted); }

/* ------------------------------------------------------------ quick nav -- */

.actions { display: flex; flex-wrap: wrap; gap: 10px; margin-bottom: 20px; }
.actions a {
  display: inline-block;
  padding: 10px 18px;
  border-radius: var(--radius-pill);
  background: var(--bg-card);
  border: 1px solid var(--border-strong);
  color: var(--brand-blue-hover);
  font-weight: 600;
  font-size: 13px;
  text-decoration: none;
  transition: transform 150ms ease, box-shadow 150ms ease, border-color 150ms ease;
}
.actions a:hover {
  text-decoration: none;
  border-color: var(--brand-blue-primary);
  background: var(--bg-muted);
}

/* horizontal snap carousel for narrow screens */
.scroll-carousel { display: flex; overflow-x: auto; scroll-snap-type: x mandatory; -webkit-overflow-scrolling: touch; }
.scroll-carousel > * { scroll-snap-align: center; }

/* ---------------------------------------------------------- list states -- */

.notif, .ins, .offer, .article, .faq { margin-bottom: 12px; }
.notif.unread { border-left: 4px solid var(--brand-blue-primary); }
.notif .when { font-size: 11px; color: var(--text-muted); margin-top: 4px; }

.ins.warning { border-left: 4px solid var(--accent-red); }
.ins.suggestion { border-left: 4px solid var(--brand-blue-primary); }
.ins.info { border-left: 4px solid var(--border-strong); }
.ins .tag {
  display: inline-block;
  margin-top: 8px;
  padding: 2px 10px;
  border-radius: var(--radius-pill);
  background: var(--bg-muted);
  border: 1px solid var(--border-soft);
  font-size: 11px;
  font-weight: 600;
  color: var(--text-secondary);
  text-transform: uppercase;
  letter-spacing: .4px;
}
.ins.warning .tag { background: #FEF2F2; border-color: #FECACA; color: #B91C1C; }
.ins.suggestion .tag { background: #EFF6FF; border-color: #BFDBFE; color: var(--brand-blue-hover); }

.offer img { max-width: 100%; height: auto; display: block; margin-bottom: 12px; border-radius: var(--radius-sm); }
.faq h3 { margin-bottom: 6px; }
.cat { margin-top: 20px; font-size: 13px; text-transform: uppercase; letter-spacing: .5px; color: var(--text-muted); }

/* ------------------------------------------------------------ dashboard -- */

/* Main column plus a fixed rail, the shape most retail banking overviews
   settle on: balances and activity get the width, everything advisory sits
   to the side. Below 1100px the rail drops underneath. */
.dash {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(300px, 350px);
  gap: 20px;
  align-items: start;
}
.dash-main, .dash-side { display: flex; flex-direction: column; gap: 16px; min-width: 0; }

.dash-head { margin-bottom: 18px; }
.dash-head h2 { margin-bottom: 2px; }
.dash-head .muted { margin: 0; }

/* Section headings are set small and lettered out, with a short silver rule
   beneath. Institutional stylesheets use a label, not a big heading, to open a
   section — the rule does the separating that a card border used to do. */
.sec-head {
  position: relative;
  display: flex; align-items: baseline; justify-content: space-between; gap: 12px;
  margin-bottom: 12px;
  padding-bottom: 8px;
  border-bottom: 1px solid var(--border-soft);
}
/* The silver sits on the divider itself, not under the heading text — the row
   is baseline-aligned, so anything hung off the h3 would float above the rule. */
.sec-head::after {
  content: '';
  position: absolute;
  inset-inline-start: 0;
  bottom: -1px;
  width: 34px;
  height: 2px;
  background: var(--silver);
}
.sec-head h3 {
  margin: 0;
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--text-secondary);
}
.sec-head a { font-size: 12.5px; font-weight: 600; }

/* ---- accounts ---- */
.acct-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 12px; }
.acct {
  padding: 16px;
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-md);
  background: var(--bg-card);
  box-shadow: var(--shadow-card);
  transition: transform 150ms ease, box-shadow 150ms ease;
}
.acct:hover { border-color: var(--silver-strong); background: var(--bg-muted); }
.acct-top { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-bottom: 8px; }
.acct-id { display: flex; align-items: center; gap: 9px; min-width: 0; }
.acct-id .acct-badge { width: 30px; height: 30px; font-size: 9.5px; }
.acct-name { font-size: 12px; font-weight: 600; color: var(--text-secondary); }
.acct-bal { font-size: 26px; font-weight: 700; line-height: 1.1; letter-spacing: -0.5px; }
.acct-cur { font-size: 13px; font-weight: 600; color: var(--text-secondary); margin-inline-start: 5px; }
.acct-num { margin-top: 4px; font-size: 12px; color: var(--text-muted); font-variant-numeric: tabular-nums; }
.acct-links {
  display: flex; gap: 12px;
  margin-top: 12px; padding-top: 10px;
  border-top: 1px solid var(--border-soft);
  font-size: 12.5px; font-weight: 600;
}

.pill {
  padding: 2px 9px;
  border-radius: var(--radius-pill);
  font-size: 10.5px; font-weight: 700;
  text-transform: uppercase; letter-spacing: .4px;
  border: 1px solid transparent;
}
.pill.active { background: #ECFDF5; border-color: #A7F3D0; color: #047857; }
.pill.pending, .pill.requested { background: #FFFBEB; border-color: #FDE68A; color: #B45309; }
.pill.blocked, .pill.cancelled, .pill.rejected { background: #FEF2F2; border-color: #FECACA; color: #B91C1C; }
.pill.closed { background: var(--bg-muted); border-color: var(--border-strong); color: var(--text-secondary); }

/* ---- flags and the pickers that carry them ---------------------------- */
/* Flags are inline SVG, not emoji: Windows has no flag glyphs and would show
   a pair of letters instead. */
.flag {
  flex: none;
  width: 22px; height: 15px;
  border-radius: 3px;
  box-shadow: 0 0 0 1px rgba(15, 23, 42, 0.14) inset;
  object-fit: cover;
}
.flag-letters {
  display: grid; place-items: center;
  background: var(--bg-muted);
  color: var(--text-secondary);
  font-size: 9px; font-weight: 700; letter-spacing: .3px;
}
.flag-lg { width: 26px; height: 18px; }

.flag-picker { position: relative; display: inline-block; }
.flag-picker-btn {
  display: flex; align-items: center; gap: 8px;
  margin: 0;
  padding: 7px 11px;
  min-height: 36px;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  background: var(--bg-card);
  font: inherit; font-size: 13px; font-weight: 500;
  color: var(--text-primary);
  cursor: pointer;
}
.flag-picker-btn:hover { border-color: var(--brand-blue-primary); transform: none; box-shadow: none; }
.flag-picker-btn[aria-expanded="true"] { border-color: var(--brand-blue-primary); }
.flag-picker-label { white-space: nowrap; }
.flag-picker-caret { flex: none; color: var(--text-muted); transition: transform 150ms ease; }
.flag-picker-btn[aria-expanded="true"] .flag-picker-caret { transform: rotate(180deg); }

.flag-picker-list {
  position: absolute;
  z-index: 40;
  inset-inline-start: 0;
  top: calc(100% + 5px);
  min-width: 100%;
  max-height: 300px;
  overflow-y: auto;
  padding: 5px;
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-md);
  background: var(--bg-card);
  /* The panel paints its own surface, so it has to paint its own text too.
     Options are `color: inherit`, and on the login and registration screens
     the host (.auth-lang) is white-on-navy — which left every option white on
     this white panel and invisible. Anything that opens over its own
     background cannot borrow the foreground of whatever it opened from. */
  color: var(--text-primary);
  box-shadow: var(--shadow-float);
}
.flag-option {
  display: flex; align-items: center; gap: 9px;
  width: 100%;
  margin: 0;
  padding: 7px 9px;
  border: 0;
  border-radius: var(--radius-sm);
  background: none;
  box-shadow: none;
  font: inherit; font-size: 13px; font-weight: 500;
  color: inherit;
  text-align: start;
  white-space: nowrap;
  cursor: pointer;
}
.flag-option:hover, .flag-option:focus-visible {
  background: var(--bg-muted);
  transform: none; box-shadow: none; border: 0;
}
.flag-option[aria-selected="true"] { background: #EFF6FF; }
.flag-option-sub { margin-inline-start: auto; font-size: 11.5px; color: var(--text-secondary); }

/* on the navy login and registration screens the picker follows the surface */
.auth-lang .flag-picker-btn, .reg-top .flag-picker-btn {
  background: rgba(255, 255, 255, 0.1);
  border-color: rgba(255, 255, 255, 0.28);
  color: var(--text-on-dark);
}
.auth-lang .flag-picker-btn:hover, .reg-top .flag-picker-btn:hover { border-color: rgba(255, 255, 255, 0.55); }
.auth-lang .flag-picker-caret, .reg-top .flag-picker-caret { color: rgba(255, 255, 255, 0.7); }

/* in the sidebar it spans the column like the select it replaced */
#sidebar .flag-picker { display: block; }
#sidebar .flag-picker-btn { width: 100%; }
#sidebar .flag-picker-list { max-height: 260px; }
/* Set by flagPicker when there is not room below the button. */
.flag-picker-list.drop-up { top: auto; bottom: calc(100% + 5px); }

/* a circular flag reads better than a lettered disc on account rows */
.acct-flag {
  display: grid; place-items: center;
  flex: none;
  width: 36px; height: 36px;
  overflow: hidden;
  border: 1px solid var(--border-soft);
  border-radius: 50%;
  background: var(--bg-muted);
}
.acct-flag .flag { width: 100%; height: 100%; border-radius: 0; box-shadow: none; }
.acct-id .acct-flag { width: 30px; height: 30px; }
.acct-hero .acct-flag { width: 46px; height: 46px; }
.total-chip .flag { margin-inline-end: 2px; }
.total-chip { align-items: center; }

/* asset rows on the investment page: every mark is the same 24px square,
   whether it holds a flag or an instrument icon, so the column lines up */
.asset-cell { display: flex; align-items: center; gap: 9px; min-width: 0; }
.asset-cell b { font-weight: 600; }
.asset-cell-name { font-size: 12px; color: var(--text-secondary); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.asset-mark {
  display: grid; place-items: center;
  flex: none;
  width: 24px; height: 24px;
  overflow: hidden;
  border: 1px solid var(--border-soft);
  border-radius: 6px;
  background: var(--bg-muted);
}
.asset-mark .flag { width: 100%; height: 100%; border-radius: 0; box-shadow: none; }

/* ---- one-line account switcher ---------------------------------------- */
/* A single row naming the account you are looking at, which opens into every
   account you hold. Picking one lands on that account's own history page. */
/* the entry animation on every #main child makes it a stacking context, so
   the host has to be lifted or the open list falls behind later siblings */
#main > .switch-host { position: relative; z-index: 40; }
.acct-switch { position: relative; width: min(420px, 100%); }
.acct-switch-btn {
  display: flex; align-items: center; gap: 11px;
  width: 100%;
  min-height: 52px;
  margin: 0;
  padding: 9px 13px;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-md);
  background: var(--bg-card);
  box-shadow: var(--shadow-card);
  font: inherit;
  color: var(--text-primary);
  text-align: start;
  cursor: pointer;
}
.acct-switch-btn:hover { border-color: var(--brand-blue-primary); transform: none; }
.acct-switch-btn[aria-expanded="true"] { border-color: var(--brand-blue-primary); }
.acct-switch-main { min-width: 0; }
.acct-switch-title {
  font-size: 13.5px; font-weight: 700; line-height: 1.25;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.acct-switch-sub { font-size: 11.5px; color: var(--text-secondary); font-variant-numeric: tabular-nums; }
.acct-switch-amt { margin-inline-start: auto; font-size: 14px; font-weight: 700; font-variant-numeric: tabular-nums; white-space: nowrap; }
.acct-switch-caret { flex: none; color: var(--text-muted); transition: transform 150ms ease; }
.acct-switch-btn[aria-expanded="true"] .acct-switch-caret { transform: rotate(180deg); }

.acct-badge {
  display: grid; place-items: center;
  flex: none;
  width: 36px; height: 36px;
  border-radius: 50%;
  background: linear-gradient(135deg, var(--brand-navy-hero) 0%, var(--brand-blue-primary) 100%);
  color: var(--text-on-dark);
  font-size: 10.5px; font-weight: 700; letter-spacing: .3px;
}
.acct-badge.muted-badge { background: linear-gradient(135deg, #64748B 0%, #94A3B8 100%); }

.acct-switch-list {
  position: absolute;
  z-index: 30;
  inset-inline-start: 0;
  top: calc(100% + 6px);
  min-width: 100%;
  max-height: 330px;
  overflow-y: auto;
  padding: 6px;
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-md);
  background: var(--bg-card);
  box-shadow: var(--shadow-float);
}
.acct-option {
  display: flex; align-items: center; gap: 11px;
  width: 100%;
  margin: 0;
  padding: 9px 10px;
  border: 0;
  border-radius: var(--radius-sm);
  background: none;
  box-shadow: none;
  font: inherit;
  color: inherit;
  text-align: start;
  cursor: pointer;
}
.acct-option:hover, .acct-option:focus-visible {
  background: var(--bg-muted);
  transform: none;
  box-shadow: none;
  border: 0;
}
.acct-option[aria-selected="true"] { background: #EFF6FF; }
.acct-option .amt { margin-inline-start: auto; font-weight: 700; font-variant-numeric: tabular-nums; white-space: nowrap; }
.acct-option-sub { font-size: 11.5px; color: var(--text-secondary); }
.acct-switch-group {
  padding: 8px 10px 4px;
  font-size: 10.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .5px;
  color: var(--text-muted);
}

/* ---- per-currency totals ------------------------------------------------ */
.totals { display: flex; flex-wrap: wrap; gap: 10px; margin: 0 0 18px; }
.total-chip {
  display: flex; align-items: baseline; gap: 9px;
  padding: 9px 15px;
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-pill);
  background: var(--bg-card);
  box-shadow: var(--shadow-card);
}
.total-chip .cur { font-size: 11px; font-weight: 700; letter-spacing: .5px; color: var(--text-secondary); }
.total-chip .val { font-size: 15px; font-weight: 700; font-variant-numeric: tabular-nums; }

/* ---- account detail header --------------------------------------------- */
.acct-hero { display: flex; flex-wrap: wrap; align-items: center; gap: 16px; }
.acct-hero .acct-badge { width: 46px; height: 46px; font-size: 12px; }
.acct-hero-main { min-width: 0; }
.acct-hero-name { display: flex; align-items: center; gap: 9px; font-size: 15px; font-weight: 700; }
.acct-hero-num { font-size: 12.5px; color: var(--text-secondary); font-variant-numeric: tabular-nums; }
.acct-hero-bal { margin-inline-start: auto; font-size: 28px; font-weight: 700; letter-spacing: -.5px; font-variant-numeric: tabular-nums; }
.acct-hero-bal span { margin-inline-start: 5px; font-size: 13px; font-weight: 600; color: var(--text-secondary); }

.filters { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 12px; margin-bottom: 14px; }
.filters .field { margin: 0; }
.filters .field label {
  display: block; margin-bottom: 6px;
  font-size: 12px; font-weight: 600; color: var(--text-secondary);
}
.filters input, .filters select, .filters button { margin: 0; min-height: 38px; }

/* ---- the card face ---- */
.card-rail {
  display: flex; gap: 14px;
  overflow-x: auto;
  padding-bottom: 4px;
  scroll-snap-type: x proximity;
  -webkit-overflow-scrolling: touch;
}
.card-rail > * { scroll-snap-align: start; }

.bankcard {
  position: relative;
  flex: none;
  width: 320px;
  aspect-ratio: 1.586;            /* ID-1, the proportion of a real card */
  padding: 17px 19px;
  border-radius: 15px;
  display: flex; flex-direction: column; justify-content: space-between;
  overflow: hidden;
  color: #fff;
  background: linear-gradient(135deg, #06203C 0%, #0F3D6B 46%, #117ACA 100%);
  box-shadow: 0 14px 30px rgba(2, 14, 28, 0.3);
}
/* a light sweep across the top-right corner, the way a printed card catches it */
.bankcard::after {
  content: '';
  position: absolute; inset: 0;
  background:
    radial-gradient(120% 80% at 88% -12%, rgba(255, 255, 255, 0.2), rgba(255, 255, 255, 0) 58%),
    linear-gradient(200deg, rgba(255, 255, 255, 0.08) 0%, rgba(255, 255, 255, 0) 42%);
  pointer-events: none;
}
.bankcard > * { position: relative; z-index: 1; }
.bankcard.credit { background: linear-gradient(135deg, #14213D 0%, #3A2A5E 48%, #6D4AA6 100%); }
.bankcard.requested { background: linear-gradient(135deg, #334155 0%, #52606D 50%, #7B8794 100%); }
.bankcard.blocked, .bankcard.cancelled, .bankcard.rejected { filter: grayscale(0.8); opacity: 0.78; }

.bankcard-top { display: flex; align-items: flex-start; justify-content: space-between; gap: 10px; }
.bankcard-brand { display: flex; align-items: center; gap: 8px; }
.bankcard-mark {
  width: 26px; height: 26px;
  border-radius: 7px;
  display: grid; place-items: center;
  background: rgba(255, 255, 255, 0.18);
  border: 1px solid rgba(255, 255, 255, 0.34);
  font-size: 11px; font-weight: 700; letter-spacing: .5px;
}
.bankcard-name { font-size: 12.5px; font-weight: 700; letter-spacing: .3px; }
.bankcard-kind {
  font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: 1.2px;
  color: rgba(255, 255, 255, 0.82);
}

.bankcard-mid { display: flex; align-items: center; gap: 12px; }
/* chip and contactless glyph — both generic, no scheme marks anywhere */
.bankcard-chip {
  position: relative;
  width: 38px; height: 28px;
  border-radius: 5px;
  background: linear-gradient(145deg, #F5D98B 0%, #D8B563 45%, #F2E2AE 100%);
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.16);
}
.bankcard-chip::before, .bankcard-chip::after {
  content: '';
  position: absolute;
  background: rgba(0, 0, 0, 0.22);
}
.bankcard-chip::before { left: 0; right: 0; top: 50%; height: 1px; }
.bankcard-chip::after { top: 4px; bottom: 4px; left: 50%; width: 1px; }
.bankcard-wave { opacity: 0.85; }

.bankcard-pan {
  font-size: 17px;
  font-weight: 600;
  letter-spacing: 2.2px;
  font-variant-numeric: tabular-nums;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.28);
}
.bankcard-foot { display: flex; align-items: flex-end; justify-content: space-between; gap: 12px; }
.bankcard-label {
  margin-bottom: 2px;
  font-size: 8px; font-weight: 700; text-transform: uppercase; letter-spacing: 1px;
  color: rgba(255, 255, 255, 0.62);
}
.bankcard-value { font-size: 12.5px; font-weight: 600; letter-spacing: .6px; text-transform: uppercase; }
.bankcard-meta { margin-top: 8px; font-size: 12px; color: var(--text-secondary); }
.bankcard-meta b { color: var(--text-primary); }

.card-slot { flex: none; width: 320px; }
.card-empty {
  display: grid; place-items: center;
  aspect-ratio: 1.586;
  padding: 16px;
  border: 1px dashed var(--border-strong);
  border-radius: 15px;
  background: var(--bg-muted);
  color: var(--text-secondary);
  font-size: 13px; font-weight: 600;
  text-align: center;
}

/* ---- credit report check ---------------------------------------------- */
.credit-steps {
  margin: 0 0 18px;
  padding-inline-start: 20px;
  font-size: 13px;
  color: var(--text-secondary);
}
.credit-steps li { margin-bottom: 5px; }
.credit-steps li::marker { color: var(--brand-blue-primary); font-weight: 700; }
#creditDetail { margin-top: 14px; }
#creditDetail .card-actions { margin-top: 14px; }
/* The country list is long, so it gets more room than a currency picker.
   The field needs a flex basis too: without one it shrinks to the button and
   the button, sized at 100% of it, shrinks to its own text. */
#creditGate .apply-card .field { flex: 1 1 260px; max-width: 360px; }
#creditGate .flag-picker { display: block; width: 100%; }
#creditGate .flag-picker-btn { width: 100%; }
#creditGate .flag-picker-list { max-height: 340px; }
#applyPanel .apply-card:has(:disabled) { opacity: .55; }

/* ---- cards page: the same face, with the detail and controls beneath it ---- */
.card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
  gap: 18px;
  align-items: start;
  margin-bottom: 22px;
}
.card-item { display: flex; flex-direction: column; gap: 14px; min-width: 0; }
/* on this page the face flexes with its column instead of staying at rail width */
.card-item .bankcard { width: 100%; max-width: 370px; }

.card-facts { display: grid; grid-template-columns: repeat(auto-fit, minmax(116px, 1fr)); gap: 10px 14px; }
.card-fact-label {
  font-size: 10.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .4px;
  color: var(--text-muted);
}
.card-fact-value { font-size: 14px; font-weight: 600; font-variant-numeric: tabular-nums; }

.card-actions {
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px;
  padding-top: 12px;
  border-top: 1px solid var(--border-soft);
}
.card-actions input { width: 92px; margin: 0; }
.card-actions input.merchant { width: 136px; }
.card-actions button { margin: 0; }
.card-actions .spend {
  display: flex; align-items: center; gap: 6px;
  padding-inline-end: 8px;
  border-inline-end: 1px solid var(--border-soft);
}

.apply-card { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 12px; }
/* A wrapper that groups controls for showing and hiding, without becoming a
   layout box itself. `#openAccRow` is a <span> holding two labelled fields and
   a button: as an ordinary inline box the fields stacked vertically inside it
   and sat out of line with the buttons beside them. `display: contents` lifts
   its children into the flex row so they align like every other control.
   Hiding still works — the base layer's `[hidden] { display: none !important }`
   outranks this. */
.apply-card .field-group { display: contents; }
.apply-card .field { margin: 0; }
.apply-card .field label {
  display: block; margin-bottom: 6px;
  font-size: 12px; font-weight: 600; color: var(--text-secondary);
}
.apply-card select { margin: 0; min-height: 38px; }
.apply-card button { margin: 0; min-height: 38px; }

/* ---- side rail ---- */
.dash-side .panel { margin-bottom: 0; padding: 14px 16px; }
.dash-side h3 { font-size: 14px; }
.feed { display: flex; flex-direction: column; gap: 8px; font-size: 13px; }
.feed-item { display: flex; gap: 8px; align-items: flex-start; color: var(--text-secondary); }
.feed-item.unread { color: var(--text-primary); font-weight: 500; }
.feed-dot {
  flex: none;
  width: 6px; height: 6px; margin-top: 6px;
  border-radius: 50%;
  background: var(--border-strong);
}
.feed-item.unread .feed-dot { background: var(--brand-blue-primary); }
.feed-more { margin: 10px 0 0; font-size: 12.5px; font-weight: 600; }

.offer-row { display: flex; gap: 10px; align-items: center; }
.offer-row img { flex: none; width: 52px; height: 52px; object-fit: cover; border-radius: var(--radius-sm); }
.offer-row b { font-size: 13px; }

td.num, th.num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }

@media (max-width: 1100px) {
  .dash { grid-template-columns: minmax(0, 1fr); }
}
@media (max-width: 560px) {
  .bankcard, .card-slot { width: 270px; }
  .acct-bal { font-size: 23px; }
}

/* --------------------------------------------------------- login screen -- */

.auth-page,
.reg-page {
  /* The diagonal rim: where the photo wedge begins at the top and at the
     bottom of the viewport. Re-angle the whole split by tuning these two. */
  --cut-top: 78%;
  --cut-bottom: 48%;
  --scrim-angle: 100deg;

  /* One photograph for every visitor. The painted gradient behind it echoes the
     same open sky, so the page still reads correctly if the file is missing.
     data-tod is still set on <body>, but it now only drives the greeting. */
  --scene-photo: url('/img/login.jpg?v=202611041609');
  --scene-paint: linear-gradient(180deg, #BFDCEF 0%, #D8E7F2 38%, #E7E2D6 66%, #CBBEAA 100%);
  --base-top: #04182E;
  --base-mid: #0A2540;
  --base-bottom: #0E3A63;

  position: relative;
  min-height: 100vh;
  min-height: 100dvh;
  margin: 0;
  overflow-x: hidden;
  color: var(--text-on-dark);
  background: linear-gradient(155deg, var(--base-top) 0%, var(--base-mid) 52%, var(--base-bottom) 100%);
}

.auth-scene {
  position: absolute;
  inset: 0;
  background-image: var(--scene-paint);
  background-size: cover;
  background-position: 50% 50%;
  background-repeat: no-repeat;
  clip-path: polygon(var(--cut-top) 0, 100% 0, 100% 100%, var(--cut-bottom) 100%);
  animation: sceneIn 900ms var(--ease-out) both;
}
/* The photo sits in its own layer so it can be given a smaller area than the
   wedge. The source files are only ~550px across; stretching one over a whole
   1440x900 viewport magnified it about 2.6x and the softness showed. */
.auth-photo {
  position: absolute;
  inset: 0;
  background-image: var(--scene-photo);
  background-repeat: no-repeat;
  background-position: 50% 50%;
  background-size: cover;
}

/* Blends the wedge into the navy along the rim and keeps the lower edge calm. */
.auth-scene::after {
  content: '';
  position: absolute;
  inset: 0;
  background:
    linear-gradient(var(--scrim-angle), var(--base-mid) 0%, rgba(10, 37, 64, 0.55) 13%, rgba(10, 37, 64, 0) 40%),
    linear-gradient(180deg, rgba(4, 24, 46, 0.26) 0%, rgba(4, 24, 46, 0) 32%, rgba(4, 24, 46, 0.48) 100%);
}
/* The rim itself: a 2px lit line running along the cut. */
.auth-rim {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.62) 0%, rgba(255, 255, 255, 0.26) 48%, rgba(255, 255, 255, 0.07) 100%);
  clip-path: polygon(
    var(--cut-top) 0,
    calc(var(--cut-top) + 2px) 0,
    calc(var(--cut-bottom) + 2px) 100%,
    var(--cut-bottom) 100%);
}

@media (min-width: 901px) {
  /* Desktop: the photo covers only the middle of the wedge and feathers into
     the painted gradient above and below, which drops the magnification to
     roughly 1.5x. The rim still runs the full height of the page. */
  .auth-photo {
    inset: 26% 0 26% 56%;
    -webkit-mask-image: linear-gradient(180deg, transparent 0%, #000 10%, #000 90%, transparent 100%);
    mask-image: linear-gradient(180deg, transparent 0%, #000 10%, #000 90%, transparent 100%);
  }
  [dir="rtl"] .auth-photo { inset: 26% 56% 26% 0; }
}

.auth-shell {
  position: relative;
  z-index: 2;
  min-height: 100vh;
  min-height: 100dvh;
  display: grid;
  grid-template-rows: auto 1fr auto;
  gap: 20px;
  padding: clamp(18px, 2.6vw, 30px) clamp(20px, 5vw, 60px);
}

.auth-top { display: flex; align-items: center; justify-content: space-between; gap: 16px; }
.auth-top .brand { margin-bottom: 0; }
.auth-page .brand-name { color: var(--text-on-dark); }
.auth-page .brand-sub { color: rgba(255, 255, 255, 0.62); }
.auth-page .brand-mark {
  background: rgba(255, 255, 255, 0.14);
  border: 1px solid rgba(255, 255, 255, 0.32);
}

.auth-lang { display: flex; align-items: center; gap: 8px; font-size: 12px; color: rgba(255, 255, 255, 0.72); }
.auth-lang select {
  margin: 0;
  background: rgba(255, 255, 255, 0.1);
  border-color: rgba(255, 255, 255, 0.28);
  color: var(--text-on-dark);
}
.auth-lang select option { color: var(--text-primary); }

.auth-body { display: flex; align-items: center; justify-content: flex-start; }
.auth-col { width: min(430px, 100%); display: flex; flex-direction: column; gap: 18px; }

.auth-greet {
  margin-bottom: 8px;
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: 1.4px;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.72);
}
.auth-intro h1 {
  margin-bottom: 10px;
  color: var(--text-on-dark);
  font-size: clamp(30px, 3.4vw, 42px);
}
.auth-intro p {
  margin: 0;
  max-width: 42ch;
  font-size: 14.5px;
  color: rgba(255, 255, 255, 0.78);
}

.auth-card {
  padding: 26px 26px 22px;
  border-radius: var(--radius-lg);
  background: var(--bg-card);
  color: var(--text-primary);
  box-shadow: 0 24px 60px rgba(2, 14, 28, 0.38);
}
.auth-card h2 { font-size: 19px; margin-bottom: 16px; }
.auth-card .field { margin-bottom: 14px; }
.auth-card .field label {
  display: block;
  margin-bottom: 6px;
  font-size: 12px;
  font-weight: 600;
  color: var(--text-secondary);
}
.auth-card input { width: 100%; margin: 0; min-height: 42px; }
.auth-card button { width: 100%; margin: 0; }
.auth-card .btn-ghost { min-height: 44px; }
.auth-msg { margin: 10px 0 0; min-height: 16px; font-size: 12.5px; color: var(--accent-red); }
.auth-card .divider {
  display: flex; align-items: center; gap: 10px;
  margin: 16px 0;
  font-size: 12px;
  color: var(--text-muted);
}
.auth-card .divider::before, .auth-card .divider::after {
  content: ''; flex: 1; height: 1px; background: var(--border-soft);
}
.auth-alt { margin: 14px 0 0; text-align: center; font-size: 13px; }

.creds {
  border: 1px solid rgba(255, 255, 255, 0.16);
  border-radius: var(--radius-md);
  background: rgba(255, 255, 255, 0.07);
  backdrop-filter: blur(6px);
  font-size: 11.5px;
  line-height: 1.75;
  color: rgba(255, 255, 255, 0.76);
}
.creds > summary {
  display: flex; align-items: center; gap: 8px;
  padding: 10px 14px;
  list-style: none;
  cursor: pointer;
  font-size: 12px;
  font-weight: 600;
  color: rgba(255, 255, 255, 0.88);
}
.creds > summary::-webkit-details-marker { display: none; }
.creds > summary::after { content: '+'; margin-inline-start: auto; font-size: 15px; opacity: 0.7; }
.creds[open] > summary::after { content: '\2212'; }
.creds .creds-body { padding: 0 14px 12px; }
.creds b { color: #fff; font-weight: 600; }

.auth-foot { font-size: 11.5px; color: rgba(255, 255, 255, 0.5); }

[dir="rtl"] .auth-page { --scrim-angle: 260deg; }
[dir="rtl"] .auth-scene {
  clip-path: polygon(0 0, calc(100% - var(--cut-top)) 0, calc(100% - var(--cut-bottom)) 100%, 0 100%);
}
[dir="rtl"] .auth-rim {
  clip-path: polygon(
    calc(100% - var(--cut-top)) 0,
    calc(100% - var(--cut-top) - 2px) 0,
    calc(100% - var(--cut-bottom) - 2px) 100%,
    calc(100% - var(--cut-bottom)) 100%);
}
[dir="rtl"] .auth-body { justify-content: flex-end; }

@keyframes sceneIn { from { opacity: 0; } to { opacity: 1; } }

@media (max-width: 900px) {
  /* Portrait has no room for a vertical wedge, so the same cut runs across the
     top instead — deeper on the left, shallow on the right — and the card sits
     below the rim rather than on top of it. */
  .auth-page { --m-cut-left: 40%; --m-cut-right: 25%; }
  .auth-page .auth-scene {
    clip-path: polygon(0 0, 100% 0, 100% var(--m-cut-right), 0 var(--m-cut-left));
  }
  /* only the band is visible, so that is all the photo has to cover — at full
     page height cover would magnify it 2.3x for nothing */
  .auth-page .auth-photo { bottom: auto; height: var(--m-cut-left); }
  .auth-page .auth-scene::after {
    background: linear-gradient(180deg, rgba(4, 24, 46, 0.64) 0%, rgba(4, 24, 46, 0.5) 28%, rgba(4, 24, 46, 0.26) 62%, rgba(4, 24, 46, 0.55) 100%);
  }
  .auth-page .auth-rim {
    background: linear-gradient(90deg, rgba(255, 255, 255, 0.14) 0%, rgba(255, 255, 255, 0.5) 100%);
    clip-path: polygon(
      0 var(--m-cut-left),
      100% var(--m-cut-right),
      100% calc(var(--m-cut-right) + 2px),
      0 calc(var(--m-cut-left) + 2px));
  }
  [dir="rtl"] .auth-page .auth-scene {
    clip-path: polygon(0 0, 100% 0, 100% var(--m-cut-left), 0 var(--m-cut-right));
  }
  [dir="rtl"] .auth-page .auth-rim {
    clip-path: polygon(
      0 var(--m-cut-right),
      100% var(--m-cut-left),
      100% calc(var(--m-cut-left) + 2px),
      0 calc(var(--m-cut-right) + 2px));
  }
  /* the column dissolves into the shell grid so the card can be pinned to the
     bottom, keeping the rim clear of it */
  .auth-body, .auth-col { display: contents; }
  .auth-shell { grid-template-rows: auto auto 1fr auto auto; }
  .auth-intro { align-self: start; }
  .auth-card { align-self: end; }
}
@media (max-width: 560px) {
  .auth-top .brand-sub { display: none; }
  .auth-card { padding: 20px 18px 18px; }
}
/* Laptop-height screens: tighten the rhythm so the card never needs a scroll. */
@media (max-height: 860px) {
  .auth-shell { padding-top: 16px; padding-bottom: 16px; gap: 12px; }
  .auth-col { gap: 12px; }
  .auth-greet { margin-bottom: 6px; }
  .auth-intro h1 { font-size: clamp(26px, 2.6vw, 32px); margin-bottom: 8px; }
  .auth-intro p { font-size: 13.5px; }
  .auth-card { padding: 20px 22px 18px; }
  .auth-card h2 { margin-bottom: 12px; }
  .auth-card .field { margin-bottom: 11px; }
  .auth-card .divider { margin: 12px 0; }
  .auth-alt { margin-top: 12px; }
  .auth-foot { display: none; }
}

/* Short phones: the intro loses its description and the band flattens, so the
   rim still passes between the heading and the card instead of through them. */
@media (max-width: 900px) and (max-height: 760px) {
  .auth-page { --m-cut-left: 28%; --m-cut-right: 20%; }
  .auth-intro p { display: none; }
  .auth-card { padding: 16px 16px 14px; }
  .auth-card h2 { margin-bottom: 10px; }
  .auth-card .field { margin-bottom: 9px; }
  .auth-card input { min-height: 40px; }
  .auth-card .divider { margin: 10px 0; }
  .auth-alt { margin-top: 10px; }
  .creds > summary { padding: 8px 12px; }
}

/* Short phones: the last few pixels that keep the card off a scrollbar. */
@media (max-width: 900px) and (max-height: 880px) {
  .auth-shell { gap: 9px; padding-bottom: 10px; }
}

@media (prefers-reduced-motion: reduce) {
  .auth-scene { animation: none; }
}

/* ---- login: photo across the page, form on the left, links beside it ----- */
/* The wedge and its rim belong to the registration hero now. Here the picture
   runs edge to edge and a wash across the left carries the form, which is the
   arrangement most retail banks land on. Brand colour stays blue throughout. */
.auth-page {
  color: var(--text-primary);
  background: var(--bg-card);
  --photo-w: min(560px, 34vw);
  /* How far the picture pulls in from the right edge so it sits nearer the
     middle. Nothing below 1200px, where there is no width to spare, then it
     drifts inward as the viewport grows — about 400px on a 1865px screen. The
     content column subtracts the same value, so the two can never close the
     gap between them however wide the window gets. */
  --photo-end: clamp(0px, (100vw - 1200px) * 0.6, 400px);
  /* Where the picture's left edge falls, so the wash can be aimed at it. */
  --photo-x: calc(100vw - var(--photo-end) - var(--photo-w));
  /* This picture carries no vignette of its own — sampling it, the studio grey
     (210,212,211) runs hard to all four edges and her jacket (43,92,124) goes
     straight off the bottom. So: two straight fades, which between them take
     every edge and corner to nothing, and an oval over the top to round what is
     left. Centred at 53% 56% because she sits centre-right and low in frame.
     Declared here rather than on the picture so the aside's copy and the phone
     band's copy are fed by the same one. */
  --photo-feather:
    radial-gradient(ellipse 90% 95% at 53% 56%,
      rgba(0, 0, 0, 1) 0%,
      rgba(0, 0, 0, 0.98) 50%,
      rgba(0, 0, 0, 0.85) 70%,
      rgba(0, 0, 0, 0.55) 85%,
      rgba(0, 0, 0, 0.20) 95%,
      rgba(0, 0, 0, 0) 100%),
    linear-gradient(90deg, transparent 0%, #000 16%, #000 92%, transparent 100%),
    linear-gradient(180deg, transparent 0%, #000 14%, #000 86%, transparent 100%);
}
/* The picture now carries its own white vignette, so the surface under it has
   to be white or that vignette reads as a pale rectangle sitting on the tint.
   Rather than drop the tint from the whole page, a soft white halo is laid over
   the paint behind the picture and dissolves back into it. It goes on the
   scene's own background, not on ::after — ::after is generated after the photo
   and would paint the halo straight over the family. */
.auth-page .auth-scene {
  clip-path: none;
  animation: none;
  background-image:
    radial-gradient(ellipse calc(var(--photo-w) * 0.84) calc(var(--photo-w) * 0.62)
      at calc(var(--photo-x) + var(--photo-w) / 2) 46%,
      #fff 0%, #fff 68%, rgba(255, 255, 255, 0) 100%),
    var(--scene-paint);
}
.auth-page .auth-rim { display: none; }
/* ---- the right-hand column: headline, picture, benefits ------------------ */
/* The band it occupies is the one the picture used to have to itself. Three
   grid rows, and because the outer two are equal fractions the picture lands on
   the exact centre line whatever the headline and the list do above and below
   it — no coordinate has to be kept in step by hand. */
.auth-page .auth-aside {
  position: absolute;
  z-index: 3;
  inset-block: clamp(24px, 5vh, 60px) clamp(96px, 14vh, 130px);
  inset-inline-end: var(--photo-end);
  width: var(--photo-w);
  display: grid;
  grid-template-rows: 1fr auto 1fr;
  gap: clamp(14px, 2.2vh, 26px);
}
/* The band's lower inset exists to clear the promo strip. The reset page has no
   promo strip, only a 4px accent, so there it holds room for nothing and leaves
   the picture sitting about 40px above the optical centre. Keyed off the strip
   itself rather than a new class, so any auth page without one is covered. */
.auth-page:not(:has(.auth-promo)) .auth-aside {
  inset-block-end: clamp(24px, 5vh, 60px);
}
.aside-head {
  /* Centred in its own row rather than pushed against the picture, so the two
     spare rows read as even space instead of a gap at the top of the band. */
  align-self: center;
  margin: 0;
  color: var(--brand-navy-hero);
  font-size: clamp(17px, 1.3vw, 21px);
  font-weight: 700;
  line-height: 1.32;
  text-align: center;
  text-wrap: balance;
}
.aside-photo {
  width: 100%;
  aspect-ratio: 612 / 408;
  background-image: var(--scene-photo);
  background-size: cover;
  background-position: 50% 50%;
  background-repeat: no-repeat;
  -webkit-mask-image: var(--photo-feather);
  mask-image: var(--photo-feather);
  -webkit-mask-composite: source-in, source-in, source-over;
  mask-composite: intersect, intersect, add;
}
.aside-list {
  align-self: center;
  justify-self: center;
  display: grid;
  gap: 9px;
  margin: 0;
  padding: 0;
  list-style: none;
}
.aside-list li {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 13.5px;
  color: var(--text-secondary);
}
.aside-list li::before {
  content: '\2713';
  flex: none;
  display: grid;
  place-items: center;
  width: 19px;
  height: 19px;
  border-radius: 50%;
  background: var(--brand-blue-primary);
  color: #fff;
  font-size: 10.5px;
  font-weight: 700;
}

.auth-page .auth-photo {
  /* The scene layer's copy is the phone band only; on desktop the picture is
     the middle row of .auth-aside instead. */
  display: none;
  /* Sized so the source is never enlarged. The file is 723x850; this box is
     smaller than that in both directions, so the browser scales it down and it
     stays sharp. Stretching it across the whole hero was what made it mushy.
     The bottom inset keeps it clear of the promo strip. */
  inset: clamp(24px, 5vh, 60px) var(--photo-end) clamp(96px, 14vh, 130px) auto;
  width: var(--photo-w);
  /* The picture is landscape, 612x408. Cropping it into a tall slot would mean
     scaling a 612px-wide source up about 1.8x, which is exactly the softness
     this slot was sized to avoid — so the slot takes the picture's proportions
     and centres itself in the band instead. At 560px wide it draws at 0.92x,
     a slight reduction, so it stays sharp. */
  height: calc(var(--photo-w) / 1.5);
  margin-block: auto;
  background-size: cover;
  background-position: 50% 50%;
  border-start-start-radius: var(--radius-lg);
  border-end-start-radius: var(--radius-lg);
  -webkit-mask-image: var(--photo-feather);
  mask-image: var(--photo-feather);
  /* Per layer, and the lowest must be `add`: it composites against transparent
     black, so `intersect` there would erase the picture entirely. */
  -webkit-mask-composite: source-in, source-in, source-over;
  mask-composite: intersect, intersect, add;
}
/* The wash used to be pinned to percentages of the viewport, which was fine
   while the picture was stuck to the right edge. Now that it moves, the stops
   are measured off --photo-x instead: white all the way to 150px short of the
   picture, gone again a sixth of the way into it. Percentages could not track
   both the text column and the picture, since they no longer move together.
   Squared off to 90deg for that reason — at 97deg the stops are measured along
   a tilted line and land about 5% wide of where the numbers say. */
.auth-page .auth-scene::after {
  background:
    linear-gradient(90deg,
      rgba(255, 255, 255, 1) 0,
      rgba(255, 255, 255, 0.95) calc(var(--photo-x) - 150px),
      rgba(255, 255, 255, 0.3) calc(var(--photo-x) + 20px),
      rgba(255, 255, 255, 0) calc(var(--photo-x) + var(--photo-w) * 0.16)),
    linear-gradient(180deg, rgba(255, 255, 255, 0.75) 0%, rgba(255, 255, 255, 0) 26%);
}

.auth-page .auth-shell { grid-template-rows: auto 1fr; padding-bottom: 0; }
.auth-page .brand-name { color: var(--text-primary); }
.auth-page .brand-sub { color: var(--text-muted); }
.auth-page .brand-mark {
  background: linear-gradient(135deg, var(--brand-navy-hero) 0%, var(--brand-blue-primary) 100%);
  border: 0;
}
.auth-page .auth-lang .flag-picker-btn {
  background: rgba(255, 255, 255, 0.85);
  border-color: var(--border-strong);
  color: var(--text-primary);
}
.auth-page .auth-lang .flag-picker-caret { color: var(--text-muted); }

/* the shell shares the page with the promo strip, which sits under it */
.auth-page { display: flex; flex-direction: column; }
.auth-page .auth-shell { flex: 1; min-height: 0; }
/* the single narrow column is the wedge layout; here it spans both columns */
/* Content runs up to the photo rather than to a fixed width, so the gap
   between them stays constant instead of growing with the viewport. */
.auth-page .auth-col {
  width: 100%;
  max-width: min(1240px, calc(var(--photo-x) - 150px));
  display: block;
}

.auth-welcome { margin-bottom: 22px; }
.auth-welcome h1 {
  margin: 0;
  color: var(--brand-navy-hero);
  font-size: clamp(24px, 2.8vw, 34px);
}
.auth-page .auth-greet {
  margin-bottom: 6px;
  color: var(--brand-blue-hover);
}

/* form on the left, everything else beside it */
.auth-cols {
  display: grid;
  grid-template-columns: minmax(0, 372px) minmax(0, 1fr);
  gap: clamp(28px, 5vw, 64px);
  align-items: start;
}

.auth-page .auth-card {
  padding: 26px 26px 22px;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-md);
  background: rgba(255, 255, 255, 0.94);
  box-shadow: 0 6px 20px rgba(15, 23, 42, 0.08);
}
.auth-page .auth-card h2 { color: var(--brand-navy-hero); }
.auth-card input[type="checkbox"] { width: 16px; min-height: 0; margin: 0; }

/* password with a reveal control sharing its box */
/* The eye sits beside the field, not on top of it. Floating it inside relied
   on padding-inline-end to keep the text clear, and that does not hold: once
   the value is longer than the box the input scrolls its own content, and the
   scrolled text renders straight through the reserved padding and under the
   icon. A generated password is exactly the case that overflows, so the one
   time the control matters most was the one time it was unreadable. */
/* The eye toggle overlays the field rather than sitting beside it. As a flex
   sibling it stole ~46px of width, so the password box came out visibly
   narrower than the email box above it. Now the input is full width like every
   other field and the toggle floats over its right edge. */
.pw-wrap { position: relative; display: block; }
.pw-wrap input { width: 100%; min-width: 0; padding-inline-end: 44px; }
/* Selector deliberately two classes deep. `.auth-card button { width: 100% }`
   is (0,1,1) and beat a bare `.pw-toggle` at (0,1,0). */
.pw-wrap .pw-toggle {
  position: absolute;
  inset-inline-end: 4px;
  top: 50%;
  transform: translateY(-50%);
  display: grid;
  place-items: center;
  width: 34px;
  min-width: 34px;
  height: 34px;
  min-height: 34px;
  margin: 0;
  padding: 0;
  border: 0;
  background: none;
  box-shadow: none;
  color: var(--text-muted);
  cursor: pointer;
}
.pw-wrap .pw-toggle:hover { background: none; border: 0; box-shadow: none; color: var(--brand-blue-primary); }
.pw-toggle[aria-pressed="true"] { color: var(--brand-blue-primary); }

.auth-remember {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 4px 0 16px;
  font-size: 13px;
  color: var(--text-secondary);
  font-weight: 500;
}
.auth-remember input { margin: 0; }

/* the column of onward links, chevrons and all */
/* Centred against the sign-in card rather than pinned to its top edge.
   This column used to hold a third block of demo credentials, which made it
   roughly as tall as the card; with that gone it is 155px beside a 447px card,
   and anchoring it to the top left the remaining 292px reading as a hole rather
   than as space. Centring makes the row balance at any card height, which also
   means it survives the card growing when an error message appears. */
.auth-links {
  padding-top: 4px;
  align-self: center;
}

/* Above 1600 the composition used to stop growing while the window kept going.
   The picture is pinned --photo-end from the right and everything else derives
   from --photo-x (= viewport - end - width), including the content column's own
   max-width and the glow painted behind the picture. So bringing the picture
   back toward the edge and letting it grow widens the content and moves the
   glow with it, from one place. At 1900 this turns 415px of empty page on the
   right into 220px, and gives the sign-in column about 120px more to work
   with. */
@media (min-width: 1600px) {
  .auth-page {
    --photo-end: clamp(0px, (100vw - 1200px) * 0.28, 240px);
    --photo-w: min(640px, 34vw);
  }
  .auth-page .auth-cols { grid-template-columns: minmax(0, 420px) minmax(0, 1fr); }
}
.auth-links a {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 8px 0;
  font-size: 14.5px;
  font-weight: 600;
  color: var(--brand-blue-hover);
}
.auth-links a:hover { text-decoration: none; color: var(--brand-navy-hero); }
.auth-links a svg { flex: none; transition: transform 150ms ease; }
.auth-links a:hover svg { transform: translateX(3px); }
.auth-links .creds { margin-top: 14px; }

/* The benefit list, in its new home beside the sign-in card. Same tick mark as
   it wore under the picture, left aligned instead of centred because it now
   sits in a column of left-aligned text rather than alone in a band. */
/* The employees screen. A colleague's photograph in the list, and the one time
   password shown after an account is created. Both live here rather than on a
   style attribute, which is what the design audit checks for. */
.staff-photo {
  width: 34px;
  height: 34px;
  border-radius: 50%;
  object-fit: cover;
  display: block;
}
.staff-pw {
  font-size: 18px;
  letter-spacing: 1px;
}

.auth-points {
  display: grid;
  gap: 9px;
  margin: 0 0 18px;
  padding: 0;
  list-style: none;
}
.auth-points li {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 13.5px;
  color: var(--text-secondary);
}
.auth-points li::before {
  content: '\2713';
  flex: none;
  display: grid;
  place-items: center;
  width: 19px;
  height: 19px;
  border-radius: 50%;
  background: var(--brand-blue-primary);
  color: #fff;
  font-size: 11px;
}

/* What the application asks for. Deliberately quieter than the list above it:
   this is reference, read once by somebody deciding whether to start. */
.auth-need {
  padding: 14px 16px;
  border: 1px solid var(--border-soft);
  border-radius: 12px;
  background: rgba(255, 255, 255, 0.55);
  font-size: 13px;
  line-height: 1.55;
  color: var(--text-secondary);
}
.auth-need b {
  display: block;
  margin-bottom: 7px;
  color: var(--text-primary);
}
.auth-need ul {
  display: grid;
  gap: 5px;
  margin: 0;
  padding-inline-start: 18px;
}

/* Made an identical box to .auth-need above it, rather than a divider-style
   note: same padding, border, radius and background, and no max-width, so the
   two boxes share a left edge and a width and read as a matched pair. */
.auth-secure {
  display: flex;
  gap: 11px;
  margin-top: 12px;
  padding: 14px 16px;
  border: 1px solid var(--border-soft);
  border-radius: 12px;
  background: rgba(255, 255, 255, 0.55);
  font-size: 13px;
  line-height: 1.55;
  color: var(--text-secondary);
}
.auth-secure svg { flex: none; margin-top: 2px; color: var(--brand-blue-primary); }
.auth-secure b { display: block; color: var(--text-primary); }

/* the offer strip along the bottom, and the brand rule under it */
.auth-promo {
  position: relative;
  z-index: 2;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: 18px;
  padding: 15px clamp(20px, 5vw, 60px);
  background: var(--brand-navy-dark);
  color: var(--text-on-dark);
  font-size: 14.5px;
}
.auth-promo .btn-primary { margin: 0; min-height: 40px; }
.auth-accent { position: relative; z-index: 2; height: 4px; background: var(--brand-blue-primary); }

/* the test-user panel is on a light surface here, not the navy one */
.auth-page .creds {
  border-color: var(--border-soft);
  background: var(--bg-muted);
  color: var(--text-secondary);
  backdrop-filter: none;
}
.auth-page .creds > summary { color: var(--text-primary); }
.auth-page .creds b { color: var(--text-primary); }

@media (max-width: 900px) {
  .auth-cols { grid-template-columns: minmax(0, 1fr); gap: 26px; }
  /* Portrait: the picture is a band across the top, so its side and top edges
     are the screen's own and only the lower one is a contour of ours. It gets
     the same treatment as the desktop edges — a fade, not a cut — and one
     layer is enough here, so no compositing is involved. */
  /* Portrait has no side column, so the aside stops being positioned and just
     falls into the page under the sign-in card. Its picture comes off — the
     band across the top is already showing her. */
  .auth-page .auth-aside {
    position: static;
    display: block;
    width: auto;
    padding: 4px 20px 28px;
  }
  /* The band across the top already shows her here, so the aside's copy of the
     picture comes off — and the arch has to go with it, or it is left standing
     as an empty grey shape framing nothing. */
  .auth-page .aside-photo,
  .auth-page .aside-arch { display: none; }
  .auth-page .aside-head { text-align: start; margin-bottom: 14px; }
  .auth-page .auth-photo {
    display: block;
    inset: 0;
    /* `width: min(560px, 34vw)` is the desktop column reservation. Left on, it
       squeezed the band to 34% of the screen and the picture showed as a strip
       down the left edge. The band spans the full width here. */
    width: auto;
    /* The desktop rule shapes the box to the picture. Here the box is the band
       across the top of the screen, so both the derived height and the auto
       margins that centre it have to come back off. */
    height: var(--m-cut-left);
    margin-block: 0;
    background-size: cover;
    background-position: 50% 26%;
    -webkit-mask-image: linear-gradient(180deg, #000 0%, #000 58%, transparent 100%);
    mask-image: linear-gradient(180deg, #000 0%, #000 58%, transparent 100%);
    -webkit-mask-composite: source-over;
    mask-composite: add;
  }
  .auth-page .auth-scene::after {
    background:
      linear-gradient(180deg, rgba(255, 255, 255, 0.55) 0%, rgba(255, 255, 255, 0.92) 34%, rgba(255, 255, 255, 0.98) 100%);
  }
  .auth-page .auth-body, .auth-page .auth-col { display: block; }
  /* The desktop rule reserves room for the photo column with
     `calc(100vw - 34vw - 150px)`. On a 390px phone that leaves 107px and the
     whole page renders as one crushed strip — there is no photo column here,
     so the reservation has to come off. */
  .auth-page .auth-col { max-width: none; }
  .auth-promo { justify-content: flex-start; text-align: start; }
}

/* -------------------------------------------------- registration screen -- */

.reg-page {
  /* The hero column is centred, so the cut runs across the band rather than
     down it — otherwise the rim would slice through the heading. */
  --r-cut-left: 96%;
  --r-cut-right: 74%;
  --reg-band: 300px;
  position: relative;
  min-height: 100vh;
  min-height: 100dvh;
  margin: 0;
  background: var(--bg-app);
  color: var(--text-primary);
}
/* here the scenery is a hero band rather than the whole page */
.reg-band {
  position: absolute;
  inset: 0 0 auto 0;
  height: var(--reg-band);
  background: linear-gradient(155deg, var(--base-top) 0%, var(--base-mid) 52%, var(--base-bottom) 100%);
}
.reg-page .auth-scene,
.reg-page .auth-rim { bottom: auto; height: var(--reg-band); }
.reg-page .auth-scene {
  clip-path: polygon(0 0, 100% 0, 100% var(--r-cut-right), 0 var(--r-cut-left));
}
.reg-page .auth-scene::after {
  background:
    linear-gradient(90deg, rgba(4, 24, 46, 0.74) 0%, rgba(4, 24, 46, 0.44) 56%, rgba(4, 24, 46, 0.2) 100%),
    linear-gradient(180deg, rgba(4, 24, 46, 0.5) 0%, rgba(4, 24, 46, 0.3) 60%, rgba(4, 24, 46, 0.12) 100%);
}
.reg-page .auth-rim {
  background: linear-gradient(90deg, rgba(255, 255, 255, 0.5) 0%, rgba(255, 255, 255, 0.16) 100%);
  clip-path: polygon(
    0 var(--r-cut-left),
    100% var(--r-cut-right),
    100% calc(var(--r-cut-right) + 2px),
    0 calc(var(--r-cut-left) + 2px));
}
[dir="rtl"] .reg-page .auth-scene {
  clip-path: polygon(0 0, 100% 0, 100% var(--r-cut-left), 0 var(--r-cut-right));
}
[dir="rtl"] .reg-page .auth-scene::after {
  background:
    linear-gradient(270deg, rgba(4, 24, 46, 0.74) 0%, rgba(4, 24, 46, 0.44) 56%, rgba(4, 24, 46, 0.2) 100%),
    linear-gradient(180deg, rgba(4, 24, 46, 0.5) 0%, rgba(4, 24, 46, 0.3) 60%, rgba(4, 24, 46, 0.12) 100%);
}
[dir="rtl"] .reg-page .auth-rim {
  background: linear-gradient(270deg, rgba(255, 255, 255, 0.5) 0%, rgba(255, 255, 255, 0.16) 100%);
  clip-path: polygon(
    0 var(--r-cut-right),
    100% var(--r-cut-left),
    100% calc(var(--r-cut-left) + 2px),
    0 calc(var(--r-cut-right) + 2px));
}

@media (min-width: 621px) {
  /* Same idea on the registration band: full width would magnify the photo
     2.6x, so it takes the right side and feathers into the gradient the hero
     text sits on. */
  .reg-page .auth-photo {
    inset: 0 0 0 58%;
    -webkit-mask-image: linear-gradient(90deg, transparent 0%, #000 24%, #000 100%);
    mask-image: linear-gradient(90deg, transparent 0%, #000 24%, #000 100%);
  }
  [dir="rtl"] .reg-page .auth-photo {
    inset: 0 58% 0 0;
    -webkit-mask-image: linear-gradient(270deg, transparent 0%, #000 24%, #000 100%);
    mask-image: linear-gradient(270deg, transparent 0%, #000 24%, #000 100%);
  }
}

.reg-shell {
  position: relative;
  z-index: 2;
  max-width: 780px;
  margin: 0 auto;
  padding: clamp(18px, 2.6vw, 28px) clamp(16px, 4vw, 28px) 48px;
}

.reg-top {
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
  margin-bottom: 18px;
}
.reg-top .brand { margin-bottom: 0; }
.reg-page .brand-name { color: var(--text-on-dark); }
.reg-page .brand-sub { color: rgba(255, 255, 255, 0.62); }
.reg-page .brand-mark {
  background: rgba(255, 255, 255, 0.14);
  border: 1px solid rgba(255, 255, 255, 0.32);
}
.reg-top .auth-lang select { min-height: 32px; padding: 5px 9px; }
.reg-top a {
  color: var(--text-on-dark);
  font-size: 13px;
  font-weight: 600;
  text-decoration: underline;
  text-underline-offset: 3px;
}

.reg-hero { margin-bottom: 88px; color: var(--text-on-dark); }
.reg-hero h1 {
  margin-bottom: 6px;
  color: var(--text-on-dark);
  font-size: clamp(24px, 3vw, 31px);
}
.reg-hero p { margin: 0; max-width: 56ch; font-size: 14px; color: rgba(255, 255, 255, 0.78); }

.reg-section {
  margin: 0 0 16px;
  padding: 20px 22px;
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-lg);
  background: var(--bg-card);
  box-shadow: var(--shadow-card);
}
.reg-section > header { display: flex; align-items: center; gap: 11px; margin-bottom: 16px; }
.reg-section > header h2 { margin: 0; font-size: 16px; }
.reg-section > header .muted { margin: 2px 0 0; font-size: 12px; }
.reg-step {
  display: grid; place-items: center;
  flex: none;
  width: 26px; height: 26px;
  border-radius: 50%;
  background: var(--brand-blue-primary);
  color: var(--text-on-dark);
  font-size: 12px; font-weight: 700;
}
.reg-section[hidden] { display: none; }

.reg-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14px 16px; }
.reg-grid .full { grid-column: 1 / -1; }
.reg-grid label {
  display: block;
  margin-bottom: 6px;
  font-size: 12px; font-weight: 600;
  color: var(--text-secondary);
}
.reg-grid input, .reg-grid select { width: 100%; margin: 0; min-height: 40px; }

.reg-actions {
  display: flex; align-items: center; flex-wrap: wrap; gap: 12px;
  margin-top: 18px;
  padding-top: 16px;
  border-top: 1px solid var(--border-soft);
}
.reg-actions button { margin: 0; }
.reg-actions.plain { margin-top: 14px; padding-top: 0; border-top: none; }

.reg-note {
  margin-bottom: 16px;
  padding: 10px 12px;
  border: 1px dashed var(--border-strong);
  border-radius: var(--radius-sm);
  background: var(--bg-muted);
  font-size: 12px;
  color: var(--text-secondary);
}
.reg-msg { font-size: 12.5px; font-weight: 600; color: var(--accent-red); }
.reg-msg.ok { color: var(--accent-green); }
.reg-check {
  display: flex; align-items: center; gap: 6px;
  font-size: 12.5px; font-weight: 500;
  color: var(--text-secondary);
}
.reg-check input { min-height: auto; margin: 0; }
.reg-code { width: 110px !important; letter-spacing: 3px; font-variant-numeric: tabular-nums; }
.reg-foot { margin-top: 22px; font-size: 11.5px; color: var(--text-muted); text-align: center; }

@media (max-width: 620px) {
  .reg-page { --reg-band: 276px; }
  .reg-grid { grid-template-columns: minmax(0, 1fr); }
  .reg-section { padding: 16px 15px; }
  .reg-top { flex-wrap: wrap; gap: 10px; }
}

/* register / other standalone pages */
.plain-page { max-width: 820px; margin: 0 auto; padding: 28px 20px 56px; }
fieldset {
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-md);
  background: var(--bg-card);
  box-shadow: var(--shadow-card);
  padding: 16px 18px;
  margin: 0 0 16px 0;
}
legend { font-weight: 600; font-size: 13px; color: var(--text-secondary); padding: 0 6px; }

/* ------------------------------------------------------------- motion --- */

@keyframes fadeInUp {
  from { opacity: 0; transform: translateY(12px); }
  to   { opacity: 1; transform: translateY(0); }
}
.animate-page-entry { animation: fadeInUp 350ms var(--ease-out) both; }
/* the auth shells are full-height, so sliding them would push a scrollbar */
@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
.auth-shell.animate-page-entry,
.reg-shell.animate-page-entry { animation-name: fadeIn; }
#main > * { animation: fadeInUp 350ms var(--ease-out) both; }
#main > *:nth-child(1) { animation-delay: 0ms; }
#main > *:nth-child(2) { animation-delay: 40ms; }
#main > *:nth-child(3) { animation-delay: 80ms; }
#main > *:nth-child(4) { animation-delay: 120ms; }
#main > *:nth-child(5) { animation-delay: 160ms; }
#main > *:nth-child(n+6) { animation-delay: 200ms; }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
  button:hover, .actions a:hover, .tile:hover { transform: none; }
}

/* --------------------------------------------------------- responsive --- */

@media (max-width: 900px) {
  #sidebar {
    position: static;
    width: auto;
    border-right: none;
    border-bottom: 1px solid var(--border-soft);
    padding: 14px 16px;
  }
  #sidebar nav {
    flex-direction: row;
    flex-wrap: nowrap;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    -webkit-overflow-scrolling: touch;
    gap: 8px;
    padding-bottom: 4px;
  }
  #sidebar nav a { scroll-snap-align: center; white-space: nowrap; border: 1px solid var(--border-soft); }
  #sidebar nav a.active { border-color: var(--brand-blue-primary); }
  #sidebar .who {
    margin-top: 12px;
    flex-direction: row;
    align-items: center;
    flex-wrap: wrap;
    gap: 10px;
  }
  #sidebar .who select { width: auto; }
  #main { margin-left: 0; padding: 16px; }
  /* .client-area #main is the more specific selector, so its centring gutter
     would beat the 16px shorthand above and widen the phone margin to 32px.
     There is no sidebar and no spare width to give away here, so it comes off. */
  .client-area #main { padding-inline: 16px; }
}

/* ------------------------------------------------- multi-step transfer -- */
/* A transfer is a decision made in stages, so it is presented in stages: the
   step list is the only place the customer can see where they are, and it is
   plain text and rules rather than a progress bar, to match the rest. */
.steps {
  display: flex;
  flex-wrap: wrap;
  gap: 0;
  margin: 0 0 20px;
  padding: 0;
  list-style: none;
  border-bottom: 1px solid var(--border-soft);
}
.steps li {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 0 18px 10px 0;
  margin-inline-end: 18px;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.steps-n {
  display: grid;
  place-items: center;
  width: 20px; height: 20px;
  border: 1px solid var(--border-strong);
  border-radius: 50%;
  font-size: 11px;
  font-variant-numeric: tabular-nums;
}
.steps li.is-current { color: var(--text-primary); }
.steps li.is-current .steps-n {
  background: var(--brand-navy-hero);
  border-color: var(--brand-navy-hero);
  color: var(--text-on-dark);
}
.steps li.is-done { color: var(--text-secondary); }
.steps li.is-done .steps-n { border-color: var(--silver-strong); color: var(--text-secondary); }

/* the two method tiles on step one */
.choice-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 12px; }
.choice {
  display: flex;
  flex-direction: column;
  gap: 6px;
  min-height: 0;
  margin: 0;
  padding: 16px;
  text-align: start;
  background: var(--bg-app);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-md);
  color: var(--text-primary);
}
.choice:hover { border-color: var(--silver-strong); background: var(--bg-muted); }
.choice-title { font-size: 14px; font-weight: 700; }
.choice-desc { font-size: 12.5px; font-weight: 400; color: var(--text-secondary); white-space: normal; }

/* the review and receipt list */
.kv {
  display: grid;
  grid-template-columns: minmax(0, auto) minmax(0, 1fr);
  gap: 0;
  margin: 0 0 16px;
}
.kv dt, .kv dd {
  margin: 0;
  padding: 9px 0;
  border-bottom: 1px solid var(--border-soft);
  font-size: 13px;
}
.kv dt { color: var(--text-secondary); padding-inline-end: 24px; }
.kv dd { text-align: end; }
.kv .kv-strong { font-weight: 700; color: var(--text-primary); }

.step-actions { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; margin-top: 4px; }
.step-actions .btn, .step-actions button { margin: 0; }

@media (max-width: 560px) {
  .steps li { padding-inline-end: 10px; margin-inline-end: 10px; font-size: 11px; }
  .kv { grid-template-columns: minmax(0, 1fr); }
  .kv dt { padding-bottom: 0; border-bottom: 0; }
  .kv dd { text-align: start; padding-top: 2px; }
}

/* ------------------------------------------------------------- offers -- */
/* The five pictures come in at different shapes — a square badge, a 3:2 photo,
   a wide banner — so the card fixes the frame and crops to it. Without that the
   grid's rows tear as each card takes the height its own picture wants. */
.offer-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 16px;
  margin-bottom: 24px;
}
.offer {
  display: flex;
  flex-direction: column;
  padding: 0;
  overflow: hidden;
}
.offer img {
  width: 100%;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  margin: 0;
  border-radius: 0;
  background: var(--bg-muted);
}
.offer-body {
  display: flex;
  flex-direction: column;
  gap: 8px;
  flex: 1;
  padding: 16px;
}
.offer-body h3 { margin: 0; font-size: 15px; letter-spacing: -0.012em; }
.offer-body p { margin: 0; flex: 1; font-size: 13px; color: var(--text-secondary); }
.offer-body button { align-self: flex-start; margin: 6px 0 0; }

/* the same picture again at the top of the application, given more room */
.offer-hero {
  width: 100%;
  max-height: 220px;
  object-fit: cover;
  border-radius: var(--radius-md);
  margin-bottom: 14px;
}
.apply-done-msg { margin: 14px 0 18px; font-size: 14px; max-width: 60ch; }

/* ---------------------------------------------------------------- logo -- */
/* The supplied artwork is padded symmetrically inside its canvas — the crest
   and wordmark occupy 373x295 of a 676x369 PNG — so the box is sized for the
   whole file and the visible mark lands smaller than the box implies. The
   background is genuinely transparent, so it sits straight on the cream. */
.brand-logo-block {
  display: block;
  margin-bottom: 18px;
}
/* Sized for a SQUARE mark. The previous artwork was a 676x369 wordmark, aspect
   1.83, and every number here was chosen against it — including a negative left
   margin that cancelled the wordmark's own generous internal padding. The
   current mark is 256x256 and effectively edge to edge (7px of transparent
   border on a 256px canvas, measured), so those pulls now drag it past the
   edge instead of onto it, and the widths would make the header half as tall
   again.

   The widths below are the OLD RENDERED HEIGHTS: a 176px-wide wordmark stood
   about 96px tall, so a square mark is 88px wide to occupy the same band. That
   keeps every header the height it was designed around. If the mark wants to be
   larger or smaller, these four numbers are the only ones to change. */
.brand-logo {
  display: block;
  width: 100%;
  max-width: 88px;
  height: auto;
  margin: 0 0 2px;
  /* The mark is a square plate of its own teal, not a cut-out. Rounding it
     makes it read as a badge on the cream sidebar; on the teal hero band its
     background is the same colour as the band, so only the key shows. */
  border-radius: var(--radius-md);
}
.brand-logo-block .brand-sub {
  padding-inline-start: 4px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  font-size: 9.5px;
}
/* On the sign-in and registration screens the logo sits on a light surface at
   the top of the page and can afford to be a little larger. */
.auth-top .brand-logo { max-width: 104px; }
@media (max-width: 900px) {
  .brand-logo { max-width: 80px; }
}

/* ==========================================================================
   Sign-in presentation layer
   A deliberately different register from the rest of the product: the app
   inside is restrained navy on cream, this is the shop window. Scoped entirely
   to .auth-page so nothing here reaches the client area or the back office.
   ========================================================================== */

.auth-page {
  background: #F7F8FA;
}

/* The cream halo and paint belong to the old treatment; the scene becomes the
   iridescent field instead. Four soft colour pools rather than one rainbow
   sweep — a single hue rotation reads as a screensaver. */
.auth-page .auth-scene {
  clip-path: none;
  background-image:
    radial-gradient(58% 46% at 76% 26%, rgba(255, 213, 233, 0.55), transparent 68%),
    radial-gradient(52% 42% at 94% 54%, rgba(203, 231, 255, 0.55), transparent 70%),
    radial-gradient(46% 40% at 60% 70%, rgba(212, 253, 233, 0.42), transparent 70%),
    radial-gradient(38% 30% at 86% 84%, rgba(255, 235, 204, 0.48), transparent 70%),
    linear-gradient(180deg, #F9FAFB 0%, #EEF0F4 100%);
  background-color: #F7F8FA;
}
.auth-page .auth-scene::after { background: none; }

/* The rim element is unused on this page, so it carries the light rays that
   fan out of the bottom-left corner instead of adding another wrapper. */
.auth-page .auth-rim {
  display: block;
  inset: auto 0 -6% 0;
  height: 70%;
  clip-path: none;
  pointer-events: none;
  opacity: 0.75;
  background: repeating-linear-gradient(74deg,
    transparent 0 22px,
    rgba(255, 255, 255, 0.85) 22px 27px,
    transparent 27px 58px);
  -webkit-mask-image: radial-gradient(62% 78% at 16% 100%, #000 0%, transparent 72%);
  mask-image: radial-gradient(62% 78% at 16% 100%, #000 0%, transparent 72%);
  filter: blur(7px);
}

/* ---- the arch the photograph stands in ---- */
.aside-stage { position: relative; }
.aside-arch {
  position: absolute;
  /* Flush with the picture horizontally, taller than it at the top. An earlier
     negative side inset made the arch wider — which looked better — but the
     aside sits hard against the right edge of the window, so those few percent
     pushed the document 8px wider than the viewport and the whole page could be
     scrolled sideways. Height is free; width here is not. */
  inset: -10% 0 -3%;
  border-radius: 999px 999px 26px 26px;
  /* Top of the arch is set close to the photograph's own studio grey so its
     background melts into the fill instead of sitting on it as a panel. */
  background: linear-gradient(180deg, #E7E9EB 0%, #F3F4F6 44%, #FAFBFC 100%);
  box-shadow: 0 30px 70px rgba(88, 108, 140, 0.16);
}
/* Iridescent hairline around the arch, drawn as a gradient ring: two masks,
   one clipped to the padding box and one to the border box, excluded from each
   other, which leaves only the 2px edge painted. */
.aside-arch::before {
  content: '';
  position: absolute;
  inset: 0;
  padding: 2px;
  border-radius: inherit;
  background: conic-gradient(from 200deg,
    #FFD9EC, #CFE6FF, #D6FFEA, #FFEBCC, #FFD9EC);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  mask-composite: exclude;
  opacity: 0.85;
}
.aside-stage .aside-photo { position: relative; }

.auth-page .aside-head { color: #16233A; font-size: clamp(18px, 1.5vw, 24px); }
.auth-page .aside-list li { color: #465061; }

/* ---- the sign-in card, frosted ---- */
.auth-page .auth-card {
  border: 1px solid rgba(255, 255, 255, 0.9);
  border-radius: 16px;
  background: linear-gradient(150deg, rgba(255, 255, 255, 0.84), rgba(246, 244, 250, 0.66));
  box-shadow: 0 20px 50px rgba(80, 100, 130, 0.14);
  -webkit-backdrop-filter: blur(18px) saturate(1.25);
  backdrop-filter: blur(18px) saturate(1.25);
}
.auth-page .auth-card h2 { color: #16233A; }
.auth-page .auth-card input[type="email"],
.auth-page .auth-card input[type="password"],
.auth-page .auth-card input[type="text"] {
  border-radius: 9px;
  border-color: rgba(120, 132, 155, 0.35);
  background: rgba(255, 255, 255, 0.7);
}

/* Primary action: a solid navy block, full width, the one dark thing on a pale
   page so there is never a question about where to click. */
.auth-page .auth-card button[type="submit"] {
  width: 100%;
  margin: 4px 0 0;
  padding: 12px 16px;
  border: 0;
  border-radius: 10px;
  background: #16233A;
  color: #F4F5F7;
  font-size: 14px;
}
.auth-page .auth-card button[type="submit"]:hover { background: #22334F; }
.auth-page .auth-card .btn-ghost {
  width: 100%;
  margin: 0;
  border-radius: 10px;
  background: rgba(255, 255, 255, 0.6);
  border-color: rgba(120, 132, 155, 0.35);
}

/* the panel beside the form sits on the same pale field, so it stays plain */
.auth-page .auth-links .creds,
/* Kept identical to .auth-need (see the box rule above); no separate treatment
   on the auth page, so the encrypted note and "What you will need" match. */
.auth-page .auth-secure {
  background: rgba(255, 255, 255, 0.55);
  border-radius: 12px;
}

/* Backstop: body already hides its own horizontal overflow, but the document
   element does not, so anything that does escape still scrolls the page.
   `clip` rather than `hidden` because it does not create a scroll container. */
html:has(body.auth-page) { overflow-x: clip; }

/* -------------------------------------------- application form furniture -- */
/* Two columns on a wide screen, one on a narrow one. A bank application asks a
   lot of short questions, and a single column of them turns every step into a
   scroll. */
.form-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 0 18px;
  margin-bottom: 4px;
}
.form-grid .field-wide { grid-column: 1 / -1; }

/* ---- identity document capture ---- */
.doc-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 16px;
  margin: 14px 0 6px;
}
.doc-slot { display: flex; flex-direction: column; gap: 8px; }
.doc-slot-label {
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-secondary);
}
.doc-drop {
  display: grid;
  place-items: center;
  aspect-ratio: 8 / 5;          /* the shape of a card or a passport page */
  overflow: hidden;
  border: 1px dashed var(--silver-strong);
  border-radius: var(--radius-md);
  background: var(--bg-muted);
  cursor: pointer;
}
.doc-drop:hover { border-color: var(--brand-blue-primary); }
.doc-preview { width: 100%; height: 100%; object-fit: cover; }
.doc-hint { font-size: 12.5px; color: var(--text-secondary); }
.doc-slot .btn-ghost { align-self: flex-start; margin: 0; }

/* ---- agreement and signature ---- */
.agreement-box {
  max-height: 240px;
  overflow-y: auto;
  padding: 16px 18px;
  margin-bottom: 14px;
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-md);
  background: var(--bg-app);
}
.agreement-box h4 { margin: 0 0 10px; font-size: 13px; }
.agreement-box p {
  margin: 0 0 10px;
  font-size: 12.5px;
  line-height: 1.55;
  color: var(--text-secondary);
  max-width: 78ch;
}
.sign-wrap { position: relative; margin-bottom: 10px; }
.sign-pad {
  display: block;
  width: 100%;
  max-width: 560px;
  aspect-ratio: 3 / 1;
  border: 1px solid var(--silver-strong);
  border-radius: var(--radius-md);
  background: #FFFFFF;
  /* Without this a drag on a touch screen scrolls the page instead of drawing. */
  touch-action: none;
  cursor: crosshair;
}
.sign-baseline {
  position: absolute;
  left: 24px;
  width: min(512px, calc(100% - 48px));
  bottom: 22%;
  border-bottom: 1px solid var(--border-strong);
  pointer-events: none;
}

/* ==================================================================== chat */
/* Two panes filling the height the shell gives them: conversations on the
   left, the open one on the right. The message list is the only thing that
   scrolls, so the composer stays put while the history moves under it. */
.chat {
  display: grid;
  grid-template-columns: minmax(0, 320px) minmax(0, 1fr);
  gap: 16px;
  /* the shell's own padding is 28px top and 56px bottom */
  height: calc(100vh - 84px - 74px);
  min-height: 460px;
}

.chat-list, .chat-pane {
  display: flex;
  flex-direction: column;
  min-height: 0;              /* lets the inner scroller actually scroll */
  overflow: hidden;
  background: var(--bg-card);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-md);
}

.chat-list-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 14px 14px 12px;
  border-bottom: 1px solid var(--border-soft);
}
.chat-list-head h3 {
  margin: 0;
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--text-secondary);
}
.chat-list-head button { margin: 0; padding: 6px 10px; min-height: 30px; font-size: 12px; }

.chat-threads { flex: 1; min-height: 0; overflow-y: auto; padding: 8px; }
.chat-none { padding: 16px 8px; font-size: 13px; color: var(--text-secondary); }

.chat-thread {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  margin: 0 0 4px;
  padding: 10px;
  text-align: start;
  background: none;
  border: 1px solid transparent;
  border-radius: var(--radius-md);
  cursor: pointer;
}
.chat-thread:hover { background: var(--bg-muted); border-color: var(--border-soft); }
.chat-thread.is-active { background: var(--bg-muted); border-color: var(--silver-strong); }
.chat-thread-main { flex: 1; min-width: 0; }
.chat-thread-top { display: flex; justify-content: space-between; gap: 8px; align-items: baseline; }
.chat-thread-top b { font-size: 13px; font-weight: 600; }
.chat-thread-top span { flex: none; font-size: 11px; color: var(--text-muted); font-variant-numeric: tabular-nums; }
.chat-thread-preview {
  margin-top: 2px;
  font-size: 12px;
  color: var(--text-secondary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.chat-unread {
  flex: none;
  display: grid;
  place-items: center;
  min-width: 18px; height: 18px;
  padding: 0 5px;
  border-radius: 999px;
  background: var(--brand-blue-primary);
  color: var(--text-on-dark);
  font-size: 11px;
  font-weight: 700;
}

/* ---- the open conversation ---- */
.chat-pane { position: relative; }
.chat-empty, .chat-new, .chat-open { display: flex; flex-direction: column; flex: 1; min-height: 0; }
.chat-empty { align-items: center; justify-content: center; color: var(--text-secondary); font-size: 13px; }
.chat-new-body { padding: 16px; overflow-y: auto; }
.chat-new-body textarea { width: 100%; }

.chat-head {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 12px 14px;
  border-bottom: 1px solid var(--border-soft);
}
.chat-head-main { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.chat-head-main b { font-size: 14px; }
.chat-head-sub { font-size: 12px; color: var(--text-secondary); }
.chat-back { display: none; margin: 0; padding: 4px 8px; min-height: 0; }

.chat-avatar {
  flex: none;
  width: 38px; height: 38px;
  border-radius: 50%;
  object-fit: cover;
  background: var(--bg-muted);
}
.chat-avatar.sm { width: 30px; height: 30px; }
.chat-avatar.is-placeholder { border: 1px dashed var(--border-strong); }

.chat-scroll {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  padding: 16px 14px;
  background: var(--bg-app);
}
.chat-day {
  margin: 6px 0 14px;
  text-align: center;
  font-size: 11px;
  letter-spacing: 0.06em;
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}

.chat-msg { display: flex; align-items: flex-end; gap: 8px; margin-bottom: 12px; }
.chat-msg.is-mine { flex-direction: row-reverse; }
.chat-bubble {
  max-width: min(72%, 62ch);
  padding: 9px 12px 7px;
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-md);
  background: var(--bg-card);
}
.chat-msg.is-mine .chat-bubble {
  background: var(--brand-navy-hero);
  border-color: var(--brand-navy-hero);
  color: var(--text-on-dark);
}
.chat-who { font-size: 11px; font-weight: 700; margin-bottom: 3px; color: var(--text-secondary); }
.chat-msg.is-mine .chat-who { color: rgba(244, 243, 240, 0.72); }
.chat-text { font-size: 13.5px; line-height: 1.5; white-space: pre-wrap; overflow-wrap: anywhere; }
.chat-time { margin-top: 4px; font-size: 10.5px; color: var(--text-muted); text-align: end; font-variant-numeric: tabular-nums; }
.chat-msg.is-mine .chat-time { color: rgba(244, 243, 240, 0.6); }

/* a file inside a bubble */
.chat-file {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  margin: 6px 0 0;
  padding: 7px 9px;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  background: var(--bg-app);
  color: var(--text-primary);
  font-size: 12px;
  text-align: start;
  cursor: pointer;
}
.chat-file:hover { border-color: var(--brand-blue-primary); background: var(--bg-muted); }
.chat-file span:nth-child(2) { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.chat-file span:last-child { flex: none; color: var(--text-muted); font-variant-numeric: tabular-nums; }

/* ---- composer ---- */
.chat-composer { border-top: 1px solid var(--border-soft); padding: 10px 12px 12px; }
.chat-composer-row { display: flex; align-items: flex-end; gap: 8px; }
.chat-composer-row textarea {
  flex: 1;
  min-height: 38px;
  max-height: 160px;
  margin: 0;
  resize: none;
  line-height: 1.45;
}
.chat-composer-row .btn-primary { margin: 0; }
.chat-clip {
  flex: none;
  margin: 0;
  padding: 0;
  width: 38px;
  min-height: 38px;
  font-size: 16px;
  line-height: 1;
}
.chat-attach-row { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 8px; }
.chat-pending {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 4px 6px 4px 10px;
  border: 1px solid var(--border-strong);
  border-radius: 999px;
  background: var(--bg-muted);
  font-size: 11.5px;
}
.chat-pending span:last-of-type { color: var(--text-muted); font-variant-numeric: tabular-nums; }
.chat-pending-x {
  margin: 0; padding: 0;
  width: 18px; min-height: 18px;
  border: 0; border-radius: 50%;
  background: none;
  font-size: 14px; line-height: 1;
  color: var(--text-secondary);
}
.chat-pending-x:hover { background: var(--border-strong); color: var(--text-primary); }
.chat-closed-note {
  padding: 12px 14px;
  border-top: 1px solid var(--border-soft);
  font-size: 12.5px;
  color: var(--text-secondary);
}

/* One pane at a time on a phone: the list until something is opened, then the
   conversation, with the arrow in its header going back. */
@media (max-width: 860px) {
  .chat {
    grid-template-columns: minmax(0, 1fr);
    height: auto;
    min-height: 0;
  }
  .chat-list { max-height: 60vh; }
  .chat-pane { min-height: 62vh; }
  .chat.is-open .chat-list { display: none; }
  .chat:not(.is-open) .chat-pane { display: none; }
  .chat-back { display: inline-block; }
  .chat-bubble { max-width: 86%; }
}

/* ------------------------------------------------- sign-in on a phone ---- */
@media (max-width: 900px) {
  /* The crest sat across her face. Smaller, and pulled hard left — the artwork
     occupies only the middle 55% of its PNG (151px of transparent padding each
     side of 676), so a plain `margin-left: 0` still leaves the visible mark
     floating inward. The negative margin is that padding, scaled. */
  .auth-top .brand {
    /* without this the header's flex squeezes the logo to whatever the language
       picker leaves over, and the mark shrinks below legibility */
    flex: none;
  }
  .auth-top .brand-logo {
    width: 68px;
    max-width: none;
    /* was -28px, cancelling the old wordmark's internal padding; the square
       mark has none to cancel */
    margin-inline-start: 0;
    margin-bottom: 0;
  }

  /* The greeting and the heading were navy text lying over her hair, which is
     close to unreadable. They join the sign-in card instead.

     They are siblings of the card, not children of it, so rather than moving
     them in the markup the two are drawn as one surface: the welcome block
     takes the top corners and border, the card gives them up. Their side
     padding has to match the card's or the seam shows. */
  .auth-page .auth-welcome {
    margin: 0;
    padding: 22px 26px 0;
    border: 1px solid rgba(255, 255, 255, 0.9);
    border-bottom: 0;
    border-radius: 16px 16px 0 0;
    background: linear-gradient(150deg, rgba(255, 255, 255, 0.84), rgba(246, 244, 250, 0.66));
    -webkit-backdrop-filter: blur(18px) saturate(1.25);
    backdrop-filter: blur(18px) saturate(1.25);
  }
  .auth-page .auth-welcome h1 { font-size: 22px; }
  .auth-page .auth-cols { margin-top: 0; }
  .auth-page .auth-card {
    border-top: 0;
    border-start-start-radius: 0;
    border-start-end-radius: 0;
    padding-top: 18px;
  }
}

/* ---- restricted account ----------------------------------------------------
   Shown on Cards, Loans and Investments while a registration is still waiting
   to be reviewed. It states account state rather than reporting an error, so
   it is amber and sits at the top of the section instead of beside a control.
   role="status" rather than "alert": nothing the customer just did caused it. */
.restricted-note {
  display: flex;
  gap: 12px;
  align-items: flex-start;
  margin: 0 0 22px;
  padding: 14px 16px;
  background: var(--bg-card);
  border: 1px solid var(--border-strong);
  border-left: 4px solid var(--accent-amber);
  border-radius: var(--radius-md);
}
.restricted-mark {
  flex: none;
  width: 20px; height: 20px; margin-top: 1px;
  border-radius: 50%;
  background: var(--accent-amber);
  color: var(--bg-card);
  font-size: 13px; font-weight: 700; line-height: 20px;
  text-align: center;
}
.restricted-text { min-width: 0; }
.restricted-title {
  font-size: 14px; font-weight: 600;
  color: var(--text-primary);
}
.restricted-detail {
  margin-top: 4px;
  font-size: 13px; line-height: 1.5;
  color: var(--text-secondary);
}

/* A locked control stays visible so the section reads as closed rather than
   empty, but it takes no clicks and no longer invites one. */
.is-locked,
.is-locked:hover {
  opacity: .5;
  cursor: not-allowed;
  border-color: var(--border-soft);
  background: var(--bg-muted);
  color: var(--text-muted);
}

/* ---- back office: chat reply --------------------------------------------
   Stacked rather than laid out as a row: the reply is the wide element here
   and the buttons sit under it, so a long message stays fully readable. */
.bo-reply { display: flex; flex-direction: column; gap: 10px; }
.bo-reply textarea {
  width: 100%;
  margin: 0;
  min-height: 96px;
  max-height: 420px;
  resize: vertical;
  line-height: 1.5;
}
.bo-reply-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
}
.bo-reply-actions button { margin: 0; min-height: 38px; }

/* ---- transfers held for review ------------------------------------------
   Amber, like every other "waiting on someone" state in here: the money has
   left but has not arrived, which is neither a success nor a failure. */
.pill.in_review { background: #FFFBEB; border-color: #FDE68A; color: #B45309; }
.pill.approved { background: #ECFDF5; border-color: #A7F3D0; color: #047857; }

#pendingList .feed-item { align-items: flex-start; }
#pendingList .pill { margin-left: 6px; }
.pending-sub {
  margin-top: 2px;
  font-size: 12px;
  color: var(--text-muted);
}

/* The beneficiary bank details stacked into one cell of the review queue —
   four columns of mostly-empty address would push the table off the page. */
.bo-bank-cell { font-size: 12px; line-height: 1.45; color: var(--text-secondary); }
.bo-bank-cell div:first-child { font-weight: 600; color: var(--text-primary); }
.bo-sub { font-size: 12px; color: var(--text-muted); }

/* ---- deposits ------------------------------------------------------------
   The details and the QR sit side by side where there is room and stack when
   there is not; the code keeps a fixed size either way, because a QR scaled
   down past its module size stops being scannable. */
.deposit-body {
  display: flex;
  flex-wrap: wrap;
  gap: 24px;
  align-items: flex-start;
}
.deposit-body .kv { flex: 1 1 320px; min-width: 0; margin: 0; }
.deposit-qr {
  flex: none;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  padding: 12px;
  background: #FFFFFF;
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-md);
}
/* white behind the modules regardless of the surrounding surface, and never
   smaller than the scanners can resolve */
.deposit-qr img { display: block; width: 200px; height: 200px; background: #FFFFFF; }
.deposit-qr-cap { font-size: 12px; color: var(--text-muted); }

/* An IBAN or a wallet address is read a character at a time when it is checked,
   so it gets a monospaced face and is allowed to wrap anywhere. */
.mono-value {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 13px;
  word-break: break-all;
}
.copy-btn {
  margin: 0 0 0 10px;
  padding: 2px 10px;
  min-height: 0;
  font-size: 12px;
  vertical-align: middle;
}
.kv-hint { font-size: 12px; color: var(--text-muted); }

/* ---- sending to a wallet -------------------------------------------------
   Coin sent to a wrong address is gone, so the warning sits above the field
   rather than below it, where it would be read only after the mistake. */
.wallet-warning {
  margin: 0 0 14px;
  padding: 10px 12px;
  background: var(--bg-card);
  border: 1px solid var(--border-strong);
  border-left: 4px solid var(--accent-amber);
  border-radius: var(--radius-md);
  font-size: 13px;
  line-height: 1.5;
  color: var(--text-secondary);
}
.wallet-row { display: flex; gap: 8px; align-items: stretch; }
.wallet-row input {
  flex: 1;
  min-width: 0;
  margin: 0;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 13px;
}
.wallet-row button { flex: none; margin: 0; }
.wallet-row button:disabled { opacity: .5; cursor: not-allowed; }

/* The camera view. Fixed over everything, because a half-visible viewfinder
   behind the page is worse than useless for lining up a code. */
.scan-overlay {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
  background: rgba(11, 22, 38, 0.82);
}
.scan-box {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  width: min(420px, 100%);
  padding: 18px;
  background: var(--bg-card);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-float);
  text-align: center;
}
.scan-box p { margin: 0; font-size: 14px; color: var(--text-secondary); }
.scan-box video {
  width: 100%;
  aspect-ratio: 1;
  object-fit: cover;
  background: #000;
  border-radius: var(--radius-md);
}
.scan-box button { margin: 0; }

/* ==========================================================================
   Client patterns lifted from the reference screenshots — hero band, account
   tile strip, quick-action discs, merchant transaction rows, contact card,
   status pills, sheet modal, legal footer.

   These are the *features* of that reference, not its styling. The register
   stays the one settled on 27 Aug: flat surfaces, 4px radii, no card shadows,
   no hover lift, cream and navy, silver rules. Where the reference floats a
   white card on a shadow, this separates with a 1px silver rule instead.
   ========================================================================== */

/* Gold, from the crest. 6.54:1 on --brand-navy-hero, so it may carry text on
   navy — but only 1.9:1 on the cream page, so on light surfaces it is a rule
   or a marker and never a letter. */
:root {
  --gold: #C9A227;
  --gold-dim: rgba(201, 162, 39, 0.35);
}

/* ------------------------------------------------------- page hero band -- */
/* Same construction as the sign-in scene: a painted sky, the photograph
   clipped to a wedge on the trailing edge, a lit rim along the cut. Reduced
   to a band, and re-declared locally because the sign-in values are scoped to
   .auth-page. */
/* The band across the top of every client and back office page.

   It carries a panoramic photograph chosen for the visitor's own part of the
   day — set by data-tod on <body> from the server's instant read in the
   browser's timezone. The sign in and registration pages are deliberately NOT
   this component: they keep their own single photograph, scoped to .auth-page.

   The photographs are ~2900x330 banners, so unlike the portrait source this
   band was first built for they span it end to end rather than being cropped
   into a diagonal wedge on the right. */
.page-hero {
  --cut-top: 62%;
  --cut-bottom: 40%;
  --scene-photo: url("/img/hero/morning.jpg?v=202611041609");
  --scene-paint: linear-gradient(180deg, #BFDCEF 0%, #D8E7F2 38%, #E7E2D6 66%, #CBBEAA 100%);
  position: relative;
  overflow: hidden;
  margin-bottom: 18px;
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-md);
  background: linear-gradient(155deg, #04182E 0%, #0A2540 52%, #0E3A63 100%);
  color: var(--text-on-dark);
}
/* No clip-path: a panorama fills the band. The diagonal cut existed to let a
   portrait photograph occupy only the right-hand end. */
.page-hero-scene {
  position: absolute;
  inset: 0;
  background-image: var(--scene-paint);
  background-size: cover;
  background-position: 50% 62%;
}
.page-hero-photo {
  position: absolute;
  inset: 0;
  background-image: var(--scene-photo);
  background-repeat: no-repeat;
  background-position: 50% 50%;
  background-size: cover;
}
.page-hero-scene::after {
  content: "";
  position: absolute;
  inset: 0;
  /* The scrim. It paints after .page-hero-photo inside the same box, so it
     covers the photograph and keeps the heading legible whatever the picture
     is doing behind it — a bright noon shot and a dark night one both end up
     readable. Carried further across than before, because the photograph now
     spans the whole band rather than only its right-hand end. */
  background:
    linear-gradient(100deg, rgba(4, 24, 46, 0.94) 0%, rgba(10, 37, 64, 0.74) 34%, rgba(10, 37, 64, 0.18) 68%, rgba(10, 37, 64, 0.08) 100%),
    linear-gradient(180deg, rgba(4, 24, 46, 0.3) 0%, rgba(4, 24, 46, 0.05) 45%, rgba(4, 24, 46, 0.45) 100%);
}
/* Mirrored right-to-left so the text still sits over the dark end. Flipping a
   landscape costs nothing; flipping a portrait of a person would not. */
[dir="rtl"] .page-hero-scene { transform: scaleX(-1); }
/* The rim drew the lit edge of the diagonal cut. There is no diagonal any
   more, so it draws nothing — kept as an empty box rather than removed from
   pageHero(), which both shells call. */
.page-hero-rim { display: none; }
/* One photograph per part of the visitor's own day. Scoped to .page-hero so it
   cannot reach the sign in and registration pages, which keep their own single
   picture under .auth-page. The default above is the morning one, so a page
   that somehow renders before data-tod is set shows a photograph rather than
   an empty band. */
body[data-tod="morning"] .page-hero { --scene-photo: url("/img/hero/morning.jpg?v=202611041609"); }
body[data-tod="afternoon"] .page-hero { --scene-photo: url("/img/hero/afternoon.jpg?v=202611041609"); }
body[data-tod="evening"] .page-hero { --scene-photo: url("/img/hero/evening.jpg?v=202611041609"); }
body[data-tod="night"] .page-hero { --scene-photo: url("/img/hero/night.jpg?v=202611041609"); }

.page-hero-body {
  position: relative;
  z-index: 2;
  padding: 26px 28px;
  max-width: 56%;
}
.page-hero-body h2 {
  margin: 0 0 3px;
  color: var(--text-on-dark);
  font-size: 24px;
  letter-spacing: -0.4px;
}
.page-hero-eyebrow {
  margin: 0 0 10px;
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 1.3px;
  text-transform: uppercase;
  color: var(--gold);
}
.page-hero-sub { margin: 0; font-size: 12.5px; color: rgba(244, 243, 240, 0.72); }

/* A .dash-head promoted into the band by renderShell keeps its own markup, so
   its heading and muted line are re-coloured for the navy rather than rebuilt. */
.page-hero-body .dash-head { margin-bottom: 0; }
.page-hero-body .dash-head h2 {
  margin: 0 0 3px;
  color: var(--text-on-dark);
  font-size: 24px;
  letter-spacing: -0.4px;
}
.page-hero-body .muted,
.page-hero-body .dash-head p { color: rgba(244, 243, 240, 0.72); }

@media (max-width: 900px) {
  .page-hero { --cut-top: 84%; --cut-bottom: 68%; }
  .page-hero-body { max-width: 100%; padding: 20px; }
  .page-hero-body h2 { font-size: 20px; }
}

/* -------------------------------------------------- account tile strip -- */
/* The reference floats separate filled cards. Here they are one strip divided
   by hairlines: the gap is the container's own colour showing through, so no
   shadow is needed to keep the tiles apart. */
/* The number of accounts varies a lot — two on one customer, eight on another —
   so the strip hugs its tiles instead of dividing the full width between them.
   Stretched to 1fr, two accounts became two 639px slabs of empty navy. Tiles
   keep a fixed footing and wrap onto further rows once they run out of room. */
.tile-strip {
  display: flex;
  flex-wrap: wrap;
  gap: 3px;
  margin-bottom: 18px;
}
.acct-tile {
  display: block;
  flex: 0 0 auto;
  min-width: 210px;
  padding: 13px 15px 14px;
  border: 0;
  /* Each tile carries its own 4px corner. An earlier version divided one
     navy block with 1px gaps, which looked right until a ragged last row left
     a wide band of the divider colour showing beside the final tile. */
  border-radius: var(--radius-md);
  font: inherit;
  text-align: start;
  text-decoration: none;
  background: var(--brand-navy-hero);
  color: var(--text-on-dark);
  cursor: pointer;
  transition: background 120ms var(--ease-out);
}
.acct-tile:hover { background: var(--brand-blue-hover); text-decoration: none; }
/* The selected account is marked with a gold rule inset along the bottom
   rather than a raised card, which is how the rest of this interface signals
   the current item. */
.acct-tile[aria-current="true"] {
  background: var(--brand-blue-hover);
  box-shadow: inset 0 -3px 0 var(--gold);
}
.acct-tile-name {
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: 0.3px;
  color: rgba(244, 243, 240, 0.78);
}
.acct-tile-bal {
  margin-top: 5px;
  font-size: 19px;
  font-weight: 700;
  line-height: 1.15;
  letter-spacing: -0.3px;
  font-variant-numeric: tabular-nums;
}
.acct-tile-cur { font-size: 11px; font-weight: 600; margin-inline-start: 4px; color: rgba(244, 243, 240, 0.7); }
.acct-tile-foot {
  margin-top: 3px;
  font-size: 10.5px;
  letter-spacing: 0.4px;
  text-transform: uppercase;
  color: rgba(244, 243, 240, 0.55);
}

/* ------------------------------------------------ quick-action discs ---- */
.qa-row {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 20px;
  margin-bottom: 22px;
}
.qa {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 7px;
  width: 76px;
  text-decoration: none;
  color: var(--text-secondary);
}
.qa:hover { text-decoration: none; color: var(--text-primary); }
.qa-disc {
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  border: 1px solid var(--silver-strong);
  border-radius: var(--radius-pill);
  background: var(--bg-card);
  color: var(--brand-blue-primary);
  transition: background 120ms var(--ease-out), color 120ms var(--ease-out), border-color 120ms var(--ease-out);
}
.qa:hover .qa-disc {
  background: var(--brand-navy-hero);
  border-color: var(--brand-navy-hero);
  color: var(--text-on-dark);
}
.qa:focus-visible { outline: none; }
.qa:focus-visible .qa-disc { outline: 2px solid var(--brand-blue-primary); outline-offset: 2px; }
.qa-label { font-size: 11.5px; font-weight: 600; text-align: center; line-height: 1.25; }

/* -------------------------------------------- merchant transaction rows -- */
/* The reference lists transactions as merchant rows rather than as a
   four-column table. Kept as rows here, but the amount stays tabular so the
   column still reads down the page. */
.txlist { display: flex; flex-direction: column; }
.tx-row {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: baseline;
  gap: 2px 16px;
  padding: 10px 0;
  border-bottom: 1px solid var(--border-soft);
  text-decoration: none;
  color: inherit;
}
.tx-row:last-child { border-bottom: 0; }
a.tx-row:hover { text-decoration: none; background: var(--bg-muted); box-shadow: 0 0 0 6px var(--bg-muted); }
.tx-name { font-size: 13px; font-weight: 600; }
.tx-meta { grid-column: 1; font-size: 11.5px; color: var(--text-muted); font-variant-numeric: tabular-nums; }
.tx-amt {
  grid-row: 1 / span 2;
  grid-column: 2;
  align-self: center;
  font-size: 13.5px;
  font-weight: 700;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.tx-amt.credit { color: var(--accent-green); }
.tx-empty { padding: 12px 0; color: var(--text-muted); }

/* A transaction row that opens something. Reset to look like the rest of the
   list rather than like a button, since what it is is a row. */
.pending-row {
  width: 100%;
  font: inherit;
  text-align: start;
  background: none;
  border-width: 0 0 1px 0;
  border-radius: 0;
  cursor: pointer;
}
.pending-row:hover { background: var(--bg-muted); box-shadow: 0 0 0 6px var(--bg-muted); }
.pending-row:focus-visible { outline: 2px solid var(--brand-blue-primary); outline-offset: 2px; }
.pending-row .tx-name { display: flex; align-items: center; gap: 7px; flex-wrap: wrap; }

/* Search sitting in a section head, as the reference puts it above its
   transaction list. .sec-head is baseline-aligned with its rule hung off
   ::after, so the tools ride in their own box rather than on the heading. */
.sec-head .sec-tools { margin-inline-start: auto; display: flex; align-items: center; gap: 8px; }
.sec-search {
  width: min(200px, 42vw);
  padding: 5px 9px;
  font: inherit;
  font-size: 12px;
  color: var(--text-primary);
  background: var(--bg-card);
  border: 1px solid var(--silver-strong);
  border-radius: var(--radius-sm);
}
.sec-search:focus { outline: 2px solid var(--brand-blue-primary); outline-offset: 1px; border-color: var(--brand-blue-primary); }

/* ------------------------------------------------------- contact card ---- */
.contact-row {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1px;
  background: var(--border-soft);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-sm);
  overflow: hidden;
}
.contact-act {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 5px;
  padding: 12px 6px;
  background: var(--bg-card);
  color: var(--text-secondary);
  font-size: 11.5px;
  font-weight: 600;
  text-decoration: none;
}
.contact-act:hover { background: var(--bg-muted); color: var(--text-primary); text-decoration: none; }
.contact-act svg { color: var(--brand-blue-primary); }

/* One person you can reach, with the ways to reach them beneath. */
.contact-block { margin-bottom: 14px; }
.contact-who {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 8px;
  font-size: 13px;
  font-weight: 600;
}
.contact-role { font-size: 11.5px; font-weight: 500; color: var(--text-muted); }
/* An email address is long and must not be truncated into uselessness, so the
   cell that carries one is allowed to wrap. */
.contact-act { word-break: break-word; text-align: center; }

/* A row whose right-hand cell holds a control rather than an amount. */
.passkey-row .tx-amt { align-self: center; }

/* ----------------------------------------------------- status pills ------ */
/* Extends the existing set with the states the reference shows on batches and
   on remote deposits. The leading dot is what carries the state for anyone who
   cannot separate the tints. */
.pill.processing, .pill.initiated { background: #FFFBEB; border-color: #FDE68A; color: #8A5A10; }
.pill.accepted, .pill.processed, .pill.ready { background: #ECFDF5; border-color: #A7F3D0; color: #1B6B4A; }
.pill.dot::before {
  content: "";
  display: inline-block;
  width: 5px;
  height: 5px;
  margin-inline-end: 5px;
  border-radius: var(--radius-pill);
  background: currentColor;
  vertical-align: 1px;
}

/* --------------------------------------------------------- sheet modal --- */
/* The reference's centred panel: back chevron, title over a subtitle, a
   summary row of counts, then the rows themselves and dot pagination.
   --shadow-float is the one elevation token this design kept, and it exists
   precisely for things that genuinely float over the page. */
.sheet-scrim {
  position: fixed;
  inset: 0;
  z-index: 90;
  display: grid;
  place-items: center;
  padding: 20px;
  background: rgba(11, 22, 38, 0.42);
}
.sheet {
  width: min(540px, 100%);
  max-height: min(680px, 88vh);
  display: flex;
  flex-direction: column;
  background: var(--bg-card);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-float);
  overflow: hidden;
}
.sheet-head {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: 10px;
  padding: 14px 16px;
  border-bottom: 1px solid var(--border-soft);
}
.sheet-title { text-align: center; }
.sheet-title strong { display: block; font-size: 14px; }
.sheet-title span { display: block; font-size: 11.5px; color: var(--text-muted); }
.sheet-icon {
  display: grid;
  place-items: center;
  width: 30px;
  height: 30px;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  background: none;
  color: var(--text-secondary);
  cursor: pointer;
}
.sheet-icon:hover { background: var(--bg-muted); color: var(--text-primary); }
.sheet-stats {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1px;
  background: var(--border-soft);
  border-bottom: 1px solid var(--border-soft);
}
/* The same summary figures outside a sheet — a statement's opening and closing
   balances, a loan's terms. Wraps rather than forcing three across, because a
   statement has six of them and a phone has room for one. */
.stat-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(148px, 1fr));
  gap: 1px;
  margin-bottom: 16px;
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-md);
  background: var(--border-soft);
  overflow: hidden;
}
.stat { padding: 12px 14px; background: var(--bg-card); }
.stat-label {
  display: flex;
  align-items: center;
  gap: 5px;
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.9px;
  text-transform: uppercase;
  color: var(--text-muted);
}
.stat-value {
  margin-top: 4px;
  font-size: 18px;
  font-weight: 700;
  letter-spacing: -0.3px;
  font-variant-numeric: tabular-nums;
}
.sheet-body { overflow-y: auto; padding: 0 16px; }
/* Actions that act on whatever the sheet is showing — repaying the loan you
   just opened, for instance. Kept with the thing they act on, so the amount
   typed can never belong to a different row. */
.sheet-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  margin: 14px 0 16px;
  padding-top: 14px;
  border-top: 1px solid var(--border-soft);
}
.sheet-actions input { width: 130px; }
.sheet-actions .reg-msg { flex-basis: 100%; }
.sheet-foot {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  padding: 10px 12px;
  border-top: 1px solid var(--border-soft);
}
.sheet-dots { display: flex; align-items: center; gap: 7px; }
/* Replaces the dots once there are too many to read. Tabular so the width
   does not jump as the page number changes. */
.sheet-count {
  min-width: 62px;
  text-align: center;
  font-size: 12px;
  font-weight: 600;
  color: var(--text-secondary);
  font-variant-numeric: tabular-nums;
}
.sheet-foot .sheet-icon:disabled {
  opacity: 0.32;
  cursor: default;
}
.sheet-foot .sheet-icon:disabled:hover { background: none; color: var(--text-secondary); }
.sheet-dot {
  width: 7px;
  height: 7px;
  padding: 0;
  border: 0;
  border-radius: var(--radius-pill);
  background: var(--border-strong);
  cursor: pointer;
}
.sheet-dot[aria-current="true"] { background: var(--brand-blue-primary); }

/* An account that is frozen or closed still appears in the strip, so this
   says so in words rather than leaving it to the absence of something. */
.acct-warn {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: -6px 0 18px;
  padding: 9px 12px;
  border: 1px solid var(--border-strong);
  border-inline-start: 3px solid var(--accent-amber);
  border-radius: var(--radius-sm);
  background: var(--bg-card);
  font-size: 12.5px;
  color: var(--text-secondary);
  font-variant-numeric: tabular-nums;
}

/* A field that wants the whole row of its .apply-card — a description, an
   instruction, anything where the value is long and the box should be too.
   Replaces `style="flex: 1 1 100%"` written onto individual fields. */
.field.wide-field { flex: 1 1 100%; }

/* A queue on the back office dashboard: the same disc as a client quick
   action, with the number of things waiting on it. */
.queue-link { position: relative; }
.queue-count {
  position: absolute;
  top: -5px;
  inset-inline-end: -5px;
  min-width: 19px;
  height: 19px;
  padding: 0 5px;
  border-radius: var(--radius-pill);
  background: var(--accent-red);
  color: #FBFBF9;
  font-size: 11px;
  font-weight: 700;
  line-height: 19px;
  text-align: center;
  font-variant-numeric: tabular-nums;
}
/* An empty queue stays on screen, dimmed. Hiding it would leave staff unsure
   whether it was empty or simply not checked. */
.queue-link.is-empty { opacity: 0.45; }
.queue-link.is-empty:hover { opacity: 1; }

/* Each investment account is its own block. It used to be separated from the
   next by an <hr>; the panel border already does that job. */
.invacct { margin-bottom: 16px; }
.invacct .sec-head { margin-top: 18px; }
.invacct .sec-head:first-child { margin-top: 0; }
.invacct-foot { margin-top: 14px; }
/* The asset mark sits inside the row heading, so it needs to line up with the
   text beside it rather than sit on the baseline. */
.asset-row .tx-name, .pending-row .tx-name { display: flex; align-items: center; gap: 7px; }

/* Which account and which period the figures below belong to. */
.stmt-period {
  margin: 0 0 12px;
  font-size: 13px;
  font-weight: 600;
  color: var(--text-secondary);
  font-variant-numeric: tabular-nums;
}

/* ------------------------------------------------------- legal footer ---- */
.site-foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px 16px;
  margin-top: 28px;
  padding: 14px 18px;
  border-radius: var(--radius-md);
  background: var(--brand-navy-hero);
  color: rgba(244, 243, 240, 0.68);
  font-size: 11.5px;
}
.site-foot a { color: rgba(244, 243, 240, 0.86); }
.site-foot a:hover { color: var(--text-on-dark); }
.site-foot-sep { color: rgba(244, 243, 240, 0.3); }

/* --------------------------------------------- sidebar icons and avatar -- */
#sidebar nav a { display: flex; align-items: center; gap: 9px; }
#sidebar nav a svg { flex: none; opacity: 0.72; }
#sidebar nav a.active svg { opacity: 1; }
#sidebar .who-id { display: flex; align-items: center; gap: 9px; margin-bottom: 9px; }
#sidebar .who-id .who-name { font-weight: 600; color: var(--text-primary); }
#sidebar .who-id .who-mail {
  font-size: 11px;
  color: var(--text-muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.avatar-disc {
  display: grid;
  place-items: center;
  flex: none;
  width: 32px;
  height: 32px;
  border-radius: var(--radius-pill);
  background: var(--brand-navy-hero);
  color: var(--gold);
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: 0.4px;
}

/* The login logo links to the public site. Keep it looking like a logo, not a
   text link: no underline, inherited colour, sub-label unaffected on hover. */
a.brand-logo-block, a.brand-logo-block:hover { text-decoration: none; color: inherit; }
a.brand-logo-block .brand-sub { text-decoration: none; }

/* Transfer form: a fixed label column so every control lines up down the form,
   whichever method is chosen. Each .field was its own inline row before, so
   labels of different widths pushed the inputs to different left edges. */
#detailsForm .field {
  display: grid;
  grid-template-columns: 160px minmax(0, 1fr);
  align-items: center;
  gap: 8px 12px;
  margin-bottom: 12px;
  max-width: 560px;
}
#detailsForm .field > label { grid-column: 1; margin: 0; justify-self: start; }
#detailsForm .field > :not(label) { grid-column: 2; width: 100%; margin: 0; }
@media (max-width: 560px) {
  #detailsForm .field { grid-template-columns: 1fr; }
  #detailsForm .field > label { grid-column: 1; }
  #detailsForm .field > :not(label) { grid-column: 1; }
}

/* Staff appear to customers as the bank, not as an individual employee: a navy
   "BI" badge and the name "St. Aldric" stand in for the agent. */
.chat-avatar.chat-bank {
  display: grid;
  place-items: center;
  background: var(--brand-navy-hero);
  color: var(--text-on-dark);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.02em;
}

/* ---------------------------------------------------------------------------
   Identity documents
   ---------------------------------------------------------------------------
   Shared by the customer's own documents page, the pending-documents queue and
   the client file. The checklist leads on both sides because "what is still
   missing" is the question either party actually has. */

.pill.accepted { background: #ECFDF5; border-color: #A7F3D0; color: #047857; }

.doc-checklist { display: flex; flex-direction: column; gap: 2px; }

.doc-leg {
  display: grid;
  grid-template-columns: 20px 1fr auto;
  gap: 10px;
  align-items: start;
  padding: 11px 2px;
  border-bottom: 1px solid var(--border-soft);
}
.doc-leg:last-child { border-bottom: 0; }
.doc-leg-mark { color: var(--silver-strong); font-weight: 700; line-height: 1.35; }
.doc-leg.is-done .doc-leg-mark { color: var(--accent-green); }
.doc-leg-body { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.doc-leg-body strong { font-size: 13.5px; }
.doc-leg-body span { font-size: 12.5px; color: var(--text-muted); }
.doc-leg-state {
  font-size: 11.5px; font-weight: 700; text-transform: uppercase;
  letter-spacing: 0.03em; color: var(--silver-strong); white-space: nowrap;
}
.doc-leg.is-done .doc-leg-state { color: var(--accent-green); }
.doc-complete { color: var(--accent-green); font-weight: 600; margin: 0; }

.doc-list { display: flex; flex-direction: column; }

.doc-row {
  display: flex;
  gap: 14px;
  align-items: flex-start;
  justify-content: space-between;
  padding: 12px 2px;
  border-bottom: 1px solid var(--border-soft);
}
.doc-row:last-child { border-bottom: 0; }
.doc-row-main { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.doc-row-meta { font-size: 12px; color: var(--text-muted); word-break: break-word; }
.doc-row-side { display: flex; align-items: center; gap: 8px; flex-shrink: 0; }
.doc-dl { padding: 4px 10px; font-weight: 700; text-decoration: none; }

.doc-source {
  align-self: flex-start;
  font-size: 11px; font-weight: 700; text-transform: uppercase;
  letter-spacing: 0.03em; color: var(--text-muted);
  background: var(--bg-muted); border-radius: var(--radius-pill);
  padding: 2px 8px; margin-top: 2px;
}

/* The reason a document was turned down. Shown to the customer in full: "not
   accepted" with no reason is a support call they cannot act on. */
.doc-reject-note {
  margin: 4px 0 0; font-size: 12.5px; color: var(--accent-red);
  background: #FEF2F2; border-left: 2px solid #FECACA;
  padding: 6px 10px; border-radius: var(--radius-sm);
}

.muted-note { font-size: 12px; color: var(--text-muted); margin: 10px 0 0; }

@media (max-width: 640px) {
  .doc-row { flex-direction: column; gap: 8px; }
  .doc-row-side { width: 100%; }
  .doc-leg { grid-template-columns: 18px 1fr; }
  .doc-leg-state { grid-column: 2; }
}

/* The queue variant: who it belongs to, and how long it has waited. */
.doc-row-head { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 10px; }
.doc-row-client { font-size: 12.5px; color: var(--brand-blue-hover); text-decoration: none; }
.doc-row-client:hover { text-decoration: underline; }
.doc-row-note {
  margin: 4px 0 0; font-size: 12.5px; color: var(--text-secondary);
  background: var(--bg-muted); padding: 6px 10px; border-radius: var(--radius-sm);
}
.doc-waited {
  font-variant-numeric: tabular-nums; font-size: 12px; font-weight: 700;
  color: var(--text-muted); min-width: 34px; text-align: right;
}

/* A key/value list pairs up on a wide screen instead of stretching one pair
   across the full panel. The single-column form left the label hard left and
   the value hard right with a gulf between them, which read as empty space and
   made a short list of facts scroll like a long one. */
@media (min-width: 900px) {
  .kv.kv-2col {
    grid-template-columns: auto minmax(0, 1fr) auto minmax(0, 1fr);
    column-gap: 40px;
  }
}

/* ---------------------------------------------------------------------------
   Back office conversation list
   ---------------------------------------------------------------------------
   The page used to be a compose form above a bare list of links, which on a
   quiet day was mostly empty screen and on a busy one gave no way to find
   anybody. Filters lead, the list carries enough to triage a row without
   opening it, and composing folds away. */

.chat-filters { align-items: flex-end; }
.chat-filters .field { min-width: 150px; }

.thread-list { list-style: none; margin: 0; padding: 0; }

.thread-row { border-bottom: 1px solid var(--border-soft); }
.thread-row:last-child { border-bottom: 0; }

.thread-link {
  display: flex; flex-direction: column; gap: 3px;
  padding: 12px 10px; text-decoration: none; color: inherit;
  border-inline-start: 3px solid transparent;
  transition: background 120ms var(--ease-out);
}
.thread-link:hover { background: var(--bg-muted); }
.thread-row.is-unread .thread-link { border-inline-start-color: var(--brand-blue-hover); }
.thread-row.is-closed .thread-link { opacity: 0.62; }

.thread-top { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.thread-top strong { font-size: 13.5px; }
.thread-unread {
  font-size: 11px; font-weight: 700; letter-spacing: 0.03em;
  background: var(--brand-blue-primary); color: var(--text-on-dark);
  border-radius: var(--radius-pill); padding: 2px 8px;
}
.thread-meta { font-size: 12px; color: var(--text-muted); }
.thread-preview {
  font-size: 12.5px; color: var(--text-secondary);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* A panel that folds. The marker sits inline with the heading so the row
   still reads as a section header rather than as a stray disclosure arrow. */
.compose-panel > summary {
  cursor: pointer; list-style: none;
  display: flex; align-items: center; gap: 8px;
}
.compose-panel > summary::-webkit-details-marker { display: none; }
.compose-panel > summary h3 { margin: 0; display: inline; }
.compose-panel > summary::after {
  content: '+'; margin-inline-start: auto;
  font-weight: 700; color: var(--text-muted); font-size: 16px; line-height: 1;
}
.compose-panel[open] > summary::after { content: '−'; }

@media (max-width: 640px) {
  .chat-filters .field { min-width: 0; width: 100%; }
}

/* ---------------------------------------------------------------------------
   FAQ entry form
   ---------------------------------------------------------------------------
   Four short settings on one row, then the question and the answer at full
   width. Controls fill their cell, which the wrapping flex layout never did:
   a one-word Sort box rendered the same width as the Question, and the gaps
   between them read as an unfinished form. */

.faq-form {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 12px 14px;
  align-items: end;
}
.faq-form .field { margin: 0; display: flex; flex-direction: column; min-width: 0; }
.faq-form .field label {
  margin-bottom: 6px;
  font-size: 12px; font-weight: 600; color: var(--text-secondary);
}
.faq-form input, .faq-form select, .faq-form textarea {
  width: 100%; margin: 0; box-sizing: border-box;
}
.faq-form select, .faq-form input { min-height: 38px; }
.faq-form textarea { resize: vertical; min-height: 110px; }
.faq-span { grid-column: 1 / -1; }
.faq-actions {
  grid-column: 1 / -1;
  display: flex; flex-wrap: wrap; align-items: center; gap: 10px;
}
.faq-actions button { margin: 0; min-height: 38px; }

@media (max-width: 700px) {
  .faq-form { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* Onboarding evidence column: what is actually on file for an applicant. */
.ob-evidence { white-space: nowrap; }
.ob-mark {
  display: inline-block; margin-inline-end: 8px;
  font-size: 11.5px; font-weight: 700; color: var(--accent-red);
}
.ob-mark.is-on { color: var(--accent-green); }

/* Sign-up document slots: one box per thing we need, so "what is still
   missing" is visible without reading a list of error messages. */
.doc-upload-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 12px;
  margin: 4px 0 12px;
}
.doc-slot {
  display: flex; flex-direction: column; gap: 6px;
  padding: 12px 14px;
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-md);
  background: var(--bg-card);
}
.doc-slot.is-sent { border-color: #A7F3D0; background: #F6FFFB; }
.doc-slot strong { font-size: 13px; }
.doc-slot-hint { font-size: 12px; color: var(--text-muted); }
.doc-slot input[type="file"] { font-size: 12.5px; max-width: 100%; }
.doc-slot-state { font-size: 12px; font-weight: 700; color: var(--accent-green); min-height: 15px; }

/* ---------------------------------------------------------------------------
   Notices raised against one customer
   ---------------------------------------------------------------------------
   A banner states something and offers the way to deal with it; a full screen
   has to be closed before the page can be used, and comes back on the next
   page until the back office clears it. */

.notice-banner {
  display: flex; flex-wrap: wrap; align-items: center; gap: 12px 16px;
  margin: 0 0 18px;
  padding: 14px 18px;
  border: 1px solid #FDE68A;
  border-inline-start: 3px solid var(--accent-amber);
  border-radius: var(--radius-md);
  background: #FFFBEB;
}
.notice-banner-text { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1 1 260px; }
.notice-banner-text strong { font-size: 14px; color: var(--accent-amber); }
.notice-banner-text span { font-size: 13px; color: var(--text-secondary); }
.notice-banner-action { flex-shrink: 0; text-decoration: none; }

.notice-scrim {
  position: fixed; inset: 0; z-index: 90;
  display: grid; place-items: center;
  padding: 24px;
  background: rgba(18, 35, 58, 0.72);
  backdrop-filter: blur(2px);
}
.notice-box {
  width: min(560px, 100%);
  max-height: 80vh; overflow-y: auto;
  background: var(--bg-card);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-float);
  padding: 28px 30px;
}
.notice-box h2 { margin: 0 0 12px; font-size: 19px; }
.notice-body p { margin: 0 0 10px; font-size: 14px; line-height: 1.55; color: var(--text-secondary); }
.notice-body p:last-child { margin-bottom: 0; }
.notice-actions { display: flex; justify-content: flex-end; margin-top: 22px; }

@media (max-width: 560px) {
  .notice-box { padding: 22px 20px; }
  .notice-banner-action { width: 100%; text-align: center; }
}

/* The composer staff write a full-screen message in. Uses the shared scrim so
   it dims the page the same way every other dialog here does. */
.notice-compose {
  width: min(620px, calc(100vw - 32px));
  max-height: 86vh; overflow-y: auto;
  background: var(--bg-card);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-float);
  padding: 24px 26px;
}
.notice-compose h3 { margin: 0 0 4px; font-size: 16px; }
.notice-compose .muted { margin: 0 0 16px; font-size: 12.5px; }
.notice-compose .field { margin: 0 0 14px; display: flex; flex-direction: column; }
.notice-compose label {
  margin-bottom: 6px; font-size: 12px; font-weight: 600; color: var(--text-secondary);
}
.notice-compose input, .notice-compose textarea {
  width: 100%; margin: 0; box-sizing: border-box;
}
.notice-compose textarea { resize: vertical; min-height: 180px; line-height: 1.5; }
.notice-compose-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; }
.notice-compose-actions button { margin: 0; }

/* Live notices on the client file, with the way to take them down. */
.notice-live {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 6px 12px;
  padding: 10px 2px; border-bottom: 1px solid var(--border-soft);
}
.notice-live:last-child { border-bottom: 0; }
.notice-live-meta { font-size: 12px; color: var(--text-muted); }
.notice-live-body { flex: 1 1 100%; font-size: 12.5px; color: var(--text-secondary); }

/* ===========================================================================
   Signed-out pages, in the style of the public landing
   ===========================================================================
   Sign in, sign up and forgot-password share the marketing site's treatment:
   a white bar carrying the wordmark, a full-bleed photograph behind a deep
   navy scrim, and a display serif for the headline.

   Scoped to .auth-landing / .reg-landing rather than replacing the older
   .auth-page rules, so the previous look is one class away if it is wanted
   back. The body element in the selector is what wins the specificity.

   The colours are measured off the supplied design, not guessed:
   scrim #0D1A2D, primary action #14415F, mark teal #185661, gold #C5A975. */

:root {
  --font-display: 'Playfair Display', 'Iowan Old Style', Georgia, serif;
  --landing-scrim: #0D1A2D;
  --landing-action: #14415F;
  --landing-action-hover: #1B5480;
  /* The mark's gold is 2.0:1 on white — a flourish, not text. This darker
     cut reaches 4.9:1, so the "Financial Services" line is actually legible
     while still reading as the same gold. */
  --gold-on-light: #8A6F3A;
}

/* ---- the photograph and its scrim ---- */

body.auth-landing .auth-scene {
  position: fixed;
  inset: 0;
  background-image: url('/img/hero-boardroom.webp?v=202611041609');
  background-size: cover;
  background-position: center 42%;
  background-repeat: no-repeat;
  filter: none;
  opacity: 1;
}
/* The old decorative cut-outs are replaced by the photograph itself. */
body.auth-landing .auth-photo,
body.auth-landing .auth-rim,
body.auth-landing .auth-aside { display: none; }

body.auth-landing .auth-scene::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(
    100deg,
    var(--landing-scrim) 0%,
    rgba(13, 26, 45, 0.94) 34%,
    rgba(13, 26, 45, 0.66) 56%,
    rgba(13, 26, 45, 0.18) 100%);
}
[dir="rtl"] body.auth-landing .auth-scene::after { transform: scaleX(-1); }

body.auth-landing { background: var(--landing-scrim); color: #fff; }

/* ---- shell: white bar on top, hero below ---- */

body.auth-landing .auth-shell {
  padding: 0;
  gap: 0;
  grid-template-rows: auto 1fr;
}

body.auth-landing .auth-top {
  background: #fff;
  padding: 13px clamp(20px, 4vw, 54px);
  border-bottom: 1px solid rgba(16, 46, 53, 0.10);
}

body.auth-landing .auth-body {
  padding: clamp(28px, 6vh, 72px) clamp(20px, 4vw, 54px) clamp(36px, 7vh, 80px);
  align-items: center;
}
body.auth-landing .auth-col { width: min(560px, 100%); gap: 22px; }

/* ---- the wordmark ---- */

.brand-logo-block { display: flex; align-items: center; gap: 11px; }
.brand-words { display: flex; flex-direction: column; line-height: 1.12; }
.brand-wordmark {
  font-family: var(--font-display);
  font-size: clamp(17px, 1.5vw, 21px);
  font-weight: 500;
  letter-spacing: 0.01em;
  color: #102E35;
}
.brand-logo-block .brand-sub {
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: 0.17em;
  text-transform: uppercase;
  color: var(--gold-on-light);
  padding-inline-start: 1px;
}
/* The mark is a small disc beside the words here, not a stacked block. */
body.auth-landing .auth-top .brand-logo,
body.reg-landing .reg-top .brand-logo {
  width: 38px; max-width: 38px; height: 38px;
  margin: 0;
  border-radius: 50%;
}

/* ---- headline ---- */

body.auth-landing .auth-welcome { margin-bottom: 4px; }
body.auth-landing .auth-welcome h1 {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: clamp(30px, 4.4vw, 52px);
  line-height: 1.1;
  letter-spacing: -0.005em;
  color: #fff;
  text-wrap: balance;
}

/* The eyebrow gets the landing's short rule before it. */
body.auth-landing .auth-greet,
body.auth-landing .auth-page .auth-greet {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 14px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.16em;
  color: rgba(255, 255, 255, 0.72);
}
body.auth-landing .auth-greet::before {
  content: '';
  width: 26px; height: 1px;
  background: var(--brand-gold);
  flex: none;
}

/* ---- the sign-in card on the dark ---- */

body.auth-landing .auth-cols {
  grid-template-columns: minmax(0, 390px) minmax(0, 1fr);
  gap: clamp(24px, 4vw, 52px);
}

body.auth-landing .auth-card,
body.auth-landing.auth-page .auth-card {
  padding: 26px 26px 22px;
  background: rgba(255, 255, 255, 0.055);
  border: 1px solid rgba(255, 255, 255, 0.16);
  border-radius: var(--radius-md);
  box-shadow: none;
  backdrop-filter: blur(3px);
}
body.auth-landing .auth-card h2,
body.auth-landing.auth-page .auth-card h2 {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: 22px;
  color: #fff;
}
body.auth-landing .auth-card .field label {
  color: rgba(255, 255, 255, 0.68);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}
body.auth-landing .auth-card input[type="email"],
body.auth-landing .auth-card input[type="password"],
body.auth-landing .auth-card input[type="text"] {
  min-height: 46px;
  background: rgba(255, 255, 255, 0.07);
  border: 1px solid rgba(255, 255, 255, 0.22);
  color: #fff;
}
body.auth-landing .auth-card input::placeholder { color: rgba(255, 255, 255, 0.4); }
body.auth-landing .auth-card input:focus {
  border-color: var(--brand-gold);
  outline-color: var(--brand-gold);
}

body.auth-landing .auth-card button[type="submit"],
body.auth-landing .auth-card .btn-primary {
  background: var(--landing-action);
  border-color: var(--landing-action);
  color: #fff;
  min-height: 48px;
  font-weight: 600;
  letter-spacing: 0.01em;
}
body.auth-landing .auth-card button[type="submit"]:hover,
body.auth-landing .auth-card .btn-primary:hover {
  background: var(--landing-action-hover);
  border-color: var(--landing-action-hover);
}
body.auth-landing .auth-card .btn-ghost {
  background: transparent;
  border: 1px solid rgba(255, 255, 255, 0.42);
  color: #fff;
}
body.auth-landing .auth-card .btn-ghost:hover {
  background: rgba(255, 255, 255, 0.09);
  border-color: rgba(255, 255, 255, 0.7);
}

body.auth-landing .auth-remember,
body.auth-landing .auth-remember span { color: rgba(255, 255, 255, 0.78); }
body.auth-landing .auth-card .divider { color: rgba(255, 255, 255, 0.45); }
body.auth-landing .auth-card .divider::before,
body.auth-landing .auth-card .divider::after { background: rgba(255, 255, 255, 0.2); }
body.auth-landing .auth-alt a { color: rgba(255, 255, 255, 0.86); }
body.auth-landing .auth-msg { color: #FFB4AE; }

/* ---- the column beside the card ---- */

body.auth-landing .auth-links { color: rgba(255, 255, 255, 0.82); }
body.auth-landing .auth-points li,
body.auth-landing .auth-need li { color: rgba(255, 255, 255, 0.78); }
body.auth-landing .auth-need {
  border: 1px solid rgba(255, 255, 255, 0.14);
  background: rgba(255, 255, 255, 0.04);
}
body.auth-landing .auth-need b { color: #fff; }
body.auth-landing .auth-secure { color: rgba(255, 255, 255, 0.6); }

/* ---- the language picker sits on white now ---- */

body.auth-landing .auth-lang { color: var(--text-secondary); }
body.auth-landing .auth-lang select {
  background: #fff;
  border-color: var(--border-strong);
  color: var(--text-primary);
}

@media (max-width: 820px) {
  body.auth-landing .auth-cols { grid-template-columns: minmax(0, 1fr); }
  body.auth-landing .auth-scene::after {
    background: linear-gradient(180deg,
      rgba(13, 26, 45, 0.86) 0%, rgba(13, 26, 45, 0.95) 45%, var(--landing-scrim) 100%);
  }
}

/* The two columns need room: capped at the old 430px the second column was
   squeezed to about 120px and the reassurance list wrapped one word per line,
   over the photograph rather than over the scrim. Widening the column means
   the scrim has to travel further right to stay behind it. */
body.auth-landing .auth-col { width: min(980px, 100%); }

body.auth-landing .auth-scene::after {
  background: linear-gradient(
    100deg,
    var(--landing-scrim) 0%,
    rgba(13, 26, 45, 0.97) 40%,
    rgba(13, 26, 45, 0.82) 58%,
    rgba(13, 26, 45, 0.35) 80%,
    rgba(13, 26, 45, 0.12) 100%);
}

/* The headline wants the landing's measure — three short lines, not two long
   ones running under the photograph. */
body.auth-landing .auth-welcome h1 { max-width: 13ch; }

body.auth-landing .auth-links { padding-top: 2px; }
body.auth-landing .auth-points { margin-top: 0; }

/* The promo bar, the secure note and the one link in the side column were
   still wearing the in-app teal, which reads as a different site sitting
   underneath this one. They move onto the landing's navy and petrol blue. */

body.auth-landing .auth-promo {
  background: var(--landing-scrim);
  border-top: 1px solid rgba(255, 255, 255, 0.12);
  color: rgba(255, 255, 255, 0.86);
}
body.auth-landing .auth-promo .btn-primary {
  background: var(--landing-action);
  border-color: var(--landing-action);
  color: #fff;
}
body.auth-landing .auth-promo .btn-primary:hover {
  background: var(--landing-action-hover);
  border-color: var(--landing-action-hover);
}

body.auth-landing .auth-secure {
  background: rgba(255, 255, 255, 0.05);
  border: 1px solid rgba(255, 255, 255, 0.14);
  color: rgba(255, 255, 255, 0.66);
}
body.auth-landing .auth-secure b,
body.auth-landing .auth-secure strong { color: rgba(255, 255, 255, 0.9); }

/* Links in the side column: white, with the gold reserved for the chevron so
   the colour still appears without carrying the words. */
body.auth-landing .auth-links a { color: #fff; }
body.auth-landing .auth-links a:hover { color: var(--brand-gold); }

/* Any prose inside the card — the reset page's instructions, helper lines —
   was still the dark body colour, which on the dark card is close to
   unreadable. */
body.auth-landing .auth-card p,
body.auth-landing .auth-card li,
body.auth-landing .auth-card .muted,
body.auth-landing .auth-card small { color: rgba(255, 255, 255, 0.74); }
body.auth-landing .auth-card a { color: #fff; }
body.auth-landing .auth-card a:hover { color: var(--brand-gold); }

/* ---- sign-up: the same white bar and navy band ---- */

body.reg-landing { --reg-band: 340px; }

/* The photograph, in a band rather than the whole page, and without the
   diagonal cut — the landing has a straight edge under its hero. */
body.reg-landing .auth-scene {
  position: absolute;
  inset: 0 0 auto 0;
  height: var(--reg-band);
  clip-path: none;
  background-image: url('/img/hero-boardroom.webp?v=202611041609');
  background-size: cover;
  background-position: center 40%;
  opacity: 1;
  filter: none;
}
body.reg-landing .auth-rim,
body.reg-landing .reg-band { display: none; }
body.reg-landing .auth-scene::after {
  background: linear-gradient(
    100deg,
    var(--landing-scrim) 0%,
    rgba(13, 26, 45, 0.95) 42%,
    rgba(13, 26, 45, 0.74) 64%,
    rgba(13, 26, 45, 0.3) 100%);
}

/* The bar runs the full width and sits above the band, as on the landing;
   the shell's own centred column resumes below it. */
body.reg-landing .reg-shell { max-width: none; padding: 0 0 48px; }
body.reg-landing .reg-top {
  margin: 0 0 clamp(26px, 5vh, 54px);
  padding: 13px clamp(20px, 4vw, 54px);
  background: #fff;
  border-bottom: 1px solid rgba(16, 46, 53, 0.10);
}
body.reg-landing .reg-top a { color: var(--landing-action); text-decoration: none; }
body.reg-landing .reg-top a:hover { text-decoration: underline; }
body.reg-landing .reg-top .auth-lang { color: var(--text-secondary); }
body.reg-landing .reg-top .auth-lang select {
  background: #fff; border-color: var(--border-strong); color: var(--text-primary);
}

/* Everything below the bar goes back into the readable centred column. */
body.reg-landing .reg-hero,
body.reg-landing .reg-shell > form,
body.reg-landing .reg-shell > .reg-section,
body.reg-landing .reg-shell > section {
  max-width: 780px;
  margin-inline: auto;
  padding-inline: clamp(16px, 4vw, 28px);
}

body.reg-landing .reg-hero h1 {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: clamp(28px, 3.6vw, 42px);
  line-height: 1.12;
  color: #fff;
}
body.reg-landing .reg-hero .auth-greet {
  display: flex; align-items: center; gap: 10px;
  margin-bottom: 12px;
  font-size: 11px; font-weight: 600; letter-spacing: 0.16em;
  color: rgba(255, 255, 255, 0.72);
}
body.reg-landing .reg-hero .auth-greet::before {
  content: ''; width: 26px; height: 1px; background: var(--brand-gold); flex: none;
}

/* The decorative cut-out photo is a separate element from the scene, and on
   sign-up it was still painting the old stock picture over the band. */
body.reg-landing .auth-photo { display: none; }

/* The old design gave the welcome block its own tinted panel and padding on
   narrow screens. Against the landing's full-bleed scrim that reads as a
   stray card clipped by the one below it. */
body.auth-landing .auth-welcome {
  background: none;
  padding: 0;
  border: 0;
  box-shadow: none;
}

/* The card's own text colour was still the dark body colour. Headings,
   labels and prose were each overridden, but anything else inside it — a
   stray span, a validation hint — came out near-black on near-black. */
body.auth-landing .auth-card,
body.auth-landing.auth-page .auth-card { color: #fff; }

@media (max-width: 820px) {
  /* On a phone the photograph is behind the form rather than beside it, so
     the scrim has to carry almost all the way or the sign-in fields sit on
     a lamp. */
  body.auth-landing .auth-scene::after {
    background: linear-gradient(180deg,
      rgba(13, 26, 45, 0.90) 0%,
      rgba(13, 26, 45, 0.97) 28%,
      var(--landing-scrim) 55%);
  }
  body.auth-landing .auth-welcome h1 { max-width: none; font-size: clamp(27px, 8vw, 36px); }
  body.auth-landing .auth-body { padding-top: 26px; }
}

/* ===========================================================================
   One brand lockup, everywhere
   ===========================================================================
   The sidebar still carried the old arrangement: an 88px plate of the mark's
   own teal with the name as a caption beneath it. Next to the signed-out
   pages it read as a different logo, and at that size the square of teal
   competed with the page rather than sitting in it.

   The mark is artwork on a square plate, so it is cropped to a disc — which
   is what the ring in the drawing is already describing. */

.brand-logo-block {
  display: flex;
  align-items: center;
  gap: 10px;
  text-decoration: none;
}
.brand-logo-block .brand-logo {
  width: 34px;
  max-width: 34px;
  height: 34px;
  margin: 0;
  border-radius: 50%;
  flex: none;
}
.brand-logo-block .brand-words {
  display: flex;
  flex-direction: column;
  line-height: 1.15;
  min-width: 0;
}
.brand-logo-block .brand-wordmark {
  font-family: var(--font-display);
  font-size: 16px;
  font-weight: 500;
  color: var(--text-primary);
  white-space: nowrap;
}
.brand-logo-block .brand-sub {
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: var(--gold-on-light);
  white-space: nowrap;
}

/* The signed-out bar runs a size larger, as the landing does. */
body.auth-landing .auth-top .brand-logo,
body.reg-landing .reg-top .brand-logo {
  width: 38px; max-width: 38px; height: 38px;
}
body.auth-landing .auth-top .brand-wordmark,
body.reg-landing .reg-top .brand-wordmark {
  font-size: clamp(17px, 1.5vw, 21px);
}

/* ---- mobile proportions ---- */

@media (max-width: 560px) {
  /* The account tiles were fixed at 210px inside a 343px row, so a second
     one could never sit beside the first: each wrapped onto its own line and
     left a third of the width empty beside it. On a phone they take the row. */
  .tile-strip { gap: 8px; }
  .acct-tile { flex: 1 1 100%; min-width: 0; }

  /* Five actions at a fixed 76px gave three on one row and two on the next
     with two dead cells beside them. Letting them grow means both rows are
     filled and the short one is centred, so the arrangement looks chosen. */
  .qa-row {
    justify-content: center;
    gap: 14px 12px;
  }
  .qa {
    flex: 1 1 92px;
    max-width: 120px;
    width: auto;
  }
}
