:root {
  --background: 240 5% 4.5%;
  --foreground: 44 44% 95%;
  --card: 240 6% 8.25%;
  --card-foreground: 44 44% 95%;
  --muted: 240 6% 11%;
  --muted-foreground: 44 16% 72%;
  --border: 240 7% 14%;
  --sidebar: 240 8% 6%;
  --sidebar-foreground: 44 44% 95%;
  --primary: 44 93% 60%;
  --primary-foreground: 240 7% 6%;
  /* Neither is redefined anywhere else in the compiled app (no .dark
     variant exists for them) — every native Radix dropdown/tooltip/select
     using bg-popover or focus:bg-accent renders in the native light-mode
     white/near-black pair otherwise, the same bug this file already found
     and fixed once for its own custom tooltips (see .portal-floating-tip)
     but never at the root — the user menu dropdown is the one still
     showing it as a plain white box. Fixing it here instead of per-
     component covers every current and future native popover/menu at
     once. */
  --popover: 240 6% 11%;
  --popover-foreground: 44 44% 95%;
  --accent: 240 6% 16%;
  --accent-foreground: 44 44% 95%;

  --grid-line: rgba(var(--ov-tint-rgb), 0.04);
  --surface-dark: rgba(var(--ov-tint-rgb), 0.035);
  --surface-dark-raised: rgba(var(--ov-tint-rgb), 0.065);

  --success: #3DA35D;
  --success-bg: rgba(61, 163, 93, 0.14);
  --success-border: rgba(61, 163, 93, 0.34);
  --warning: #D97A34;
  --warning-bg: rgba(217, 122, 52, 0.14);
  --warning-border: rgba(217, 122, 52, 0.32);
  --danger: #E5484D;
  --danger-bg: rgba(229, 72, 77, 0.14);
  --danger-border: rgba(229, 72, 77, 0.34);
  --info: #5B9BD9;
  --info-bg: rgba(91, 155, 217, 0.14);
  --info-border: rgba(91, 155, 217, 0.34);
  --gold: #F0B94A;
  --gold-bg: rgba(240, 185, 74, 0.16);
  --gold-border: rgba(240, 185, 74, 0.36);

  /* Neutral surface system this whole file is built on — every card/menu/
     tooltip background, border and body-text color below resolves through
     one of these six tokens instead of a literal, so the light theme below
     only has to redeclare these six to re-skin the entire file at once.
     --ov-tint-rgb/--ov-muted-rgb hold bare "R, G, B" triples (no alpha) so
     they can be dropped straight into any existing rgba(var(--x), N) call
     while keeping that call's own original alpha untouched. */
  --ov-tint-rgb: 255, 255, 255;
  --ov-muted-rgb: 245, 242, 233;
  --ov-text: #F5F2E9;
  --ov-surface-bg: #111113;
  --ov-surface-bg-alt: #0D0D0F;
  --ov-tooltip-bg: #1A1A1D;
  --ov-page-bg: #0A0A0B;
  /* Multiplies every box-shadow's black alpha via calc(N * var(--ov-shadow-
     scale)) at each call site. A shadow tuned to read as a soft lift on a
     near-black page (this theme) is a heavy, visibly-edged smudge on a
     white one — same literal alpha, very different result depending on
     what it's sitting on — so unlike the neutral tokens above, this one
     needs an actual multiplier, not just a color swap. */
  --ov-shadow-scale: 1;
}

/* ---- Light theme. Toggled by adding/removing this class on <html> (see
   ensureThemeToggle / applyThemeMode in portal-overrides.js) — flips the
   same six neutral tokens above (dark-on-light instead of light-on-dark,
   same alpha at every call site) plus the handful of shadcn tokens this
   file forces dark up top for its own reasons (the popover/accent bug
   noted above doesn't exist in light mode, so those go back to the
   compiled app's own native light values here instead of staying forced).
   Semantic colors (--success/--warning/--danger/--info/--gold and their
   -bg/-border tints, plus the gold gradient badges elsewhere in this file)
   are left alone in both themes — they're alpha tints designed to sit on
   top of any page color, not part of this neutral system, and read fine
   on white as-is. --ov-shadow-scale turned down instead — see its comment
   above. */
.portal-light-theme {
  --background: 0 0% 100%;
  --foreground: 240 8% 10%;
  --card: 0 0% 100%;
  --card-foreground: 240 8% 10%;
  --muted: 240 10% 96%;
  --muted-foreground: 240 6% 42%;
  --border: 240 10% 88%;
  /* --sidebar/--sidebar-foreground/-accent/-border/-ring deliberately NOT
     redefined here — the left nav rail and top header (both bg-sidebar)
     stay permanently dark in both themes, by request, instead of following
     the light/dark toggle like the rest of the page. */
  --popover: 0 0% 100%;
  --popover-foreground: 240 8% 10%;
  --accent: 240 10% 94%;
  --accent-foreground: 240 8% 10%;

  --ov-tint-rgb: 0, 0, 0;
  --ov-muted-rgb: 23, 23, 26;
  --ov-text: #17171A;
  --ov-surface-bg: #FFFFFF;
  --ov-surface-bg-alt: #FFFFFF;
  --ov-tooltip-bg: #FFFFFF;
  --ov-page-bg: #F4F4F5;
  --ov-shadow-scale: 0.35;
}

/* The globe/theme-toggle/bell buttons in the header, the two dropdown
   panels they open, and the left nav rail (including "Что будет после
   подачи" / "Подсказки", injected inside that same rail by
   findGlobalNavSidebar — see portal-newapp-sidebar below) are all part of
   that same permanently-dark chrome (see the --sidebar note above), not
   the content underneath. Re-pinning the six neutral tokens back to their
   dark values on just this subtree keeps them rendering as light-on-dark
   in light mode too, instead of going dark-on-dark and disappearing —
   which is exactly what happened to portal-newapp-steps' text before this
   rule covered [data-slot='sidebar'] too. */
.portal-light-theme .portal-notif-group,
.portal-light-theme .portal-notif-panel,
.portal-light-theme [data-slot='sidebar'] {
  --ov-tint-rgb: 255, 255, 255;
  --ov-muted-rgb: 245, 242, 233;
  --ov-text: #F5F2E9;
  --ov-surface-bg: #111113;
  --ov-surface-bg-alt: #111113;
  --ov-tooltip-bg: #111113;
}

/* Smooth color-scheme switch on theme toggle. Scoped to the properties the
   tokens above actually drive (color/background/border), not `all`, so it
   can't fight unrelated transitions (transform, opacity) elsewhere in this
   file. Selectors that opt out with `transition: none !important` (e.g.
   .portal-overview-card, to avoid the stuck-transition-frame bug described
   near that rule) keep winning here too — !important still applies.
   box-shadow deliberately excluded — animating the big blurred shadows
   this file uses on ~a dozen cards at once produced a stray jagged
   rendering seam during the transition. Shadows just snap instantly
   instead; barely noticeable next to the 0.25s color fade. */
html,
html *,
html *::before,
html *::after {
  transition: background-color 0.25s ease, border-color 0.25s ease, color 0.25s ease;
}

html,
body,
#root {
  min-height: 100%;
  background: var(--ov-page-bg);
}

/* No page ever needs to scroll sideways here — every table wide enough to
   have once needed it now either scrolls within its own card (Мои
   сделки/Архив, both already scoped to their own overflow) or is refit to
   fit the viewport in landscape (see the rules further down). Without
   this, iOS Safari's elastic overscroll still lets a swipe drag the
   *whole page* a few px sideways and bounce back even when nothing
   actually overflows — no wider element to find or fix, just the
   platform's default rubber-banding on an axis this app never uses.
   Same fix already in place on the main landing page (see the portrait
   media query in the root style.css). */
html,
body {
  overflow-x: hidden;
  overscroll-behavior-x: none;
}

body {
  margin: 0;
  position: relative;
  background: var(--ov-page-bg);
  color: var(--ov-text);
  font-family: 'Inter', system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
}

body::before {
  content: '';
  position: fixed;
  inset: 0;
  background-image:
    linear-gradient(var(--grid-line) 1px, transparent 1px),
    linear-gradient(90deg, var(--grid-line) 1px, transparent 1px);
  background-size: 84px 84px, 84px 84px;
  pointer-events: none;
}

body,
#root,
main,
[data-slot='sidebar'] {
  background: transparent;
}

/* On mobile, shadcn's Sidebar swaps from the desktop inline rail (a
   "group peer ... hidden md:block" placeholder — genuinely meant to stay
   transparent, see above) to a Radix Sheet: same [data-slot='sidebar'],
   now `position: fixed` and floating above the page as a real drawer. The
   transparent rule above then left it see-through, so the page content
   underneath (Overview heading, gold CTA button) showed straight through
   the nav links instead of a clean opaque panel. `.fixed` only ever
   appears on the mobile Sheet variant, so this can't touch the desktop
   rail. */
[data-slot='sidebar'].fixed {
  background: hsl(var(--sidebar));
}


/* The real source of the persistent dark rounded panel: shadcn's
   SidebarInset renders <main data-slot="sidebar-inset"> with a
   "bg-background" class (and rounded-xl/shadow-sm on the inset variant).
   A plain "main" tag selector loses to that class on specificity, so it
   has to be beaten explicitly. */
main[data-slot='sidebar-inset'] {
  background: transparent !important;
  box-shadow: none !important;
  border-radius: 0 !important;
  margin: 0 !important;
}

/* The app's own .portal-grid-bg draws a grid overlay masked with a
   radial-gradient fade (mask-image: radial-gradient) plus a bg-muted/30
   tint on the <main> box itself — the background "fog" effect. Killed
   outright per request; the page background is now a flat solid color. */
main.portal-grid-bg {
  background: transparent !important;
}

main.portal-grid-bg::before {
  content: none !important;
}

.portal-overview-page {
  padding-top: 0.3rem;
}

/* Top "Обзор" block: kpi-dark-card is the app's own class for this container.
   Targeted directly (not only via the portal-overview-card marker) so the fix
   holds even if the marker class gets stripped by a React re-render. */
.portal-overview-card,
.kpi-dark-card {
  background: transparent !important;
  border: 0 !important;
  box-shadow: none !important;
  border-radius: 0 !important;
  /* No bottom padding here — the gap down to .portal-bottom-grid comes
     solely from overviewRoot's own native gap-6 (24px, a Tailwind flex
     gap between its direct children, not something this rule owns).
     Padding here used to compound with that gap-6, making this gap
     visibly bigger than .portal-overview-metrics's own 1.5rem row-gap
     below, which is now set to match gap-6 exactly (see that rule). */
  padding: 0 !important;
  backdrop-filter: none !important;
  -webkit-backdrop-filter: none !important;
  /* The base app's own .kpi-dark-card rule sets
     "transition: background .28s, box-shadow .28s, ...". Without killing
     that here too, the browser keeps the pre-override gradient/shadow
     visually painted as a stuck transition frame even though the
     computed value above is already transparent — the gray "plate" this
     override is supposed to remove. */
  transition: none !important;
}

.kpi-dark-card:hover {
  background: transparent !important;
  border-color: transparent !important;
  box-shadow: none !important;
  transform: none !important;
}

.kpi-dark-card::before {
  content: none !important;
}

.portal-overview-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1rem;
  padding: 0 0 1.25rem;
  margin-bottom: 0;
}

.portal-overview-header h1 {
  margin: 0;
  color: var(--ov-text);
  font-size: clamp(1.75rem, 2.2rem, 2.5rem);
  line-height: 1.05;
  letter-spacing: -0.03em;
}

.portal-overview-header p {
  margin: 0.35rem 0 0;
  color: rgba(var(--ov-muted-rgb), 0.72);
}

.portal-overview-header a,
.portal-overview-header button {
  margin-top: 0.15rem;
}

.portal-overview-metrics {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  /* Matches overviewRoot's own native gap-6 (24px) — see the padding note
     on .portal-overview-card/.kpi-dark-card above — so the gap above
     Заявок/Активных/Ближайшее reads the same as the gap below them. */
  gap: 1.5rem;
  border: 0 !important;
  padding: 0;
  margin-top: 0;
}

/* "Всего профинансировано" is the borrower's key figure: promote it to a
   full-width row above the other three, which stay compact underneath. */
.portal-metric-card:has([data-testid="kpi-total-financed"]),
.kpi-dark-card div[class*="divide-y"] > div:has([data-testid="kpi-total-financed"]) {
  grid-column: 1 / -1;
  order: -1;
  padding: 1.6rem 1.9rem;
}

