New tab under NPA > Reports > Recovery Management, dedicated to Cash Credit accounts: Drawing Power vs outstanding, interest due/paid this cycle, lifetime recovery, and a Days-Overdrawn/Status view (Regular / Overdrawn / NPA) in place of the generic EMI-style SMA labels, matching how a CC/OD book is actually monitored in real banks. Status now checks NPA history first so an account doesn't show "Regular" just because it's briefly back within DP (RBI upgrade norms require full clearance, not a one-off snapshot). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
612 lines
12 KiB
SCSS
612 lines
12 KiB
SCSS
/**
|
|
* Copyright since 2025 Mifos Initiative
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
*/
|
|
|
|
// NPA-specific status colouring layered on top of ../cashier/cashier-shared.scss (pg-*, cctr-*)
|
|
// and ../investment/investment-shared.scss (inv-kpis, inv-form-*, inv-toast — reused as-is since
|
|
// they are the same generic "KPI tile / entry form / toast" primitives, not Investment-specific).
|
|
|
|
.npa-report-note {
|
|
max-width: none;
|
|
}
|
|
|
|
.npa-badge {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
padding: 3px 10px;
|
|
border-radius: 999px;
|
|
font-size: 11px;
|
|
font-weight: 700;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.04em;
|
|
white-space: nowrap;
|
|
|
|
&--standard {
|
|
background: #f0fdf4;
|
|
color: #15803d;
|
|
border: 1px solid #bbf7d0;
|
|
}
|
|
|
|
&--sma0 {
|
|
background: #fefce8;
|
|
color: #854d0e;
|
|
border: 1px solid #fde68a;
|
|
}
|
|
|
|
&--sma1 {
|
|
background: #fff7ed;
|
|
color: #9a3412;
|
|
border: 1px solid #fed7aa;
|
|
}
|
|
|
|
&--sma2 {
|
|
background: #fff1f0;
|
|
color: #b91c1c;
|
|
border: 1px solid #fecdd3;
|
|
}
|
|
|
|
&--substandard {
|
|
background: #fef2f2;
|
|
color: #dc2626;
|
|
border: 1px solid #fecaca;
|
|
}
|
|
|
|
&--doubtful1 {
|
|
background: #fef2f2;
|
|
color: #b91c1c;
|
|
border: 1px solid #fca5a5;
|
|
}
|
|
|
|
&--doubtful2 {
|
|
background: #fdf2f8;
|
|
color: #9d174d;
|
|
border: 1px solid #fbcfe8;
|
|
}
|
|
|
|
&--doubtful3 {
|
|
background: #f5f3ff;
|
|
color: #5b21b6;
|
|
border: 1px solid #ddd6fe;
|
|
}
|
|
|
|
&--loss {
|
|
background: #1f2937;
|
|
color: #f9fafb;
|
|
border: 1px solid #1f2937;
|
|
}
|
|
}
|
|
|
|
.npa-kpis--ratio {
|
|
.inv-kpi__value {
|
|
&.npa-warn {
|
|
color: #dc2626;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Recovery Management Dashboard's 3 loan-type panels — same .inv-kpi tile, just a 3-wide grid
|
|
// instead of the portfolio strip's 4-wide one.
|
|
.npa-kpis--three {
|
|
grid-template-columns: repeat(3, 1fr);
|
|
}
|
|
|
|
// -----------------------------------------------------------------------
|
|
// Cash Credit Recovery Management — a glossary strip explaining DP / Out of
|
|
// Order / SMA / NPA to a reader meeting the terms for the first time (e.g. a
|
|
// stakeholder demo), plus tone-coloured accents for that screen's KPI row.
|
|
// -----------------------------------------------------------------------
|
|
.npa-glossary {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
|
|
gap: 14px;
|
|
margin-top: 18px;
|
|
}
|
|
|
|
.npa-glossary-card {
|
|
padding: 16px 16px 16px 18px;
|
|
border-radius: 12px;
|
|
background: #fff;
|
|
border: 1px solid #e2e8f0;
|
|
border-left: 4px solid #64748b;
|
|
transition: box-shadow 0.15s ease;
|
|
|
|
&:hover {
|
|
box-shadow: 0 4px 14px rgb(15 23 42 / 8%);
|
|
}
|
|
|
|
&__icon {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
width: 34px;
|
|
height: 34px;
|
|
border-radius: 999px;
|
|
background: #f1f5f9;
|
|
color: #475569;
|
|
font-size: 14px;
|
|
margin-bottom: 10px;
|
|
}
|
|
|
|
&__term {
|
|
font-size: 12px;
|
|
font-weight: 800;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.05em;
|
|
color: #0f172a;
|
|
margin-bottom: 6px;
|
|
}
|
|
|
|
&__desc {
|
|
font-size: 12.5px;
|
|
line-height: 1.55;
|
|
color: #475569;
|
|
margin: 0;
|
|
}
|
|
|
|
&--dp {
|
|
border-left-color: #2563eb;
|
|
|
|
.npa-glossary-card__icon {
|
|
background: #dbeafe;
|
|
color: #2563eb;
|
|
}
|
|
}
|
|
|
|
&--ooo {
|
|
border-left-color: #d97706;
|
|
|
|
.npa-glossary-card__icon {
|
|
background: #fef3c7;
|
|
color: #b45309;
|
|
}
|
|
}
|
|
|
|
&--sma {
|
|
border-left-color: #ca8a04;
|
|
|
|
.npa-glossary-card__icon {
|
|
background: #fef9c3;
|
|
color: #854d0e;
|
|
}
|
|
}
|
|
|
|
&--npa {
|
|
border-left-color: #dc2626;
|
|
|
|
.npa-glossary-card__icon {
|
|
background: #fee2e2;
|
|
color: #dc2626;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Compact gap variant for a KPI row that otherwise uses npa-kpis--ratio's 4-wide grid — used by
|
|
// the CC Recovery Management summary row, which packs more (smaller) tiles than the main header.
|
|
.npa-kpis--compact {
|
|
gap: 8px;
|
|
}
|
|
|
|
// Tone-coloured KPI tile for the CC summary row — same .inv-kpi tile, with a left accent + icon
|
|
// chip so "Out of Order"/"SMA"/"NPA" read as a severity strip rather than four identical boxes.
|
|
// Sized smaller than the default .inv-kpi tile since this row packs 6 of them.
|
|
.npa-kpi--accent {
|
|
padding: 10px 12px 10px 14px;
|
|
border-left: 4px solid var(--npa-kpi-accent, #64748b);
|
|
|
|
.inv-kpi__label {
|
|
font-size: 9px;
|
|
}
|
|
|
|
.inv-kpi__value {
|
|
font-size: 16px;
|
|
}
|
|
|
|
.inv-kpi__sub {
|
|
font-size: 10px;
|
|
}
|
|
|
|
.npa-kpi__icon {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
width: 22px;
|
|
height: 22px;
|
|
border-radius: 999px;
|
|
background: var(--npa-kpi-accent-soft, #f1f5f9);
|
|
color: var(--npa-kpi-accent, #475569);
|
|
font-size: 10px;
|
|
margin-bottom: 4px;
|
|
}
|
|
|
|
&--neutral {
|
|
--npa-kpi-accent: #0f4f3c;
|
|
--npa-kpi-accent-soft: #dcfce7;
|
|
}
|
|
|
|
&--warn {
|
|
--npa-kpi-accent: #d97706;
|
|
--npa-kpi-accent-soft: #fef3c7;
|
|
}
|
|
|
|
&--sma {
|
|
--npa-kpi-accent: #ca8a04;
|
|
--npa-kpi-accent-soft: #fef9c3;
|
|
}
|
|
|
|
&--npa {
|
|
--npa-kpi-accent: #dc2626;
|
|
--npa-kpi-accent-soft: #fee2e2;
|
|
}
|
|
|
|
&--info {
|
|
--npa-kpi-accent: #2563eb;
|
|
--npa-kpi-accent-soft: #dbeafe;
|
|
}
|
|
|
|
&--positive {
|
|
--npa-kpi-accent: #15803d;
|
|
--npa-kpi-accent-soft: #dcfce7;
|
|
}
|
|
}
|
|
|
|
// Account Detail header — title/badge on the left, the Recovery Journey trigger pinned right.
|
|
.npa-detail-header {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 12px;
|
|
flex-wrap: wrap;
|
|
}
|
|
|
|
.npa-timeline-trigger {
|
|
margin-left: auto;
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 7px;
|
|
background: linear-gradient(135deg, #eef2ff, #e0e7ff);
|
|
color: #4338ca;
|
|
border: 1px solid #c7d2fe;
|
|
font-weight: 700;
|
|
text-transform: none;
|
|
letter-spacing: normal;
|
|
transition:
|
|
box-shadow 0.15s ease,
|
|
transform 0.15s ease;
|
|
|
|
&:hover {
|
|
background: linear-gradient(135deg, #e0e7ff, #c7d2fe);
|
|
box-shadow: 0 4px 14px rgb(67 56 202 / 22%);
|
|
transform: translateY(-1px);
|
|
}
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Recovery / Collection Journey popup — a date-led timeline of every SMS, call,
|
|
// visit, notice and payment run against one account, opened from the Account
|
|
// Detail Report's "Recovery Journey" button.
|
|
// ---------------------------------------------------------------------------
|
|
.npa-timeline-backdrop {
|
|
position: fixed;
|
|
inset: 0;
|
|
background: rgb(15 23 42 / 55%);
|
|
backdrop-filter: blur(3px);
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
z-index: 1000;
|
|
padding: 24px;
|
|
animation: npa-timeline-fade-in 0.15s ease-out;
|
|
}
|
|
|
|
.npa-timeline-modal {
|
|
background: #fff;
|
|
border-radius: 18px;
|
|
width: 640px;
|
|
max-width: 100%;
|
|
max-height: min(720px, 88vh);
|
|
display: flex;
|
|
flex-direction: column;
|
|
box-shadow: 0 24px 60px rgb(15 23 42 / 35%);
|
|
animation: npa-timeline-slide-up 0.2s cubic-bezier(0.16, 1, 0.3, 1);
|
|
overflow: hidden;
|
|
|
|
&__head {
|
|
display: flex;
|
|
align-items: flex-start;
|
|
justify-content: space-between;
|
|
gap: 16px;
|
|
padding: 20px 22px;
|
|
border-bottom: 1px solid #e2e8f0;
|
|
background: linear-gradient(180deg, #f8fafc, #fff);
|
|
}
|
|
|
|
&__title {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 6px;
|
|
min-width: 0;
|
|
|
|
h2 {
|
|
margin: 0;
|
|
font-size: 17px;
|
|
font-weight: 800;
|
|
color: #0f172a;
|
|
}
|
|
}
|
|
|
|
&__eyebrow {
|
|
font-size: 10.5px;
|
|
font-weight: 700;
|
|
letter-spacing: 0.07em;
|
|
text-transform: uppercase;
|
|
color: #4338ca;
|
|
}
|
|
|
|
&__meta {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
flex-wrap: wrap;
|
|
font-size: 12px;
|
|
color: #64748b;
|
|
}
|
|
|
|
&__branch::before,
|
|
&__count::before {
|
|
content: '·';
|
|
margin-right: 8px;
|
|
color: #cbd5e1;
|
|
}
|
|
|
|
&__close {
|
|
flex-shrink: 0;
|
|
width: 32px;
|
|
height: 32px;
|
|
border-radius: 999px;
|
|
border: 1px solid #e2e8f0;
|
|
background: #fff;
|
|
color: #64748b;
|
|
display: inline-flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
cursor: pointer;
|
|
transition:
|
|
background 0.15s ease,
|
|
color 0.15s ease;
|
|
|
|
&:hover {
|
|
background: #f1f5f9;
|
|
color: #0f172a;
|
|
}
|
|
}
|
|
|
|
&__body {
|
|
overflow-y: auto;
|
|
padding: 22px;
|
|
}
|
|
}
|
|
|
|
@keyframes npa-timeline-fade-in {
|
|
from {
|
|
opacity: 0;
|
|
}
|
|
|
|
to {
|
|
opacity: 1;
|
|
}
|
|
}
|
|
|
|
@keyframes npa-timeline-slide-up {
|
|
from {
|
|
opacity: 0;
|
|
transform: translateY(14px) scale(0.98);
|
|
}
|
|
|
|
to {
|
|
opacity: 1;
|
|
transform: translateY(0) scale(1);
|
|
}
|
|
}
|
|
|
|
@media (prefers-reduced-motion: reduce) {
|
|
.npa-timeline-backdrop,
|
|
.npa-timeline-modal {
|
|
animation: none;
|
|
}
|
|
}
|
|
|
|
// The timeline list itself — a connecting vertical line runs behind the icon badges.
|
|
.npa-timeline {
|
|
list-style: none;
|
|
margin: 0;
|
|
padding: 0;
|
|
}
|
|
|
|
.npa-timeline-item {
|
|
position: relative;
|
|
display: flex;
|
|
gap: 14px;
|
|
padding-bottom: 22px;
|
|
|
|
// The connecting line spans from just under this item's icon to just above the next one's —
|
|
// anchored to the item itself (not the fixed-size icon) via top+bottom, so it always reaches
|
|
// exactly as far as the gap to the next entry, however tall this entry's text runs.
|
|
&:not(:last-child)::before {
|
|
content: '';
|
|
position: absolute;
|
|
top: 34px;
|
|
bottom: -22px;
|
|
left: 17px;
|
|
width: 2px;
|
|
background: #e2e8f0;
|
|
}
|
|
|
|
&:last-child {
|
|
padding-bottom: 0;
|
|
}
|
|
|
|
&__icon {
|
|
position: relative;
|
|
flex-shrink: 0;
|
|
width: 34px;
|
|
height: 34px;
|
|
border-radius: 999px;
|
|
display: inline-flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
font-size: 13px;
|
|
z-index: 1;
|
|
}
|
|
|
|
&--neutral &__icon {
|
|
background: #eff6ff;
|
|
color: #1d4ed8;
|
|
}
|
|
|
|
&--alert &__icon {
|
|
background: #fef2f2;
|
|
color: #b91c1c;
|
|
}
|
|
|
|
&--positive &__icon {
|
|
background: #f0fdf4;
|
|
color: #15803d;
|
|
}
|
|
|
|
&__body {
|
|
flex: 1;
|
|
min-width: 0;
|
|
padding-top: 4px;
|
|
}
|
|
|
|
&__row {
|
|
display: flex;
|
|
align-items: baseline;
|
|
justify-content: space-between;
|
|
gap: 10px;
|
|
}
|
|
|
|
&__type {
|
|
font-weight: 700;
|
|
font-size: 13.5px;
|
|
color: #0f172a;
|
|
}
|
|
|
|
&__date {
|
|
font-size: 11.5px;
|
|
color: #94a3b8;
|
|
font-variant-numeric: tabular-nums;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
&__remarks {
|
|
margin: 3px 0 6px;
|
|
font-size: 12.5px;
|
|
color: #475569;
|
|
line-height: 1.45;
|
|
}
|
|
|
|
&__channel {
|
|
display: inline-block;
|
|
font-size: 10.5px;
|
|
font-weight: 700;
|
|
letter-spacing: 0.03em;
|
|
text-transform: uppercase;
|
|
color: #64748b;
|
|
background: #f1f5f9;
|
|
padding: 2px 8px;
|
|
border-radius: 6px;
|
|
}
|
|
}
|
|
|
|
.npa-timeline-empty {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
gap: 10px;
|
|
padding: 40px 20px;
|
|
color: #64748b;
|
|
text-align: center;
|
|
|
|
fa-icon {
|
|
font-size: 26px;
|
|
color: #22c55e;
|
|
}
|
|
|
|
p {
|
|
margin: 0;
|
|
font-size: 13px;
|
|
}
|
|
}
|
|
|
|
.npa-detail-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
|
|
gap: 12px 20px;
|
|
padding: 18px;
|
|
}
|
|
|
|
.npa-detail-field {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 3px;
|
|
|
|
dt {
|
|
font-size: 10px;
|
|
font-weight: 700;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.06em;
|
|
color: #64748b;
|
|
}
|
|
|
|
dd {
|
|
margin: 0;
|
|
font-size: 14px;
|
|
font-weight: 600;
|
|
color: #0d1b2a;
|
|
font-variant-numeric: tabular-nums;
|
|
}
|
|
}
|
|
|
|
// Wraps tables with more columns than comfortably fit — .pg-card clips overflow with
|
|
// border-radius, so the scroll container has to live one level in, around the <table> only.
|
|
.pg-table-scroll {
|
|
overflow-x: auto;
|
|
}
|
|
|
|
// Lets a single field span the whole .inv-form-grid row instead of being squeezed into one
|
|
// ~220px column — needed for the Account Detail search box, whose "code — name (branch)"
|
|
// option text is long enough to overflow a narrow column even with ellipsis truncation.
|
|
.npa-form-field--full {
|
|
grid-column: 1 / -1;
|
|
}
|
|
|
|
.pg-pagination {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
flex-wrap: wrap;
|
|
gap: 10px;
|
|
padding: 10px 16px;
|
|
border-top: 1px solid #e2e8f0;
|
|
background: #f8fafc;
|
|
font-size: 12.5px;
|
|
color: #64748b;
|
|
|
|
&__controls {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 10px;
|
|
}
|
|
|
|
&__page {
|
|
font-weight: 600;
|
|
color: #0d1b2a;
|
|
font-variant-numeric: tabular-nums;
|
|
white-space: nowrap;
|
|
}
|
|
}
|