.portal-metric-card:has([data-testid="kpi-total-financed"]) [data-testid="kpi-total-financed"] {
  font-size: clamp(2.25rem, 4vw, 3rem);
  line-height: 1.05;
  margin-top: 0.5rem;
}

.portal-metric-card:has([data-testid="kpi-total-financed"]) [data-testid="kpi-total-financed"] {
  display: flex;
  align-items: baseline;
}

.metric-currency-tag {
  font-weight: 500;
  font-size: 0.5em;
  color: rgba(var(--ov-muted-rgb), 0.5);
  margin-right: 0.5rem;
}

/* Structural fallback selector for the four metric cells (works even if the
   portal-metric-card marker class is stripped by a React re-render). */
.kpi-dark-card div[class*="divide-y"] > div {
  position: relative;
  overflow: hidden;
}

/* One recipe for every Обзор container — Всего профинансировано's own
   (Заявок на рассмотрении / Активных сделок / Ближайшее погашение /
   Требует внимания / Ближайшие погашения / Последние события all match it
   below, instead of each having its own variant). */
.portal-metric-card,
.kpi-dark-card div[class*="divide-y"] > div {
  border-radius: 12px;
  background: linear-gradient(145deg, rgba(var(--ov-tint-rgb), 0.075), rgba(var(--ov-tint-rgb), 0.025)), var(--ov-surface-bg);
  border: 1px solid rgba(var(--ov-tint-rgb), 0.16);
  box-shadow:
    inset 0 1px 0 rgba(var(--ov-tint-rgb), 0.14),
    0 18px 48px rgba(0, 0, 0, calc(0.16 * var(--ov-shadow-scale)));
  padding: 1rem 1.1rem;
  transition: background 0.25s ease, box-shadow 0.25s ease, transform 0.25s ease, border-color 0.25s ease;
}

.portal-metric-card:hover,
.kpi-dark-card div[class*="divide-y"] > div:hover {
  background: linear-gradient(145deg, rgba(var(--ov-tint-rgb), 0.1), rgba(var(--ov-tint-rgb), 0.035)), var(--ov-surface-bg);
  box-shadow:
    inset 0 1px 0 rgba(var(--ov-tint-rgb), 0.18),
    0 22px 54px rgba(0, 0, 0, calc(0.2 * var(--ov-shadow-scale)));
  transform: translateY(-3px);
}

/* Заявок на рассмотрении / Активных сделок / Ближайшее погашение double as
   links into Мои сделки (see wireMetricCardLinks in portal-overrides.js) —
   same lift as every other metric card, plus the landing page's own
   "quick-flow-card" motion signature: a diagonal sheen that sweeps across
   on hover, so these three read as distinctly interactive. */
.portal-metric-card-clickable {
  cursor: pointer;
}

.portal-metric-card-clickable::before {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(110deg, transparent 0%, rgba(var(--ov-tint-rgb), 0.08) 42%, transparent 68%);
  opacity: 0;
  transform: translateX(-36%);
  transition: opacity 0.35s ease, transform 0.6s ease;
  pointer-events: none;
}

.portal-metric-card-clickable:hover {
  border-color: rgba(var(--ov-tint-rgb), 0.30);
  transform: translateY(-4px);
}

.portal-metric-card-clickable:hover::before {
  opacity: 1;
  transform: translateX(34%);
}

.portal-metric-card > * {
  position: relative;
  z-index: 1;
}

.portal-metric-card .text-white\/60,
.portal-metric-card .text-white\/50,
.portal-metric-card .text-muted-foreground {
  color: rgba(var(--ov-muted-rgb), 0.72) !important;
}

.portal-metric-card .text-2xl,
.portal-metric-card .text-3xl {
  color: var(--ov-text) !important;
}

/* "Последние события": target both the JS marker class and, robustly, the
   Card element that wraps the activity list directly by its data-testid, so
   the border/shadow fix holds even without the marker class. */
/* Matched to Всего профинансировано's recipe, same as every metric card
   above (Требует внимания / Ближайшие погашения below now match this too). */
.portal-activity-card,
main .mx-auto.flex.max-w-5xl.flex-col.gap-6 > div:has([data-testid="list-activity"]) {
  margin-top: 0;
  background: linear-gradient(145deg, rgba(var(--ov-tint-rgb), 0.075), rgba(var(--ov-tint-rgb), 0.025)), var(--ov-surface-bg) !important;
  border: 1px solid rgba(var(--ov-tint-rgb), 0.16) !important;
  border-radius: 12px !important;
  box-shadow:
    inset 0 1px 0 rgba(var(--ov-tint-rgb), 0.14),
    0 18px 48px rgba(0, 0, 0, calc(0.16 * var(--ov-shadow-scale))) !important;
}

/* Not clickable, so no hover lift — static like Требует внимания /
   Ближайшие погашения below, just with the shared color recipe. */

/* Deal detail page ("Мои сделки" -> a row): same recipe again, for its 4
   Cards (Статус сделки / Расчёт финансирования / Ключевые даты /
   Документы по сделке — see ensureDealDetailCardsThemed in
   portal-overrides.js). Static, not clickable, same as .portal-activity-
   card above — no hover lift here either. */
.portal-deal-detail-card {
  background: linear-gradient(145deg, rgba(var(--ov-tint-rgb), 0.075), rgba(var(--ov-tint-rgb), 0.025)), var(--ov-surface-bg) !important;
  border: 1px solid rgba(var(--ov-tint-rgb), 0.16) !important;
  border-radius: 12px !important;
  box-shadow:
    inset 0 1px 0 rgba(var(--ov-tint-rgb), 0.14),
    0 18px 48px rgba(0, 0, 0, calc(0.16 * var(--ov-shadow-scale))) !important;
}

/* Overdue/default banner on the same page — recolored off the native
   --status-warning-bg/--status-danger-bg tokens (pale, no dark-theme
   variant anywhere in the compiled app) onto this file's own dark-safe
   --warning/--danger set (see ensureDealDetailFlagBanner in
   portal-overrides.js). */
.portal-deal-detail-flag-warning {
  background: var(--warning-bg) !important;
  border-color: var(--warning-border) !important;
  color: var(--warning) !important;
}

.portal-deal-detail-flag-danger {
  background: var(--danger-bg) !important;
  border-color: var(--danger-border) !important;
  color: var(--danger) !important;
}

/* Bottom two-column layout: activity feed on the left, secondary widgets
   stacked on the right — built by portal-overrides.js, which moves the
   existing activity card into .portal-bottom-left and appends the new
   widgets to .portal-bottom-right. */
/* Same fix as .portal-overview-metrics above: fill the gutter between the
   two bottom columns with a solid panel so the grid doesn't show through it. */
.portal-bottom-grid {
  display: grid;
  grid-template-columns: minmax(0, 3fr) minmax(0, 2fr);
  gap: 1rem;
  /* stretch (not start): lets .portal-repayments-card below grow to reach
     the same bottom edge as Последние события instead of stopping short
     at its own natural content height. */
  align-items: stretch;
  /* No extra margin here — the 1rem bottom padding on .portal-overview-card
     above is the only gap source now, matching .portal-overview-metrics's
     own 1rem row-gap so the rhythm is consistent top to bottom instead of
     compounding into a bigger gap right before this block. */
  margin-top: 0;
  padding: 1.25rem;
  border-radius: 16px;
  background: linear-gradient(180deg, rgba(var(--ov-tint-rgb), 0.035), rgba(var(--ov-tint-rgb), 0.015)), var(--ov-surface-bg-alt);
  border: 1px solid rgba(var(--ov-tint-rgb), 0.08);
  box-shadow:
    0 24px 44px rgba(0, 0, 0, calc(0.3 * var(--ov-shadow-scale))),
    inset 0 1px 0 rgba(var(--ov-tint-rgb), 0.08);
}

.portal-bottom-left,
.portal-bottom-right {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  min-width: 0;
}

.portal-widget-title {
  margin: 0 0 0.85rem;
  font-size: 0.95rem;
  font-weight: 600;
  color: var(--ov-text);
}

/* "Требует внимания" / "Ближайшие погашения" are not themselves clickable —
   only the action button and list rows inside them are — so no hover
   motion, but now the same color recipe as Последние события /
   Всего профинансировано (was its own separate var(--ov-surface-bg-alt) recipe before). The
   warning semantic for attention items lives on the action button, not
   the card. */
.portal-attention-card,
.portal-repayments-card {
  border: 1px solid rgba(var(--ov-tint-rgb), 0.16) !important;
  background: linear-gradient(145deg, rgba(var(--ov-tint-rgb), 0.075), rgba(var(--ov-tint-rgb), 0.025)), var(--ov-surface-bg) !important;
  box-shadow:
    inset 0 1px 0 rgba(var(--ov-tint-rgb), 0.14),
    0 18px 48px rgba(0, 0, 0, calc(0.16 * var(--ov-shadow-scale))) !important;
}

/* Grows to close the gap down to Последние события's bottom edge (see
   align-items:stretch on .portal-bottom-grid above) instead of stopping at
   its own short, 3-row natural height. Требует внимания above it (if
   present) keeps its own natural height — only this one absorbs the
   stretched space. */
.portal-repayments-card {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-height: 0;
}

.portal-attention-card:hover,
.portal-repayments-card:hover {
  transform: none !important;
  background: linear-gradient(145deg, rgba(var(--ov-tint-rgb), 0.075), rgba(var(--ov-tint-rgb), 0.025)), var(--ov-surface-bg) !important;
  box-shadow:
    inset 0 1px 0 rgba(var(--ov-tint-rgb), 0.14),
    0 18px 48px rgba(0, 0, 0, calc(0.16 * var(--ov-shadow-scale))) !important;
}

.portal-attention-list,
.portal-repayments-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.85rem;
}

/* Grows with .portal-repayments-card (see above) and scrolls internally
   once its content is taller than the space that stretch gives it —
   .portal-attention-list keeps its own natural, un-scrolled height. */
.portal-repayments-list {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  padding-right: 10px;
  scrollbar-width: thin;
  scrollbar-color: rgba(var(--ov-tint-rgb), 0.22) rgba(var(--ov-tint-rgb), 0.06);
}

/* Same thin, rounded scrollbar recipe as the landing page's apply-form
   file list (.apply-form .file-list-items), for a consistent look
   wherever a scroll appears in this app. */
.portal-repayments-list::-webkit-scrollbar {
  width: 5px;
}

.portal-repayments-list::-webkit-scrollbar-track {
  background: rgba(var(--ov-tint-rgb), 0.06);
  border-radius: 999px;
}

.portal-repayments-list::-webkit-scrollbar-thumb {
  background: rgba(var(--ov-tint-rgb), 0.22);
  border-radius: 999px;
}

.portal-attention-item {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.5rem;
  padding-bottom: 0.85rem;
  border-bottom: 1px solid rgba(var(--ov-tint-rgb), 0.06);
}

.portal-attention-item:last-child {
  border-bottom: 0;
  padding-bottom: 0;
}

.portal-attention-text {
  margin: 0;
  font-size: 0.85rem;
  color: rgba(var(--ov-muted-rgb), 0.9);
}

.portal-attention-action {
  font-size: 0.78rem;
  font-weight: 600;
  color: var(--warning);
  border: 1px solid var(--warning-border);
  border-radius: 8px;
  padding: 0.35rem 0.7rem;
  text-decoration: none;
  transition: background 0.2s ease;
}

.portal-attention-action:hover {
  background: var(--warning-bg);
}

.portal-repayment-row {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 0.15rem 0.5rem;
  font-size: 0.82rem;
  padding-bottom: 0.6rem;
  border-bottom: 1px solid rgba(var(--ov-tint-rgb), 0.06);
}

.portal-repayment-row:last-child {
  border-bottom: 0;
  padding-bottom: 0;
}

.portal-repayment-obligor {
  grid-column: 1;
  color: var(--ov-text);
  font-weight: 500;
}

.portal-repayment-amount {
  grid-column: 2;
  grid-row: 1;
  color: var(--ov-text);
  font-weight: 600;
  text-align: right;
}

.portal-repayment-date {
  grid-column: 1 / -1;
  color: rgba(var(--ov-muted-rgb), 0.55);
  font-size: 0.75rem;
}

.portal-repayment-overdue .portal-repayment-obligor,
.portal-repayment-overdue .portal-repayment-amount {
  color: var(--warning);
}

.portal-repayment-overdue .portal-repayment-date {
  color: var(--warning);
  font-weight: 600;
}

/* Activity feed color-coding: warnings/overdue and success events get a
   semantic accent so money-relevant items stand out from routine ones. */
.portal-feed-warning,
.portal-feed-success {
  border-radius: 10px;
  padding: 0.4rem 0.5rem;
  margin: 0 -0.5rem;
}

.portal-feed-warning {
  background: var(--warning-bg);
}

.portal-feed-warning svg {
  color: var(--warning) !important;
}

.portal-feed-warning > div:first-child {
  background: var(--warning-bg) !important;
}

.portal-feed-success {
  background: var(--success-bg);
}

.portal-feed-success svg {
  color: var(--success) !important;
}

.portal-feed-success > div:first-child {
  background: var(--success-bg) !important;
}

@media (max-width: 900px) {
  .portal-bottom-grid {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .portal-overview-header {
    flex-direction: column;
    align-items: flex-start;
  }

  .portal-overview-metrics {
    grid-template-columns: 1fr;
  }
}

/* Page root is native max-w-5xl (1024px) — was already widened 15% to
   1178px, this is another 10% on top of that (1178 * 1.1 ≈ 1296px), same
   page-specific override pattern as .portal-new-application-page's own
   max-width. */
.portal-deals-page {
  max-width: 1296px !important;
}

/* "Мои сделки": reads as one dense table frame, matching Архив's actual
   <table>, instead of a stack of individually-rounded cards with gaps
   between them (see applyDealsTheme in portal-overrides.js — same dark
   card recipe used everywhere else in this file). */
.portal-deals-table {
  border-radius: 12px;
  border: 1px solid rgba(var(--ov-tint-rgb), 0.16);
  background: linear-gradient(145deg, rgba(var(--ov-tint-rgb), 0.075), rgba(var(--ov-tint-rgb), 0.025)), var(--ov-surface-bg);
  box-shadow:
    inset 0 1px 0 rgba(var(--ov-tint-rgb), 0.14),
    0 18px 48px rgba(0, 0, 0, calc(0.16 * var(--ov-shadow-scale)));
  overflow: hidden;
}

/* Extra left padding here reserves the same gutter width the chevron
   overlay below claims on each row (2rem, matching Архив's own w-8
   chevron column) — otherwise these header labels would sit 2rem left
   of the data they label, since both share the same grid template. */
.portal-deals-header {
  margin: 0;
  padding: 0.85rem 1.25rem 0.85rem 2rem;
  border-bottom: 1px solid rgba(var(--ov-tint-rgb), 0.18);
}

/* Removes the gap-3 between row-cards so they sit flush against each
   other, like a table's rows. */
.portal-deals-list {
  gap: 0;
}

/* The divider/hover live on .portal-deals-list's actual direct children —
   the <a> Link wrapping each deal's Card, one level above the Card itself
   (list-deals > Link > Card[data-testid=card-deal-N]). Putting :last-child
   on the Card directly was the bug in the previous version: a Card is
   always the only/last child of its own Link, so that rule matched every
   single row instead of just the final one, cancelling the border-bottom
   everywhere. */
.portal-deals-list > * {
  display: block;
  border-bottom: 1px solid rgba(var(--ov-tint-rgb), 0.18);
  transition: background 0.15s ease;
}

.portal-deals-list > *:last-child {
  border-bottom: none;
}

.portal-deals-list > *:hover {
  background: rgba(var(--ov-tint-rgb), 0.04);
}

/* Very faint full-row tint for Дефолт/Просрочка (tagDealRowSeverity in
   portal-overrides.js) — deliberately subtler than the status badge itself,
   just enough that the eye catches these rows scanning down the list
   without the row reading as "loud" or fighting the badge for attention. */
.portal-deal-row-danger {
  background: rgba(229, 72, 77, 0.055);
}

.portal-deal-row-warning {
  background: rgba(217, 122, 52, 0.055);
}

.portal-deal-row-danger:hover {
  background: rgba(229, 72, 77, 0.09);
}

.portal-deal-row-warning:hover {
  background: rgba(217, 122, 52, 0.09);
}

/* Flattens each deal's own card (rounded-xl border shadow) to a plain
   transparent box — the row's actual border/hover now come from the Link
   wrapper above — without touching its Link/click behavior. */
.portal-deals-list [data-testid^="card-deal-"] {
  border-radius: 0 !important;
  border: 0 !important;
  box-shadow: none !important;
  background: transparent !important;
}

/* Moves the row's chevron (data grid's last item, native class
   justify-self-end, confirmed from the compiled component) to the start
   of the row instead of the end — matching Архив's own chevron column,
   which sits before ID. Done as a reserved-gutter + absolute-position
   overlay rather than reordering the grid, so the other 7 columns keep
   their exact original grid-column tracks (shared with the header row's
   own template) instead of every column needing to shift over one slot. */
.portal-deals-list [data-testid^="card-deal-"] > div {
  position: relative;
  padding-left: 2rem !important;
}

.portal-deals-list [data-testid^="card-deal-"] > div > .justify-self-end {
  position: absolute;
  left: 0.75rem;
  top: 50%;
  transform: translateY(-50%);
}

/* Column widths: 8 visible tracks — ID, Дебитор, Сумма, Ставка, Погашение,
   Отсчёт (see ensureDealCountdownCell in portal-overrides.js), Статус, and
   a near-zero trailing track that sizes the chevron before it moves to the
   left overlay (see the rule below this one). The chevron's own 32px is
   spent as this row's padding-left, not a real leading grid track — it's
   the row's last DOM child (native justify-self-end), and overlaying it
   into a reserved gutter avoids reordering the grid itself (see the
   comment above). Срок is dropped from the visible list entirely
   (hideDealTermCell adds .portal-deal-term-cell, display:none below) — a
   display:none child isn't a grid item at all, so the remaining 8 visible
   children auto-place into these 8 tracks in DOM order with no gap left
   behind.
   ID/Сумма/Ставка/Погашение/Отсчёт are plain fixed widths — their content
   is short and doesn't vary in length. Дебитор (minmax(200px, 2fr)) and
   Статус (minmax(180px, 1fr)) are the two columns with genuinely variable-
   length content (obligor names; badge text from "Дефолт" to "Ожидает
   загрузки документов") — both flexible so leftover width lands there
   instead of as dead space past the last column, weighted 2:1 towards
   Дебитор since obligor names run longer than status labels. Their floors
   (200px/180px) are a hard lower bound: if the table itself ever gets
   narrower than the sum of every column's floor, the row overflows
   (scrolls) instead of these two shrinking past what their own content
   needs. Shared by the header row and every data row (both use this exact
   template — see NS in the compiled component) so columns stay aligned. */
.portal-deals-header,
.portal-deals-list [data-testid^="card-deal-"] > div {
  grid-template-columns: 110px minmax(200px, 2fr) 130px 90px 100px 150px minmax(180px, 1fr) 2px !important;
  column-gap: 0.375rem !important;
  justify-content: start !important;
}

.portal-deals-list [data-testid^="card-deal-"] > div {
  padding-right: 0.5rem !important;
}

.portal-deals-list [data-testid^="text-deal-id-"] {
  overflow: visible;
  text-overflow: clip;
}

/* Дебитор (grid column 2 — ID is 1, see the template above): min-width:0
   overrides the grid default (min-width:auto, sized to fit the text
   unshrunk) that would otherwise block truncation outright. Ellipsis
   covers names too long even for the 2fr share; ensureDealObligorTooltip
   in portal-overrides.js sets title= with the full name so it's still
   readable on hover when that happens. */
.portal-deals-list [data-testid^="card-deal-"] > div > *:nth-child(2) {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Статус badge text (e.g. "Ожидает загрузки документов") must stay on one
   line — the 180px floor above was sized for exactly this, but only holds
   if the badge itself doesn't wrap first. */
.portal-deals-list [data-testid^="badge-status-"] {
  white-space: nowrap;
}

/* Table's own rendered width (not the viewport) drives this — same numbers
   regardless of what's eating space beside it (nav rail, page padding).
   Below this, Отсчёт is the one column allowed to give up space: Дебитор
   and Статус keep their floors from the template above, everything else
   is already a content-sized minimum. 130px still fits "просрочено 60
   дн." / "пеня AED 3,240" (the longest realistic pair) on their own lines
   at the smaller font-size below — narrower than that risks wrapping the
   penalty line, which is the one thing here that must never truncate. */
.portal-deals-table {
  container-type: inline-size;
  container-name: portal-deals-table;
}

@container portal-deals-table (max-width: 1120px) {
  .portal-deals-header,
  .portal-deals-list [data-testid^="card-deal-"] > div {
    grid-template-columns: 110px minmax(200px, 2fr) 130px 90px 100px 130px minmax(180px, 1fr) 2px !important;
  }

  .portal-deal-countdown {
    padding-left: 8px;
  }

  .portal-deal-countdown-days {
    font-size: 0.72rem;
  }

  .portal-deal-countdown-penalty {
    font-size: 0.66rem;
  }
}

/* ---- "Архив": identical look to "Мои сделки" above, on a real native
   <table> (shadcn Table primitives — see applyArchiveTheme in
   portal-overrides.js) rather than Мои сделки's CSS-grid div cards. No
   markup to share a selector between the two, so the frame recipe below
   is copied verbatim from .portal-deals-table rather than reused from it.
   Where a column exists in both (ID/Дебитор/Сумма/Ставка), it now uses
   the exact same px width as Мои сделки too (see the per-column widths
   further down) — Архив's own extra columns (settlement figures Мои
   сделки has no equivalent for) render in the same style regardless. */
.portal-archive-table {
  border-radius: 12px !important;
  border: 1px solid rgba(var(--ov-tint-rgb), 0.16) !important;
  background: linear-gradient(145deg, rgba(var(--ov-tint-rgb), 0.075), rgba(var(--ov-tint-rgb), 0.025)), var(--ov-surface-bg) !important;
  box-shadow:
    inset 0 1px 0 rgba(var(--ov-tint-rgb), 0.14),
    0 18px 48px rgba(0, 0, 0, calc(0.16 * var(--ov-shadow-scale))) !important;
  overflow: hidden;
}

/* ---- Rotate-to-landscape prompt: Мои сделки / Архив on a portrait phone ----
   Same idea as the landing page's own invoice table (.rotate-hint /
   .landscape-modal-open in style.css + main.js) — both tables are wide by
   nature (7-8 columns) and previously only fit a portrait phone by
   scrolling sideways with no visual cue that more content sat off-screen.
   Rather than that landing-page implementation's approach (a JS-driven
   fullscreen overlay it reparents DOM nodes into on 'orientationchange'),
   this is plain CSS: ensureRotateHint in portal-overrides.js inserts the
   hint once as a plain sibling right before the table card, and which one
   is visible is entirely driven by these (max-width:960px) portrait/
   landscape media queries — no JS orientation listener needed, and it
   can't drift out of sync with the CSS. */
.portal-rotate-hint {
  display: none;
}

@media (max-width: 960px) and (orientation: portrait) {
  .portal-rotate-hint {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 16px;
    padding: 48px 24px 52px;
    text-align: center;
    border-radius: 12px;
    border: 1px solid rgba(var(--ov-tint-rgb), 0.16);
    background: linear-gradient(145deg, rgba(var(--ov-tint-rgb), 0.075), rgba(var(--ov-tint-rgb), 0.025)), var(--ov-surface-bg);
  }

  .portal-rotate-hint-phone {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 72px;
    height: 72px;
  }

  .portal-rotate-hint-phone svg {
    width: 36px;
    height: auto;
    color: rgba(244, 210, 132, 0.9);
    animation: portal-rotate-hint-phone 2.4s ease-in-out infinite;
    transform-origin: center center;
  }

  @keyframes portal-rotate-hint-phone {
    0%, 15%  { transform: rotate(0deg); }
    55%, 80% { transform: rotate(90deg); }
    100%     { transform: rotate(0deg); }
  }

  .portal-rotate-hint-text {
    margin: 0;
    font-size: 16px;
    font-weight: 600;
    color: var(--ov-text);
    line-height: 1.3;
  }

  .portal-rotate-hint-sub {
    margin: -8px 0 0;
    font-size: 12px;
    color: rgba(var(--ov-muted-rgb), 0.6);
    line-height: 1.5;
  }

  /* The table/list card itself, not the hint, is what steps aside here —
     both cards keep their normal (scrollable, wide) layout at every other
     breakpoint; only this exact portrait phone case swaps one for the
     other. */
  .portal-deals-table,
  .portal-archive-table {
    display: none;
  }
}

/* ---- Landscape: no sideways scroll, real content instead ----
   The hint above only ever shows in portrait — here the actual table
   is what's visible, refit to actually fill a landscape phone's width
   (not the 940px/1297px desktop content the pre-scroll era relied on
   scrolling to reach) so it needs no horizontal scroll of its own. */
@media (max-width: 960px) and (orientation: landscape) {
  /* Below the md breakpoint (768px) shadcn's Sidebar renders as the
     mobile Sheet (.fixed, its own open/close handled elsewhere in this
     file) — but plenty of real phones are wider than 768px in landscape
     (iPhone 13: 390 portrait -> 844 landscape) while still very much
     being a phone, not a tablet. At that width the component instead
     renders its *desktop* variant: a permanent, always-visible rail
     that isn't a drawer at all, so there's no "closing" it — it just
     sits there eating ~256px that a landscape phone doesn't have to
     spare, which is exactly the ~500-600px squeeze the column widths a
     few rules down were built around. Tried making it collapse to its
     own icon-only rail state instead of hiding it outright (shadcn's
     Sidebar does support that) — its own logo/label header doesn't
     participate in that collapse, so "Factor0x" just overflowed a 48px
     rail into the content next to it. Hiding it outright avoids that
     bug entirely; main already flexes to fill the freed width on its
     own, confirmed directly, no extra margin/width rule needed. */
  [data-slot="sidebar"]:not(.fixed) {
    display: none !important;
  }

  .portal-deals-page .overflow-x-auto,
  .portal-archive-table {
    overflow-x: hidden !important;
  }

  /* Мои сделки: the desktop template's two flexible tracks — Дебитор
     (min 200px) and Статус (min 180px) — are genuine floors a CSS grid
     won't shrink below, and the five fixed tracks alone already total
     580px; there's no landscape phone width that fits the desktop
     template. Dropping both floors to minmax(0, Nfr) is what lets the
     *tracks* shrink — but .portal-deals-table (the grid rows' own
     ancestor) carries a separate, native min-w-[940px] Tailwind class of
     its own, a hard floor on the *container*. Without also overriding
     that, the grid still had 940px to distribute across these smaller
     tracks (confirmed directly: the 2fr/1fr tracks resolved to ~355px/
     ~177px, exactly what 940px minus the fixed tracks splits to, not
     what the ~600-800px landscape viewport actually left available) — no
     visible scrollbar since overflow-x is hidden here, just the Статус/
     Отсчёт columns silently cut off past the viewport edge. Smaller fixed
     tracks + font-size below keep the short columns (ID/Сумма/Ставка/
     Погашение) readable at the width that leaves for them.

     Статус is fixed px here, not a second fr share like desktop — a
     landscape phone with the (still md+ width) persistent nav rail
     showing leaves as little as ~520px total for all 8 columns; splitting
     the leftover 2-3 ways gave Статус as little as ~39px, nowhere near
     enough for its own badge + padding (confirmed directly — that's what
     produced the "FinancedDefault" run-together text). Дебитор is the
     one column that actually degrades gracefully when squeezed (ellipsis
     + a title= tooltip fallback, already in place), so it's the only
     one left as minmax(0, 1fr), absorbing whatever the fixed columns
     (now including Статус) don't need. */
  .portal-deals-table {
    min-width: 0 !important;
    width: 100% !important;
  }

  .portal-deals-header,
  .portal-deals-list [data-testid^="card-deal-"] > div {
    grid-template-columns: 58px minmax(0, 1fr) 62px 48px 56px 68px 82px 2px !important;
    column-gap: 4px !important;
  }

  /* Header labels are plain <span>s with no width/overflow handling of
     their own (fine on desktop, where every track has room to spare) —
     "Repayment" and "Countdown" are two separate spans that, once their
     tracks shrink to 64px/78px, each render past their own column with no
     clipping and visually run together with zero gap between them, same
     underlying issue as .portal-deal-countdown's overflow above. */
  .portal-deals-header > * {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  /* Same clipping backstop on every data row's own cells (ID/Сумма/Ставка/
     Погашение — Дебитор/Отсчёт/Статус already have their own more
     specific handling above/below): at these track widths, "AED 128,000"
     runs right up against the column edge with nothing to spare, and
     without a hard clip it visibly bleeds into Ставка next to it. */
  .portal-deals-list [data-testid^="card-deal-"] > div > * {
    overflow: hidden;
    text-overflow: ellipsis;
  }

  .portal-deals-header,
  .portal-deals-list [data-testid^="card-deal-"] > div,
  .portal-deals-list [data-testid^="badge-status-"] {
    font-size: 11px !important;
  }

  .portal-deals-list [data-testid^="badge-status-"] {
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 100%;
    padding: 3px 6px !important;
  }

  /* Статус's own cell (8th child of the row — see the grid-template
     comment above) can carry more than just the badge: a stage word and
     an overdue/late-fee caption alongside it, same "align-items doesn't
     stretch its children to the cell's width" shape as .portal-deal-
     countdown above. overflow:hidden on the cell itself is the backstop —
     whatever's inside stays visually clipped to its 82px track instead of
     spilling past the row's right edge. */
  .portal-deals-list [data-testid^="card-deal-"] > div > :nth-child(8) {
    overflow: hidden;
  }

  /* .portal-deal-countdown (the grid cell itself) sizes correctly to its
     78px track (min-width:0 already handles that), but its own
     align-items:center means ITS children size to their own natural
     content width rather than being capped to the cell — "overdue 60
     days" / "late fee AED 3,240" both render wider than 78px regardless,
     and since the cell's own overflow-x is visible (desktop has room, so
     this was never a problem there), that overflow spills out over
     Статус instead of being clipped. Each line's own overflow:hidden +
     text-overflow:ellipsis (already set, see the base rule) only engages
     once something actually caps its width — max-width:100% here is that
     cap, resolved against the (correctly 78px) parent. */
  .portal-deal-countdown-days,
  .portal-deal-countdown-penalty {
    max-width: 100%;
  }

  .portal-deal-countdown-days {
    font-size: 0.66rem;
  }

  .portal-deal-countdown-penalty {
    font-size: 0.6rem;
  }

  /* Архив: same underlying issue, different mechanism — table-layout:fixed
     treats each column's explicit px width (32/115/420/140/100/125/135/130/
     100, summing to 1297px) as a hard floor the table can't shrink below
     no matter what its own width/max-width is set to (confirmed directly:
     even an inline width:356px!important on the <table> itself was
     ignored while those px column widths stood). Percentages aren't a
     floor — they're a share of the table's own resolved width — so
     switching to percentages is what actually lets the whole table
     compress to fit a landscape phone. Weighted by each column's real
     content (see the 0-based index comment on ensureArchiveRowFormatted
     above — nth-child is that index + 1): Комиссия/Вы получили (7/8) are
     "AED 9,250" / "AED 175,750" in full, not the abbreviated Сумма/Ставка
     figures, so they need more room than a proportional share of the
     original 125px/135px would give them — confirmed by first rendering
     this with a mechanical proportional split, which wrapped "AED 9,250"
     mid-word into an unreadable "D 9,250" line break. Дебитор gives up
     the most (18%) — its own ellipsis (already in place) is what a long
     company name degrades to, unlike a date or number that needs to stay
     on one line intact. Дата закрытия (12, 7% -> 10%) was the one column
     that still didn't have room for its own "09.05.26" once the sidebar
     started hiding in this same landscape breakpoint (see the rule at
     the top of this file) freed up real width to redistribute — 7% of
     even a same-page-wider table still clipped the date value itself,
     not just its header, into "09.05...". */
  .portal-archive-table thead th:nth-child(1),
  .portal-archive-table tbody td:nth-child(1) { width: 3% !important; }
  .portal-archive-table thead th:nth-child(2),
  .portal-archive-table tbody td:nth-child(2) { width: 9% !important; }
  .portal-archive-table thead th:nth-child(3),
  .portal-archive-table tbody td:nth-child(3) { width: 18% !important; }
  .portal-archive-table thead th:nth-child(4),
  .portal-archive-table tbody td:nth-child(4) { width: 12% !important; }
  .portal-archive-table thead th:nth-child(5),
  .portal-archive-table tbody td:nth-child(5) { width: 8% !important; }
  .portal-archive-table thead th:nth-child(7),
  .portal-archive-table tbody td:nth-child(7) { width: 13% !important; }
  .portal-archive-table thead th:nth-child(8),
  .portal-archive-table tbody td:nth-child(8) { width: 14% !important; }
  .portal-archive-table thead th:nth-child(11),
  .portal-archive-table tbody td:nth-child(11) { width: 13% !important; }
  .portal-archive-table thead th:nth-child(12),
  .portal-archive-table tbody td:nth-child(12) { width: 10% !important; }

  /* The "Как рассчитано" (i) tooltip-trigger buttons on Ставка/Комиссия/
     Вы получили exist to explain the calculation behind each figure — a
     nice-to-have popover, not the figure itself. At this width they're
     what push "AED 9,250" into wrapping onto an unreadable second line;
     dropping them (chevron-expand's own icon isn't a button, untouched)
     gives that text the few extra px it needs to stay on one line. */
  .portal-archive-table [data-testid="table-archive"] td button {
    display: none;
  }

  /* Комиссия's own second line (the rate the fee was computed at) is
     already shown in full one column over, in Ставка — dropping the
     repeat here is the same "give up the least-needed thing first"
     tradeoff as Дебитор's shrink above, not an information loss. */
  .portal-archive-table [data-testid="table-archive"] tbody td:nth-child(7) > div > div > div:last-child {
    display: none;
  }

  .portal-archive-table [data-testid="table-archive"] th,
  .portal-archive-table [data-testid="table-archive"] td {
    padding: 6px 5px !important;
    font-size: 11px !important;
    overflow: hidden;
    text-overflow: ellipsis;
  }

  .portal-archive-table [data-testid="table-archive"] th {
    font-size: 9.5px !important;
  }
}

/* Page root — 1400px, 8% wider than .portal-deals-page's 1296px (a later,
   Архив-specific request; the two pages no longer share a width). Table
   itself is width:100% (see below) with table-layout:fixed, so widening
   this alone stretches every column proportionally along with it — no
   need to touch the per-column widths further down to match. */
.portal-archive-page {
  max-width: 1400px !important;
}

/* Срок / Дни просрочки / Пеня за просрочку (columns 6/9/10 of the
   original 12) dropped from the collapsed row entirely — 11 columns (12
   with the chevron) is what was overlapping "ПЕНЯ ЗА ПРОСРОЧКУ" into
   "СТАТУС" in the first place, and all three are already in the expanded
   detail row (Срок in "Расчёт", both others in "Была просрочка платежа" —
   see X_ in the compiled component, untouched). Still real <td>/<th>
   elements at these DOM positions (ensureArchiveRowFormatted in
   portal-overrides.js still reads/reformats column 6's text, harmlessly,
   for the same reason it always did) — just display:none, so every
   nth-child index below and in the rest of this file still lines up with
   the *original* 12-column position, not a renumbered 9. */
.portal-archive-table thead th:nth-child(6),
.portal-archive-table tbody td:nth-child(6),
.portal-archive-table thead th:nth-child(9),
.portal-archive-table tbody td:nth-child(9),
.portal-archive-table thead th:nth-child(10),
.portal-archive-table tbody td:nth-child(10) {
  display: none;
}

/* Explicit per-column widths for the 8 that remain (plus the chevron) —
   same idea as Мои сделки's grid-template-columns but expressed as a real
   <table>'s own column widths (table-layout:fixed makes a nth-child width
   apply to the whole column, not just one cell). Дебитор gets the bulk of
   what Срок/Дни просрочки/Пеня freed up — 420px comfortably fits a full
   legal name ("Carrefour UAE (Majid Al Futtaim Hypermarkets LLC)") on one
   line; ellipsis + title= below is still there for anything longer. These
   sum to ~1297px on their own, less than .portal-archive-page's 1400px —
   table-layout:fixed with the table itself at width:100% (below) scales
   every column up proportionally to fill the difference, so the ratios
   here still hold even though the raw px numbers no longer sum to the
   page width exactly. box-sizing:border-box (below) makes each width
   include its own padding, so these numbers are the full column, not
   content-only. */
.portal-archive-table [data-testid="table-archive"] {
  table-layout: fixed;
  width: 100%;
}

.portal-archive-table [data-testid="table-archive"] th,
.portal-archive-table [data-testid="table-archive"] td {
  box-sizing: border-box;
}

.portal-archive-table thead th:nth-child(1),
.portal-archive-table tbody td:nth-child(1) {
  width: 32px;
}

.portal-archive-table thead th:nth-child(2),
.portal-archive-table tbody td:nth-child(2) {
  width: 115px;
}

.portal-archive-table thead th:nth-child(3),
.portal-archive-table tbody td:nth-child(3) {
  width: 420px;
}

.portal-archive-table thead th:nth-child(4),
.portal-archive-table tbody td:nth-child(4) {
  width: 140px;
}

.portal-archive-table thead th:nth-child(5),
.portal-archive-table tbody td:nth-child(5) {
  width: 100px;
}

.portal-archive-table thead th:nth-child(7),
.portal-archive-table tbody td:nth-child(7) {
  width: 125px;
}

.portal-archive-table thead th:nth-child(8),
.portal-archive-table tbody td:nth-child(8) {
  width: 135px;
}

.portal-archive-table thead th:nth-child(11),
.portal-archive-table tbody td:nth-child(11) {
  width: 130px;
}

.portal-archive-table thead th:nth-child(12),
.portal-archive-table tbody td:nth-child(12) {
  width: 100px;
}

/* Single-line by default everywhere (fixes ID "DEAL-" / "0009" wrapping
   once its column above is narrow and fixed-width) — Дебитор is the
   deliberate exception, ellipsis instead of nowrap-and-overflow so a name
   too long even for 420px degrades the same way Мои сделки's own Дебитор
   does (see ensureArchiveRowFormatted in portal-overrides.js for the
   matching title= hover fallback). Once no visible cell wraps, every
   row's height is driven by the same single line of text (Комиссия's own
   two stacked lines are the tallest, consistently, on every row) — that's
   what makes row heights uniform. */
.portal-archive-table [data-testid="table-archive"] th,
.portal-archive-table [data-testid="table-archive"] td {
  white-space: nowrap;
}

.portal-archive-table tbody td:nth-child(3) {
  /* Native <td> here carries no color class at all (unlike Мои сделки's
     own Дебитор, which is text-muted-foreground) — full-brightness
     --foreground by default, visibly lighter than the same company names
     one tab over. Matched to the exact same token instead. */
  color: hsl(var(--muted-foreground));
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Тёплая подсветка просроченных строк reuses .portal-deal-row-warning
   itself (already a plain, unscoped rule further up — applies to any
   element with the class, <tr> included; see ensureArchiveRowFormatted in
   portal-overrides.js for how a row earns it) — only the :hover variant
   needs repeating here, to win against .portal-archive-table's own
   generic tbody tr:hover !important above. Архив has no equivalent to
   Дефолт (a closed deal is always "Погашена" regardless of how it got
   there), so only the warning tone ever applies here. */
.portal-archive-table tbody tr.portal-deal-row-warning:hover {
  background: rgba(217, 122, 52, 0.09) !important;
}

/* Same row divider/hover tone as .portal-deals-list > * above — native
   TableRow already ships border-b/hover:bg-muted/50, this just repoints
   both at the exact same rgba values instead of trusting the theme's
   --border/--muted vars to land on the same tone by coincidence. */
.portal-archive-table tbody tr {
  border-bottom: 1px solid rgba(var(--ov-tint-rgb), 0.18) !important;
}

/* Native TableBody already drops the last row's border ([&_tr:last-child]
   in the compiled component) — matched here so the !important above
   doesn't reinstate it. Expanding a row inserts its detail <tr> right
   after it, so "last child" only ever means the true last summary row. */
.portal-archive-table tbody tr:last-child {
  border-bottom: none !important;
}

.portal-archive-table tbody tr:hover {
  background: rgba(var(--ov-tint-rgb), 0.04) !important;
}

/* Headers centered like Мои сделки's. Мои сделки's own header row gets
   its caps from a native "uppercase tracking-wide" class already baked
   into that component — Архив's TableHead has no such class, so it's
   added explicitly here instead. */
.portal-archive-table thead th {
  text-align: center;
  text-transform: uppercase;
  letter-spacing: 0.025em;
  font-size: 0.75rem;
}

/* Value cells for Сумма инвойса / Статус / Дата закрытия (columns 4/11/12
   of 12) are plain text or a single inline-flex badge, so text-align on
   the cell itself is enough. Ставка/мес / Комиссия / Вы получили (5/7/8)
   each render their value as a block-level "flex items-center gap-1.5"
   row (rate or amount, plus a tooltip icon) that fills the full cell
   width — text-align doesn't affect a block flex box's own children, so
   these need justify-content on that row instead. */
.portal-archive-table tbody td:nth-child(4),
.portal-archive-table tbody td:nth-child(11),
.portal-archive-table tbody td:nth-child(12) {
  text-align: center;
}

.portal-archive-table tbody td:nth-child(5) > *,
.portal-archive-table tbody td:nth-child(7) > *,
.portal-archive-table tbody td:nth-child(8) > * {
  justify-content: center;
}

/* Header labels read as centered captions over their column — Сумма
   инвойса included now (was the one right-aligned exception; a later,
   more specific instruction to center every value column below,
   including this one, replaces that). !important: Ставка/мес and
   Погашение's <span> still carry the native text-right class too — this
   already won for Сумма инвойса's own text-right span (a longer label,
   filling most of the column either way, so the miscentering was hard to
   spot there), but visibly lost for these two shorter ones. */
.portal-deals-header > * {
  text-align: center !important;
}

/* Value cells for Сумма инвойса / Ставка/мес / Погашение / Отсчёт /
   Статус, centered to match their now-centered headers above. Each needs
   a different property because each renders differently: Сумма/Погашение
   are plain right-aligned text (text-align), Ставка is a "flex ...
   justify-end" row (justify-content), Отсчёт is this file's own flex-
   column .portal-deal-countdown (align-items, its cross axis), Статус is
   a "flex flex-wrap items-center gap-2" row holding the badge (+ overdue
   note below it, when present) — align-items centers both rows as a
   block instead of stretching them to the column's full width. */
.portal-deals-list [data-testid^="card-deal-"] > div > *:nth-child(3),
.portal-deals-list [data-testid^="card-deal-"] > div > *:nth-child(5) {
  text-align: center !important;
}

.portal-deals-list [data-testid^="card-deal-"] > div > *:nth-child(4) {
  justify-content: center !important;
}

.portal-deals-list [data-testid^="card-deal-"] > div > *:nth-child(7) {
  align-items: center;
}

/* Every row is back to a single content line now that the overdue note has
   its own column instead of wrapping under the status badge — this is just
   a comfortable padding floor, not what forces rows to match anymore. */
.portal-deals-list [data-testid^="card-deal-"] > div {
  min-height: 3rem;
}

/* Срок ("30 days") — hidden in the list to make room for Отсчёт; still
   visible in the deal's own detail view. */
.portal-deal-term-cell {
  display: none;
}

/* Отсчёт: "просрочено N дн." on its own line so it never has to fight the
   penalty amount for space on one line (that's what was truncating it) —
   the penalty gets a second, smaller line underneath instead. min-height
   here reserves that two-line height on EVERY row, not just flagged ones,
   so a normal deal's single "через N дн." line still takes up the same
   vertical space as a flagged deal's two lines — without this, only
   flagged rows would grow, reintroducing the uneven-row-height problem.
   Used to also have a left border as a visual seam against Погашение —
   dropped, it read as visual clutter once every column centered. */
.portal-deal-countdown {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  text-align: center;
  gap: 1px;
  min-width: 0;
  min-height: 2.1rem;
  font-size: 0.78rem;
}

.portal-deal-countdown-days {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.portal-deal-countdown-penalty {
  font-size: 0.7rem;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  opacity: 0.78;
}

/* "Через N дн." when the due date is close but not yet overdue — a muted
   amber, deliberately softer than Просрочка's full-strength warning color
   (that one's an actual problem; this is just "coming up soon"). */
.portal-deal-countdown-soon {
  color: var(--warning);
  opacity: 0.8;
}

/* Shared floating tooltip (see attachDealTooltip in portal-overrides.js) —
   one node appended straight to <body> and positioned via
   getBoundingClientRect on open, used by the New Application autofill
   note's "i" and every Статус badge below. Fixed positioning means it's
   never clipped by a rounded card's own overflow:hidden (e.g.
   .portal-deals-table needs that for its corners) the way a nested
   position:absolute child inside the trigger used to be. Colors are
   explicit here rather than the app's own bg-popover/text-popover-
   foreground tokens — those default to a plain white/near-black pair with
   no dark-mode override anywhere in the compiled app, which is its own
   separate light-popup-on-a-dark-page bug this happens to sidestep. */
.portal-floating-tip {
  position: fixed;
  z-index: 9999;
  width: 288px;
  max-width: calc(100vw - 16px);
  padding: 14px 16px;
  border-radius: 10px;
  background: var(--ov-tooltip-bg);
  border: 1px solid rgba(var(--ov-tint-rgb), 0.14);
  box-shadow: 0 18px 48px rgba(0, 0, 0, calc(0.35 * var(--ov-shadow-scale)));
  color: var(--ov-text);
  font-size: 0.85rem;
  line-height: 1.5;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.12s ease;
}

.portal-floating-tip-visible {
  opacity: 1;
  pointer-events: auto;
}

/* The trigger itself (an icon, or — for Статус badges — the pill with no
   separate icon at all now) just needs to read as hoverable/tappable. */
.portal-tip-trigger {
  cursor: pointer;
}

/* Subtitle + summary badge share one line (ensureDealsSummaryBar in
   portal-overrides.js wraps the native <p> in this row rather than
   replacing it) — badge pinned to the end via space-between, gives context
   ("2 сделки требуют внимания · остальные в порядке") right where the eye
   already lands reading the subtitle, before a red Дефолт row further down
   is the first *row* seen. */
.portal-deals-subtitle-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 16px;
}

.portal-deals-summary {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  padding: 4px 12px;
  border-radius: 999px;
  font-size: 0.78rem;
  font-weight: 600;
  white-space: nowrap;
  background: rgba(var(--ov-tint-rgb), 0.08);
  border: 1px solid rgba(var(--ov-tint-rgb), 0.14);
  color: rgba(var(--ov-muted-rgb), 0.85);
}

.portal-deals-summary-warning {
  background: var(--warning-bg);
  border-color: var(--warning-border);
  color: var(--warning);
}

.portal-deals-summary-ok {
  background: var(--success-bg);
  border-color: rgba(61, 163, 93, 0.32);
  color: var(--success);
}

/* Статус column badges (see applyDealBadgeStyle in portal-overrides.js):
   same soft-tint pill as .portal-deals-summary above, in place of the
   native badge's pale, ~90%+-lightness bg/border tokens — those read as a
   washed-out white smudge on this dark table regardless of which status.
   Six distinct tones instead of the native badge palette, which doubled
   up "Просрочка" (a problem) and "Готов к финансированию" (good news) on
   the exact same --status-warning token — indistinguishable at a glance
   despite being opposites. */
.portal-deal-badge {
  padding: 4px 12px !important;
  border-radius: 999px !important;
  font-size: 0.78rem !important;
  font-weight: 600 !important;
  line-height: 1.3 !important;
}

.portal-badge-danger {
  background: var(--danger-bg) !important;
  border-color: var(--danger-border) !important;
  color: var(--danger) !important;
}

.portal-badge-warning {
  background: var(--warning-bg) !important;
  border-color: var(--warning-border) !important;
  color: var(--warning) !important;
}

.portal-badge-info {
  background: var(--info-bg) !important;
  border-color: var(--info-border) !important;
  color: var(--info) !important;
}

.portal-badge-gold {
  background: var(--gold-bg) !important;
  border-color: var(--gold-border) !important;
  color: var(--gold) !important;
}

.portal-badge-success {
  background: var(--success-bg) !important;
  border-color: var(--success-border) !important;
  color: var(--success) !important;
}

.portal-badge-neutral {
  background: rgba(var(--ov-tint-rgb), 0.06) !important;
  border-color: rgba(var(--ov-tint-rgb), 0.16) !important;
  color: rgba(var(--ov-muted-rgb), 0.75) !important;
}

/* "Новая заявка": restyle to match the landing page's "Get financing"
   apply-form look (dark glass panels, mono uppercase labels, gold pill
   submit). Fields/layout are untouched on purpose — this is a visual
   pass only, scoped to .portal-new-application-page so it can't leak
   into other forms across the app. */

/* Wider than the page's own max-w-2xl (672px): now that "Что будет после
   подачи"/"Подсказки" moved into the nav rail instead of a column next to
   the form, that freed-up width goes here so the Данные/Документы split
   below has room to actually read as two columns instead of two cramped
   half-columns — and, combined with the document rows going 2-up (below),
   keeps the whole page short enough to need no scroll on typical screens. */
.portal-new-application-page {
  max-width: 1200px !important;
  margin-left: auto !important;
  margin-right: auto !important;
}

/* Same title size/weight as Обзор's h1 (.portal-overview-header h1) —
   native Tailwind text-2xl here read noticeably smaller than that page. */
.portal-new-application-page h1 {
  font-size: clamp(1.75rem, 2.2rem, 2.5rem) !important;
  line-height: 1.05 !important;
  letter-spacing: -0.03em !important;
  color: var(--ov-text);
}

/* `page`'s only two children are the header (title + subtitle) and the
   <form> (see the DOM-surgery note in portal-overrides.js). The header
   kept its own original width cap from before the form was widened above,
   so it sat narrower than — and flush left of — the two columns instead of
   spanning the same width as the whole layout below it. */
.portal-new-application-page > :not(form) {
  max-width: none !important;
  width: 100%;
}

.portal-new-application-page .bg-card {
  background:
    linear-gradient(145deg, rgba(var(--ov-tint-rgb), 0.075), rgba(var(--ov-tint-rgb), 0.025)),
    var(--ov-surface-bg) !important;
  border: 1px solid rgba(var(--ov-tint-rgb), 0.16) !important;
  box-shadow:
    inset 0 1px 0 rgba(var(--ov-tint-rgb), 0.14),
    0 18px 48px rgba(0, 0, 0, calc(0.16 * var(--ov-shadow-scale))) !important;
  border-radius: 12px !important;
}

.portal-new-application-page .border-input {
  border: 1px solid rgba(var(--ov-tint-rgb), 0.18) !important;
  border-radius: 7px !important;
  background: rgba(var(--ov-tint-rgb), 0.12) !important;
  color: #fff !important;
  box-shadow: none !important;
  transition: border-color 0.18s ease, background 0.18s ease, box-shadow 0.18s ease;
}

.portal-new-application-page input.border-input,
.portal-new-application-page button.border-input {
  min-height: 38px;
}

.portal-new-application-page textarea.border-input {
  min-height: 132px;
}

/* Hide the native number-input spinner (Сумма инвойса) — it clashes with
   the rest of the app's controls, none of which use it. */
.portal-new-application-page input[type="number"].border-input {
  -moz-appearance: textfield;
}

.portal-new-application-page input[type="number"].border-input::-webkit-outer-spin-button,
.portal-new-application-page input[type="number"].border-input::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}

.portal-new-application-page .border-input::placeholder {
  color: rgba(var(--ov-tint-rgb), 0.34);
  opacity: 1;
}

.portal-new-application-page .border-input:focus,
.portal-new-application-page .border-input:focus-visible {
  outline: none !important;
  border-color: rgba(244, 210, 132, 0.46) !important;
  background: rgba(var(--ov-tint-rgb), 0.16) !important;
  box-shadow: 0 0 0 3px rgba(244, 210, 132, 0.08) !important;
}

/* Exact recipe of .gold-cta (the "Подать новую заявку" button on Обзор,
   see index-Fw-zsoxe.css) instead of this page's own bespoke pill/mono-
   uppercase treatment — same gold CTA look everywhere it appears. Real
   button text shows through normally now (no more hide-text-inject-::after
   trick, which only existed to force the old pill's mono/uppercase style). */
.portal-new-application-page [data-testid="button-submit-application"] {
  position: relative;
  overflow: hidden;
  color: #171008 !important;
  background: linear-gradient(135deg, #C79A36, #FFE2A0 48%, #9E7124) !important;
  border: 1px solid #F4D28494 !important;
  border-radius: 8px !important;
  font-size: 0.875rem !important;
  font-weight: 600 !important;
  min-height: 0 !important;
  padding: 12px 24px !important;
  box-shadow: none !important;
  transition: transform 0.2s, background 0.2s, border-color 0.2s !important;
}

.portal-new-application-page [data-testid="button-submit-application"]:hover {
  background: linear-gradient(135deg, #D1A540, #FFE8B2 48%, #A97928) !important;
  transform: translateY(-1px);
}

.portal-new-application-page [data-testid="button-submit-application"]::after {
  content: '';
  opacity: 0;
  pointer-events: none;
  background: linear-gradient(100deg, transparent, rgba(var(--ov-tint-rgb), 0.52), transparent);
  width: 34%;
  height: 220%;
  position: absolute;
  top: -60%;
  left: -45%;
  transform: skew(-18deg);
}

.portal-new-application-page [data-testid="button-submit-application"]:hover::after {
  animation: 0.85s forwards cta-shine;
}

/* ---- Inline validation (kept as a safety net for any future required
   field; none of the current data fields are required anymore — see the
   locked-field styles further down) ---- */

.portal-field-invalid .border-input {
  border-color: rgba(229, 72, 77, 0.6) !important;
  background: rgba(229, 72, 77, 0.08) !important;
}

.portal-field-invalid label {
  color: rgba(var(--ov-muted-rgb), 0.92) !important;
}

/* ---- More readable field labels (was 10px all-caps DM Mono) ---- */

.portal-new-application-page label {
  color: rgba(var(--ov-tint-rgb), 0.78) !important;
  font-family: 'Inter', sans-serif;
  font-size: 13px !important;
  font-weight: 500 !important;
  letter-spacing: normal !important;
  text-transform: none !important;
}

/* ---- Document checklist: "needed to start" vs "can wait" ----
   Headings are inserted as plain siblings of the native document rows
   (see groupNewAppDocuments in portal-overrides.js) rather than each
   group's rows being moved into its own wrapper div — an earlier version
   did that and crashed React on navigating away from this page, since
   unmounting removes each row from the parent React itself rendered it
   into, and a reparented row's actual DOM parent no longer matched that.
   No wrapper now means no spacing-utility parent to hang a "gap between
   this group's own rows" rule on — targets consecutive rows directly
   under the rows container instead, which the `+` combinator already
   limits to true neighbors (skips any pair with a heading between them,
   so this doesn't stack on top of .portal-doc-group-heading's own 10px
   bottom padding below). */
.portal-doc-rows-grouped > .flex.flex-col.gap-3 + .flex.flex-col.gap-3 {
  margin-top: 16px;
}

.portal-doc-group-heading {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  padding: 4px 0 10px;
}

/* Only the "can add later" heading gets the divider treatment — the
   "needed to start" one is always inserted first (see NEWAPP_DOC_ORDER's
   own required-then-optional order in portal-overrides.js), so it never
   needs separating from something above it. */
.portal-doc-group-heading.portal-doc-group-later {
  padding-top: 28px;
  margin-top: 10px;
  border-top: 1px solid rgba(var(--ov-tint-rgb), 0.16);
}

.portal-doc-group-title {
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--ov-text);
}

.portal-doc-group-required .portal-doc-group-title::before {
  content: '';
  display: inline-block;
  width: 6px;
  height: 6px;
  margin-right: 7px;
  border-radius: 50%;
  background: var(--warning);
  vertical-align: middle;
}

/* The icon+label wrapper (confirmed from the compiled component: a plain
   `flex items-start gap-3` div — icon box, then a second div holding the
   label <p> and an optional note/filename <p>) top-aligns its two
   children instead of centering them, so a single-line label (no note)
   sits near the icon's top edge instead of centered against its 36px
   height. align-self on the label itself did nothing (it isn't a direct
   child of this flex row — the surrounding div is), so this targets the
   actual flex container. Doesn't touch the row's own outer
   direction/structure (see the doc-row grid revert above for why that's
   off-limits without seeing the live markup) — just this one wrapper's
   cross-axis alignment. */
.portal-newapp-docs-card .flex.items-start.gap-3 {
  align-items: center;
}

.portal-doc-group-hint {
  font-size: 0.78rem;
  color: rgba(var(--ov-muted-rgb), 0.5);
}

/* "Комплектность пакета / Загружено N из M документов" + its progress bar
   (hideNewAppPackageProgress in portal-overrides.js) — the document list
   right below already shows this row by row. */
.portal-hidden-package-progress {
  display: none;
}

/* Invoice is the one document upload entry point now (the old top card is
   gone) — a plain background tint. Flush (zero side padding) read as if it
   ended right at the first letter of "Инвойс"; a 14px bleed (negative
   margin + matching padding, so icon/text/button don't shift) overcorrected
   the other way and poked out past the icon on the left. 6px keeps the same
   trick at a size that stays inside the card's own left padding instead of
   crossing past the icon. */
.portal-doc-row-primary {
  background: rgba(var(--ov-tint-rgb), 0.045);
  border-radius: 10px;
  margin: 0 -6px;
  padding: 0 6px;
}

/* Brighter/more contrasty than the first pass — it blended into the
   background before. Kept neutral (not gold: gold stays reserved for
   "Отправить") but bright enough to read as "start here". */
.portal-doc-row-primary-tag {
  display: inline-flex;
  align-items: center;
  vertical-align: middle;
  margin-left: 8px;
  padding: 2px 9px;
  border-radius: 999px;
  background: rgba(var(--ov-tint-rgb), 0.16);
  border: 1px solid rgba(var(--ov-tint-rgb), 0.22);
  font-size: 0.7rem;
  font-weight: 600;
  color: var(--ov-text);
}

/* Document icons: soften the identical 7-in-a-row look, then bring
   invoice's back to full strength since it's the primary document. Both
   classes (rounded-lg + bg-muted) together are unique to the icon's own
   box in this row (confirmed against the compiled component); nothing
   else in this card pairs them. */
.portal-newapp-docs-card .rounded-lg.bg-muted {
  opacity: 0.55;
}

.portal-newapp-docs-card .portal-doc-row-primary .rounded-lg.bg-muted {
  opacity: 1;
  background: rgba(var(--ov-tint-rgb), 0.14) !important;
}

/* ---- Mobile: every document row shares one structure, top to bottom ----
   icon+label, then status (now shown for every document — see
   softenDocStatusTone in portal-overrides.js, which used to hide it for
   anything optional and untouched; not just a mobile change, that read as
   "why does only Invoice/Contract have a status?" on desktop too), then a
   full-width Upload button. Desktop keeps the two native sibling rows
   (icon+label, then status+button side by side) — this only touches the
   status+button row, and only below 640px. */
@media (max-width: 640px) {
  /* The status/Upload row (badge + hidden file input + button — a plain
     sibling of the icon+label row above it, not nested inside it; see the
     doc-row grid revert note above for why these two rows can't be merged
     into one without risking the reparent-related React crash that
     happened here before) natively carries pl-12 — Tailwind's own choice
     to indent it under the label text rather than the icon — and lays
     badge/button out side by side. column + flush-left is what turns it
     into its own two lines (status, then Upload) instead of one cramped
     row; the tightened negative margin-top pulls it up against the
     icon+label row above (margin only affects the edge it's declared on,
     so the *next* document's own gap-3 above its own icon+label row is
     untouched) so the three lines read as one document block, not two
     disjointed ones. */
  .portal-newapp-docs-card .flex.items-center.gap-3.pl-12 {
    flex-direction: column;
    align-items: flex-start;
    padding-left: 0 !important;
    gap: 8px;
    margin-top: -4px;
  }

  /* Upload, full width — a thumb-sized target instead of a narrow button
     off to one side, and (native justify-center, already part of this
     button's own classes) keeps its icon+label pair centered once it's
     wide enough for that to matter. */
  .portal-newapp-docs-card .flex.items-center.gap-3.pl-12 button[data-testid^="button-upload-"] {
    width: 100%;
    min-height: 44px;
  }

  /* Group heading: title + caption ("can't submit without these" / "attach
     now, or add later...") were side by side (space-between) — enough
     room for that on desktop, not on a 350px-wide phone card, where the
     caption crowding the title made *both* wrap and collide. Stacked
     instead: title on its own line, caption below it, both full width. */
  .portal-doc-group-heading {
    flex-direction: column;
    align-items: flex-start;
    gap: 2px;
  }
}

/* ---- Inside the form: "Данные по инвойсу" / "Документы" side by side.
   Documents are the active thing the visitor works on; the data fields are
   a byproduct of them, so they sit next to (not above/below) each other. ---- */

/* `form` itself becomes the grid — the data/docs cards stay exactly where
   React put them among its direct children (see the comment above
   applyNewAppColumnsLayout in portal-overrides.js for why: no reparenting,
   only these classes + grid-column placement). */
.portal-new-application-page form {
  display: grid !important;
  /* Документы (column 1) 15 points wider, Заявка на финансирование
     (column 2) 15 points narrower than the even 50/50 split. */
  grid-template-columns: minmax(0, 65fr) minmax(0, 35fr);
  gap: 24px;
  /* stretch (not start): both cards share row 1, so this is what makes the
     shorter Заявка card match Документы's height exactly, top and bottom —
     see .portal-newapp-data-card below for what fills the resulting extra
     space. */
  align-items: stretch;
}

/* 640px was too low for this specific 65/35 split: at anything below
   ~1100px total viewport, Заявка на финансирование's 35% column shrinks to
   the point where its own heading/button (see .portal-newapp-submit-row)
   no longer fit side by side — confirmed by testing, not a guess. Below
   this, single column is the only layout that has room for both. */
@media (max-width: 1100px) {
  .portal-new-application-page form {
    grid-template-columns: 1fr;
  }
}

/* Документы is the action (upload happens there); Данные is its result
   (fields fill in from what got uploaded) — left-to-right reading order
   should match that, so Документы sits in the first column now. */
.portal-new-application-page form > .portal-newapp-docs-card {
  grid-column: 1;
  grid-row: 1;
  order: 1;
}

/* Документы is the taller card, so its own natural content height is what
   the grid row (and Заявка's stretched height, see below) is measured
   against — the native 24px of bottom padding below the last row
   (Подтверждение долга дебитором) carries straight through into both
   cards' bottom edge. Trimming it here raises both at once, without
   touching Заявка's own padding-bottom (still reserved for the submit
   button, see .portal-newapp-data-card > .p-6.pt-0 below). */
.portal-newapp-docs-card > .p-6.pt-0 {
  padding-bottom: 8px;
}

.portal-new-application-page form > .portal-newapp-data-card {
  grid-column: 2;
  grid-row: 1;
  order: 2;
  /* Документы (7 rows) runs taller than Заявка (a handful of fields) —
     align-items:stretch on the grid (above) is what makes this card match
     that height exactly, top and bottom, instead of stopping short at its
     own natural content height. The resulting empty space at the bottom is
     deliberate — that's where .portal-newapp-submit-row lands (see below). */
}

/* Submit overlaps Заявка на финансирование's own grid cell (same column
   and row as .portal-newapp-data-card) instead of sitting in a separate
   full-width row, or actually inside the card's DOM — the last time two of
   form's top-level sections got nested a level deeper (the old columns-
   wrapper attempt), React's reconciliation for form's direct children
   broke and duplicated content. Self-alignment inside the same grid cell
   gets the same visual result without touching the DOM tree: pinned to the
   bottom of the now-stretched cell, centered at 2/3 of the column's width. */
.portal-new-application-page form > .portal-newapp-submit-row {
  grid-column: 2;
  grid-row: 1;
  order: 3;
  justify-self: stretch;
  align-self: end;
  /* Native classes are "flex justify-end" — the button itself doesn't
     stretch to fill a flex row just because the row is wide, so centering
     lives here on the row and the actual 2/3 width lives on the button
     below, not on this row. */
  justify-content: center;
  margin: 0 0 24px;
  z-index: 2;
}

.portal-new-application-page form > .portal-newapp-submit-row [data-testid="button-submit-application"] {
  width: 66.67%;
}

@media (max-width: 1100px) {
  /* All three still carry an explicit grid-row: 1 from the desktop rules
     above (never overridden here before) — at a single column that pins
     all three into the exact same cell, stacked on top of each other
     instead of one below another. grid-row: auto lets normal top-to-bottom
     flow take over, so order (1/2/3, already set above) is what actually
     determines the stacking order here. */
  .portal-new-application-page form > .portal-newapp-data-card,
  .portal-new-application-page form > .portal-newapp-docs-card,
  .portal-new-application-page form > .portal-newapp-submit-row {
    grid-column: 1;
    grid-row: auto;
  }

  .portal-new-application-page form > .portal-newapp-data-card {
    align-self: auto;
  }

  /* The card's own bottom padding no longer needs to reserve clearance for
     the button — it's its own row below the card now, not overlapping it. */
  .portal-newapp-data-card > .p-6.pt-0 {
    padding-bottom: 24px;
  }

  /* Single column: no card left to overlap, so submit goes back to being
     its own full-width row instead of overlaid on Заявка's corner. */
  .portal-new-application-page form > .portal-newapp-submit-row {
    justify-self: stretch;
    align-self: auto;
    margin: 0;
  }

  .portal-new-application-page form > .portal-newapp-submit-row [data-testid="button-submit-application"] {
    width: 100%;
  }
}

/* The data card's own field pairs (Сумма/Валюта, Дебитор/Страна, ...) were
   laid out via Tailwind's grid-cols-2 for the old full-width column; at
   half that width there isn't room for two up, so collapse to one. Matched
   by the utility class substring rather than an exact class list, since the
   compiled markup's exact Tailwind combo isn't something this file owns. */
.portal-newapp-data-card [class*="grid-cols-2"],
.portal-newapp-data-card [class*="grid-cols-3"] {
  display: flex !important;
  flex-direction: column !important;
}

/* Дата инвойса / Срок оплаты (Invoice Date / Payment Due Date) are the one
   pair asked to stay side by side even on a portrait phone, unlike every
   other pair here (Сумма/Валюта, Дебитор/Страна) — both are short, fixed-
   format date inputs (dd.mm.yyyy) that never wrap or need the full row
   width the way a company name or amount can, so two-up doesn't cramp
   them the way it would the others. :has(#invoiceDate) targets that
   specific grid only (an ID inside :has() outweighs the class-substring
   specificity of the collapse rule above, so !important here isn't even
   load-bearing, just consistent with it) — the collapse rule still
   applies normally to every other pair in this card.
   minmax(0, 1fr), not plain 1fr: a bare 1fr track is really minmax(auto,
   1fr) — its floor is the date input's own min-content width (~190px,
   whatever a native date field's mm/dd/yyyy chrome needs), which a 358px-
   wide phone has no room for twice over. Confirmed directly: with plain
   1fr the card itself rendered ~440px wide, pushing Payment Due Date's
   whole column off the right edge of the screen. minmax(0, 1fr) lets the
   track (and the input inside it) actually shrink to fit. */
@media (max-width: 640px) {
  .portal-newapp-data-card .grid:has(#invoiceDate) {
    display: grid !important;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: 10px;
  }
}

/* Tighter vertical rhythm between field rows (native gap-5 = 20px, gap-4 =
   16px) — shorter inputs above and a denser stack read as a more composed
   form instead of a padded-out one. Exact class names, confirmed from the
   compiled component, not a guess. */
.portal-newapp-data-card .gap-5 {
  gap: 14px;
}

.portal-newapp-data-card .gap-4 {
  gap: 10px;
}

/* Every field here except the comment is now genuinely locked (disabled —
   see lockNewAppDataFields in portal-overrides.js), so this dim-until-
   touched treatment only ever applies to them in practice: they can't be
   focused/touched, so they stay dim permanently, reading as "system value",
   not "empty field waiting for input". #description is excluded below —
   it's the one field a visitor actually uses, so it stays at full
   brightness from the start instead of waiting for a first touch. */
.portal-newapp-data-card .flex.flex-col.gap-2 input,
.portal-newapp-data-card .flex.flex-col.gap-2 select,
.portal-newapp-data-card .flex.flex-col.gap-2 textarea,
.portal-newapp-data-card .flex.flex-col.gap-2 [role="combobox"] {
  opacity: 0.55;
  transition: opacity 0.15s ease;
}

.portal-newapp-data-card .flex.flex-col.gap-2.portal-field-active input,
.portal-newapp-data-card .flex.flex-col.gap-2.portal-field-active select,
.portal-newapp-data-card .flex.flex-col.gap-2.portal-field-active textarea,
.portal-newapp-data-card .flex.flex-col.gap-2.portal-field-active [role="combobox"] {
  opacity: 1;
}

.portal-newapp-data-card #description {
  opacity: 1 !important;
}

/* Locked fields (Сумма/Валюта/Дебитор/Страна/Даты): truly inert, not just
   dim — no hover feedback, no cursor implying you could click into it. */
.portal-newapp-data-card .portal-field-locked {
  cursor: not-allowed;
  pointer-events: none;
}

/* An <input> can't hold the lock icon as a real child (void element), and
   the <select> trigger — while it technically can — crashes React on
   navigating away from this page if it does (see addNewAppSelectLockIcons
   in portal-overrides.js). Both cases get the icon inserted as a plain
   sibling instead, placed with an absolute position — the field/trigger's
   *existing* parent becomes the anchor rather than a new wrapper it gets
   moved into (that parent also holds a <label>, so top:50% here would
   center against the whole label+field block, not just the field's own
   row).
   bottom (not top): every locked field/trigger this positions against
   shares the same 38px min-height (.border-input's own rule) and its
   bottom edge always lines up with this anchor's own bottom edge —
   label height above it (one line, or wrapped to two on a narrow mobile
   column) never affects that. 12px = (38px field height - 14px icon
   height) / 2, i.e. centered against the field regardless of the label.
   Anchoring from the top used to need a one-time JS measurement instead
   (see the comment on NEWAPP_LOCKED_SIBLING_ICON_IDS in
   portal-overrides.js for why that went stale) — this needs none. */
.portal-lock-anchor {
  position: relative;
}

.portal-lock-anchor > .portal-field-locked {
  padding-right: 34px !important;
}

.portal-lock-anchor > .portal-lock-icon {
  position: absolute;
  right: 12px;
  bottom: 12px;
  pointer-events: none;
}

.portal-lock-icon {
  display: inline-flex;
  flex-shrink: 0;
  color: rgba(var(--ov-muted-rgb), 0.4);
}

/* Same size/color as "Приложите пакет документов..." (Документы card's
   own subtitle, native text-sm text-muted-foreground) — hsl(var(...))
   rather than a hand-picked rgba so this tracks --muted-foreground
   exactly, including if that token ever changes. */
.portal-newapp-autofill-note {
  display: flex;
  align-items: center;
  gap: 6px;
  margin: 2px 0 6px;
  font-size: 0.875rem;
  line-height: 1.4;
  color: hsl(var(--muted-foreground));
}

/* Used to reserve room for "Отправить" when it sat top-right, overlapping
   this header — now that it's pinned to the bottom of the card instead
   (see .portal-newapp-submit-row), the header has the card's full width to
   itself. overflow-wrap stays as a cheap safety net regardless — no reason
   to drop it now that it isn't load-bearing for anything.
   padding-bottom trims the native CardHeader gap below the (now one-line)
   note, so "Сумма инвойса" and the rest of the fields below it sit closer
   to the header instead of leaving a gap sized for the old, longer note. */
.portal-newapp-data-header {
  overflow-wrap: break-word;
  padding-bottom: 8px;
}

/* Reserves clearance at the bottom of the card's own content for
   .portal-newapp-submit-row, which sits at the bottom of this now-stretched
   card (see align-items:stretch above) as a separate overlapping sibling,
   not as a DOM child — without this, the button (≈44px + its own 24px
   bottom margin) can overlap the last field (Комментарий) whenever the
   stretched height doesn't leave quite enough natural gap below it. */
.portal-newapp-data-card > .p-6.pt-0 {
  padding-bottom: 84px;
}

/* Валюта / Страна дебитора show a real selected value (AED / United Arab
   Emirates), not an empty placeholder, so opacity alone left their text
   noticeably brighter than Сумма инвойса's dim placeholder example —
   recolored to the exact same hint tone, same as Сумма инвойса's
   ::placeholder below. Native <input type="date"> doesn't use
   ::placeholder for its empty "дд.мм.гггг" segments either, so it needs
   the same explicit color. Both go back to full white once touched. */
.portal-newapp-data-card .flex.flex-col.gap-2 [role="combobox"],
.portal-newapp-data-card .flex.flex-col.gap-2 input[type="date"] {
  /* !important: these carry .border-input, whose own `color: #fff
     !important` (see .border-input above) otherwise wins regardless of
     this rule's specificity, keeping them at full brightness. */
  color: rgba(var(--ov-tint-rgb), 0.34) !important;
}

.portal-newapp-data-card .flex.flex-col.gap-2.portal-field-active [role="combobox"],
.portal-newapp-data-card .flex.flex-col.gap-2.portal-field-active input[type="date"] {
  color: #fff !important;
}

/* Submit stays inert (not just visually muted) until the two documents that
   actually gate underwriting — Invoice + Contract — are attached. */
.portal-new-application-page [data-testid="button-submit-application"]:disabled {
  opacity: 0.45;
  cursor: not-allowed;
  pointer-events: none;
}

/* ---- "Что будет после подачи" / "Подсказки" — injected into the spare
   room below the persistent global nav rail's own links (see
   findGlobalNavSidebar in portal-overrides.js) rather than a dedicated
   column next to the form, so the form gets the full content width. ---- */

.portal-newapp-sidebar {
  display: flex;
  flex-direction: column;
  gap: 16px;
  margin-top: 20px;
  padding-top: 20px;
  border-top: 1px solid rgba(var(--ov-tint-rgb), 0.12);
}

.portal-newapp-side-title {
  margin: 0 0 14px;
  font-size: 0.9rem;
  font-weight: 600;
  color: var(--ov-text);
}

.portal-newapp-steps {
  margin: 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 14px;
  counter-reset: portal-step;
}

.portal-newapp-steps li {
  position: relative;
  padding-left: 30px;
  font-size: 0.82rem;
  line-height: 1.45;
  color: rgba(var(--ov-muted-rgb), 0.78);
  counter-increment: portal-step;
}

.portal-newapp-steps li::before {
  content: counter(portal-step);
  position: absolute;
  left: 0;
  top: 0;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.72rem;
  font-weight: 700;
  color: #171008;
  background: linear-gradient(135deg, #C79A36, #FFE2A0 48%, #9E7124);
}

.portal-newapp-steps li:not(:last-child)::after {
  content: '';
  position: absolute;
  left: 9px;
  top: 22px;
  width: 1px;
  height: calc(100% - 6px);
  background: rgba(var(--ov-tint-rgb), 0.14);
}

/* ---- Pre-submit summary overlay ---- */

.portal-newapp-summary-backdrop {
  position: fixed;
  inset: 0;
  z-index: 200;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  background: rgba(5, 5, 5, 0.72);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
}

.portal-newapp-summary-card {
  width: min(440px, 100%);
  border-radius: 16px;
  padding: 28px;
  background: linear-gradient(145deg, rgba(var(--ov-tint-rgb), 0.075), rgba(var(--ov-tint-rgb), 0.025)), var(--ov-surface-bg);
  border: 1px solid rgba(var(--ov-tint-rgb), 0.16);
  box-shadow: 0 30px 70px rgba(0, 0, 0, calc(0.4 * var(--ov-shadow-scale))), inset 0 1px 0 rgba(var(--ov-tint-rgb), 0.14);
}

.portal-newapp-summary-kicker {
  color: rgba(var(--ov-tint-rgb), 0.5);
  font-family: 'DM Mono', monospace;
  font-size: 10px;
  font-weight: 500;
  letter-spacing: 1.3px;
  text-transform: uppercase;
  margin-bottom: 8px;
}

.portal-newapp-summary-card h3 {
  margin: 0 0 20px;
  font-size: 1.3rem;
  font-weight: 600;
  color: var(--ov-text);
}

.portal-newapp-summary-list {
  margin: 0 0 24px;
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.portal-newapp-summary-list > div {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 16px;
  padding-bottom: 10px;
  border-bottom: 1px solid rgba(var(--ov-tint-rgb), 0.08);
}

.portal-newapp-summary-list dt {
  font-size: 0.8rem;
  color: rgba(var(--ov-muted-rgb), 0.55);
}

.portal-newapp-summary-list dd {
  margin: 0;
  font-size: 0.9rem;
  font-weight: 600;
  color: var(--ov-text);
  text-align: right;
}

.portal-newapp-summary-actions {
  display: flex;
  justify-content: flex-end;
  gap: 12px;
}

.portal-newapp-summary-back {
  border: 1px solid rgba(var(--ov-tint-rgb), 0.18);
  border-radius: 999px;
  background: transparent;
  color: rgba(var(--ov-muted-rgb), 0.85);
  font-size: 0.82rem;
  font-weight: 500;
  padding: 0 20px;
  min-height: 44px;
  cursor: pointer;
  transition: background 0.18s ease, border-color 0.18s ease;
}

.portal-newapp-summary-back:hover {
  background: rgba(var(--ov-tint-rgb), 0.06);
  border-color: rgba(var(--ov-tint-rgb), 0.3);
}

.portal-newapp-summary-confirm {
  border: 1px solid rgba(244, 210, 132, 0.62);
  border-radius: 999px;
  background: linear-gradient(135deg, #C79A36, #FFE2A0 48%, #9E7124);
  color: #171008;
  font-family: 'DM Mono', monospace;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 1.1px;
  text-transform: uppercase;
  padding: 0 28px;
  min-height: 44px;
  cursor: pointer;
  box-shadow: 0 10px 26px rgba(199, 154, 54, 0.2), inset 0 1px 0 rgba(var(--ov-tint-rgb), 0.52);
  transition: transform 0.18s ease, filter 0.18s ease;
}

.portal-newapp-summary-confirm:hover {
  transform: translateY(-1px);
  filter: brightness(1.04);
}

/* ---- Notification bell, next to the user menu in the persistent header
   (see ensureNotificationBell in portal-overrides.js) — a self-contained
   front-end mock, no backend feature behind it. */
.portal-notif-group {
  display: flex;
  align-items: center;
  gap: 6px;
}

.portal-notif-bell {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  border: none;
  border-radius: 999px;
  background: transparent;
  color: rgba(var(--ov-muted-rgb), 0.75);
  cursor: pointer;
  transition: background 0.15s ease, color 0.15s ease;
}

.portal-notif-bell:hover {
  background: rgba(var(--ov-tint-rgb), 0.08);
  color: var(--ov-text);
}

.portal-notif-badge {
  position: absolute;
  top: 2px;
  right: 2px;
  min-width: 16px;
  height: 16px;
  padding: 0 4px;
  border-radius: 999px;
  background: var(--danger);
  color: #fff;
  font-size: 0.62rem;
  font-weight: 700;
  line-height: 16px;
  text-align: center;
  box-shadow: 0 0 0 2px hsl(var(--sidebar));
}

.portal-notif-badge-hidden {
  display: none;
}

/* Fixed + positioned via JS (getBoundingClientRect, see
   positionNotifPanel) rather than nested position:absolute — same reason
   as .portal-floating-tip elsewhere in this file: a rounded card ancestor
   with overflow:hidden would otherwise clip it. */
.portal-notif-panel {
  position: fixed;
  z-index: 9999;
  width: 320px;
  max-height: 420px;
  overflow-y: auto;
  border-radius: 12px;
  background: linear-gradient(145deg, rgba(var(--ov-tint-rgb), 0.075), rgba(var(--ov-tint-rgb), 0.025)), var(--ov-surface-bg);
  border: 1px solid rgba(var(--ov-tint-rgb), 0.16);
  box-shadow:
    inset 0 1px 0 rgba(var(--ov-tint-rgb), 0.14),
    0 18px 48px rgba(0, 0, 0, calc(0.3 * var(--ov-shadow-scale)));
}

.portal-notif-panel-header {
  padding: 14px 16px;
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--ov-text);
  border-bottom: 1px solid rgba(var(--ov-tint-rgb), 0.1);
}

.portal-notif-panel-list {
  display: flex;
  flex-direction: column;
}

.portal-notif-item {
  padding: 12px 16px;
  border-bottom: 1px solid rgba(var(--ov-tint-rgb), 0.06);
}

.portal-notif-item:last-child {
  border-bottom: none;
}

.portal-notif-item-unread {
  background: rgba(244, 210, 132, 0.07);
}

.portal-notif-item-text {
  margin: 0;
  font-size: 0.82rem;
  line-height: 1.4;
  color: var(--ov-text);
}

.portal-notif-item-time {
  margin: 4px 0 0;
  font-size: 0.72rem;
  color: rgba(var(--ov-muted-rgb), 0.5);
}

/* ---- Language switcher, left of the bell (see ensureLanguageSwitcher in
   portal-overrides.js) — same pure-CSS globe glyph as the marketing
   site's .language-trigger (a circle plus a vertical bar and a
   horizontal band via ::before/::after), scaled down from 42px to this
   header's 36px. The dropdown itself is this file's own dark card recipe
   rather than the landing page's light one — that page has no dark theme
   to match, this header does. */
.portal-lang-select {
  position: relative;
}

.portal-lang-trigger {
  width: 36px;
  height: 36px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 1px solid rgba(var(--ov-tint-rgb), 0.16);
  border-radius: 7px;
  background: rgba(var(--ov-tint-rgb), 0.08);
  color: rgba(var(--ov-muted-rgb), 0.75);
  cursor: pointer;
  transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}

.portal-lang-trigger:hover {
  background: rgba(var(--ov-tint-rgb), 0.12);
  border-color: rgba(var(--ov-tint-rgb), 0.3);
  color: var(--ov-text);
}

.portal-lang-trigger span {
  position: relative;
  width: 16px;
  height: 16px;
  display: block;
  border: 1.5px solid currentColor;
  border-radius: 50%;
}

.portal-lang-trigger span::before,
.portal-lang-trigger span::after {
  content: '';
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
}

.portal-lang-trigger span::before {
  width: 1.5px;
  height: 13px;
  background: currentColor;
}

.portal-lang-trigger span::after {
  width: 14px;
  height: 6px;
  border-top: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
}

.portal-lang-menu {
  position: absolute;
  z-index: 50;
  top: calc(100% + 8px);
  left: 0;
  min-width: 92px;
  display: none;
  flex-direction: column;
  gap: 2px;
  padding: 6px;
  border-radius: 10px;
  background: linear-gradient(145deg, rgba(var(--ov-tint-rgb), 0.075), rgba(var(--ov-tint-rgb), 0.025)), var(--ov-surface-bg);
  border: 1px solid rgba(var(--ov-tint-rgb), 0.16);
  box-shadow:
    inset 0 1px 0 rgba(var(--ov-tint-rgb), 0.14),
    0 18px 48px rgba(0, 0, 0, calc(0.3 * var(--ov-shadow-scale)));
}

.portal-lang-menu.portal-lang-open {
  display: flex;
}

.portal-lang-option {
  border: none;
  border-radius: 7px;
  background: transparent;
  padding: 7px 10px;
  color: rgba(var(--ov-muted-rgb), 0.75);
  font-family: 'DM Mono', monospace;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.4px;
  text-align: left;
  cursor: pointer;
}

.portal-lang-option:hover {
  background: rgba(var(--ov-tint-rgb), 0.08);
  color: var(--ov-text);
}

.portal-lang-option-active {
  color: var(--ov-text);
  background: rgba(244, 210, 132, 0.12);
}

/* ---- Light/dark theme toggle (see ensureThemeToggle in
   portal-overrides.js) — a plain button, not a dropdown, matching
   .portal-lang-trigger's exact bordered-box recipe (same size/color/
   padding as the globe and bell on either side of it). Swaps its own SVG
   content (sun/moon) and title/aria-label on click; no separate open/
   closed state to style since there's no menu. */
.portal-theme-trigger {
  width: 36px;
  height: 36px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 1px solid rgba(var(--ov-tint-rgb), 0.16);
  border-radius: 7px;
  background: rgba(var(--ov-tint-rgb), 0.08);
  color: rgba(var(--ov-muted-rgb), 0.75);
  cursor: pointer;
  transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}

.portal-theme-trigger:hover {
  background: rgba(var(--ov-tint-rgb), 0.12);
  border-color: rgba(var(--ov-tint-rgb), 0.3);
  color: var(--ov-text);
}

/* ---- Deal detail "Deal Status" stepper ([data-testid="stage-stepper"],
   native component, no override hook of its own) on narrow screens: its 5
   steps are equal flex-1 columns (~55-60px each at 390px wide), and each
   step's label sits in a plain centered <span> with no side padding of
   its own. A short label (e.g. "Approved", "Financed") renders wide
   enough to fill essentially its whole column, so two neighboring labels'
   text touches edge-to-edge with zero gap — reads as one glued word
   ("ApprovedFinanced") instead of two. Padding on the column itself (not
   the span) opens a visible gap at every boundary without changing the
   stepper's own width math. */
@media (max-width: 640px) {
  [data-testid="stage-stepper"] > div {
    padding: 0 3px;
  }
}
