Files
cbsnexora/src/app/loan-origination/loan-pipeline/loan-pipeline.component.scss
T
sonaliandClaude Sonnet 5.5 ef1efb78e3 feat(loan-origination): purpose and priority sector at KYC, simpler deposit-loan sanction, account wizard from LOS
- Purpose & Priority Sector section in KYC (priority sector Yes/No against the product's setting with a reason when
  they differ, category from the PrioritySectorCategory Code, weaker section and its type, supporting documents per
  category); Complete KYC and the sanction need it.
- Deposit loans: Deposit Selection in two steps (deposit, then lien letter); no checkbox lists at sanction; the
  approver approves without ticking rows; sanction letter released on approval, with the sanctioning authority's name
  and date; Personal Discussion plan lists what was collected and the product terms; income, EMI and co-borrower
  hidden at KYC; loan-specific documents can always be added.
- Loan account wizard takes purpose, priority sector, weaker section from the LOS application; LOS applications can be
  picked from a client's view; Limit & Security, Guarantors and SMS steps for advances.
- FP-style deposit products are recognised as deposit loans once the product catalog is registered.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-30 15:30:34 +05:30

1142 lines
22 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/.
*/
// Modern, executive-grade styles for Loan Origination Pipeline (/loan-origination/pipeline)
// Designed for high visual excellence, responsiveness, and polished banking UX.
:host {
display: block;
font-family: inherit;
color: #0f172a;
}
// ---------------------------------------------------------------------------
// Main Page Container
// ---------------------------------------------------------------------------
.lop-page {
padding: 24px;
display: flex;
flex-direction: column;
gap: 20px;
max-width: 1680px;
margin: 0 auto;
@media (width <= 768px) {
padding: 16px;
gap: 16px;
}
}
// ---------------------------------------------------------------------------
// Header Section
// ---------------------------------------------------------------------------
.lop-header {
background: linear-gradient(135deg, #fff 0%, #f8fafc 100%);
border: 1px solid #e2e8f0;
border-radius: 16px;
padding: 24px 28px;
display: flex;
align-items: flex-start;
justify-content: space-between;
gap: 24px;
flex-wrap: wrap;
box-shadow: 0 4px 20px -2px rgb(15 23 42 / 4%);
position: relative;
overflow: hidden;
&::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 3px;
background: linear-gradient(90deg, #0f766e 0%, #0d9488 50%, #1074b9 100%);
}
&__left {
flex: 1 1 520px;
}
&__eyebrow {
display: inline-flex;
align-items: center;
gap: 8px;
font-size: 11px;
font-weight: 700;
letter-spacing: 0.08em;
text-transform: uppercase;
color: #0f766e;
background: #f0fdf4;
border: 1px solid #bbf7d0;
padding: 4px 10px;
border-radius: 999px;
margin-bottom: 10px;
.lop-pulse-dot {
width: 6px;
height: 6px;
border-radius: 50%;
background: #10b981;
box-shadow: 0 0 0 2px rgb(16 185 129 / 25%);
}
}
&__title {
font-size: 26px;
font-weight: 700;
color: #0f172a;
letter-spacing: -0.02em;
margin: 0 0 6px;
display: flex;
align-items: center;
gap: 12px;
flex-wrap: wrap;
}
&__sub {
font-size: 13.5px;
color: #64748b;
line-height: 1.5;
margin: 0;
max-width: 780px;
}
&__toolbar {
display: flex;
align-items: center;
gap: 12px;
flex-wrap: wrap;
align-self: center;
@media (width <= 768px) {
width: 100%;
justify-content: flex-start;
}
}
}
.lop-field-group {
display: flex;
flex-direction: column;
gap: 5px;
&__label {
font-size: 11px;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.05em;
color: #64748b;
display: flex;
align-items: center;
gap: 4px;
}
}
.lop-select-wrap {
position: relative;
display: inline-flex;
align-items: center;
select {
height: 40px;
min-width: 200px;
padding: 0 36px 0 14px;
border: 1px solid #cbd5e1;
border-radius: 10px;
font-size: 13.5px;
font-weight: 500;
color: #0f172a;
background: #fff;
cursor: pointer;
appearance: none;
transition: all 0.2s ease;
&:hover {
border-color: #94a3b8;
}
&:focus {
outline: none;
border-color: #0d9488;
box-shadow: 0 0 0 3px rgb(13 148 136 / 15%);
}
}
.lop-select-arrow {
position: absolute;
right: 12px;
pointer-events: none;
color: #64748b;
display: flex;
align-items: center;
}
}
.lop-chip-scope {
display: inline-flex;
align-items: center;
gap: 6px;
height: 40px;
padding: 0 14px;
border-radius: 10px;
background: #f1f5f9;
border: 1px solid #e2e8f0;
font-size: 13px;
font-weight: 600;
color: #334155;
}
// ---------------------------------------------------------------------------
// KPI Stat Cards Grid
// ---------------------------------------------------------------------------
.lop-kpi-grid {
display: grid;
grid-template-columns: repeat(5, 1fr);
gap: 16px;
@media (width <= 1200px) {
grid-template-columns: repeat(3, 1fr);
}
@media (width <= 768px) {
grid-template-columns: repeat(2, 1fr);
}
@media (width <= 480px) {
grid-template-columns: 1fr;
}
}
.lop-kpi-card {
background: #fff;
border: 1px solid #e2e8f0;
border-radius: 14px;
padding: 18px 20px;
display: flex;
flex-direction: column;
justify-content: space-between;
gap: 10px;
position: relative;
overflow: hidden;
box-shadow: 0 2px 6px -1px rgb(15 23 42 / 4%);
transition:
transform 0.2s ease,
box-shadow 0.2s ease,
border-color 0.2s ease;
&:hover {
transform: translateY(-2px);
box-shadow: 0 8px 20px -3px rgb(15 23 42 / 8%);
}
&::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 3px;
background: #cbd5e1;
}
&--total::before {
background: linear-gradient(90deg, #3b82f6, #1d4ed8);
}
&--progress::before {
background: linear-gradient(90deg, #0ea5e9, #0284c7);
}
&--hold::before {
background: linear-gradient(90deg, #f59e0b, #d97706);
}
&--rejected::before {
background: linear-gradient(90deg, #ef4444, #dc2626);
}
&--disbursed::before {
background: linear-gradient(90deg, #10b981, #059669);
}
&__header {
display: flex;
align-items: center;
justify-content: space-between;
}
&__label {
font-size: 11.5px;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.05em;
color: #64748b;
}
&__icon {
width: 32px;
height: 32px;
border-radius: 8px;
display: inline-flex;
align-items: center;
justify-content: center;
color: #475569;
background: #f1f5f9;
&--total {
background: #eff6ff;
color: #2563eb;
}
&--progress {
background: #f0f9ff;
color: #0284c7;
}
&--hold {
background: #fffbeb;
color: #d97706;
}
&--rejected {
background: #fef2f2;
color: #dc2626;
}
&--disbursed {
background: #ecfdf5;
color: #059669;
}
}
&__value {
font-size: 26px;
font-weight: 800;
font-variant-numeric: tabular-nums;
color: #0f172a;
line-height: 1.1;
letter-spacing: -0.02em;
&.npa-warn {
color: #d97706;
}
&--danger {
color: #dc2626;
}
&--success {
color: #059669;
}
}
&__sub {
font-size: 12px;
color: #64748b;
font-weight: 500;
display: flex;
align-items: center;
gap: 4px;
}
}
// ---------------------------------------------------------------------------
// Navigation Tabs
// ---------------------------------------------------------------------------
.lop-tabs-wrap {
background: #f1f5f9;
padding: 6px;
border-radius: 14px;
border: 1px solid #e2e8f0;
display: flex;
align-items: center;
gap: 4px;
overflow-x: auto;
scrollbar-width: none;
-webkit-overflow-scrolling: touch;
&::-webkit-scrollbar {
display: none;
}
}
.lop-tab-btn {
display: inline-flex;
align-items: center;
gap: 8px;
padding: 8px 16px;
border-radius: 10px;
font-size: 13px;
font-weight: 600;
color: #64748b;
background: transparent;
border: none;
cursor: pointer;
white-space: nowrap;
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
outline: none;
svg {
opacity: 0.7;
transition: opacity 0.2s;
}
&:hover {
color: #0f172a;
background: rgb(255 255 255 / 60%);
svg {
opacity: 1;
}
}
&--active {
background: #fff !important;
color: #0f766e !important;
box-shadow: 0 2px 8px rgb(15 23 42 / 8%);
svg {
opacity: 1;
color: #0f766e;
}
}
}
// ---------------------------------------------------------------------------
// Modern Card Container
// ---------------------------------------------------------------------------
.lop-card {
background: #fff;
border: 1px solid #e2e8f0;
border-radius: 16px;
box-shadow: 0 2px 10px -2px rgb(15 23 42 / 4%);
overflow: hidden;
display: flex;
flex-direction: column;
&__header {
padding: 18px 24px;
border-bottom: 1px solid #f1f5f9;
display: flex;
align-items: center;
justify-content: space-between;
gap: 16px;
flex-wrap: wrap;
background: #fff;
}
&__title {
font-size: 15px;
font-weight: 700;
color: #0f172a;
letter-spacing: -0.01em;
display: flex;
align-items: center;
gap: 8px;
margin: 0;
.lop-count-badge {
display: inline-flex;
align-items: center;
justify-content: center;
padding: 2px 8px;
font-size: 11.5px;
font-weight: 700;
color: #0f766e;
background: #f0fdf4;
border: 1px solid #bbf7d0;
border-radius: 999px;
}
}
&__desc {
font-size: 13px;
color: #64748b;
margin: 6px 0 0;
line-height: 1.5;
}
&__body {
padding: 20px 24px;
}
}
// ---------------------------------------------------------------------------
// Modern Filter Panel
// ---------------------------------------------------------------------------
.lop-filter-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 16px;
padding: 18px 22px;
background: #fff;
@media (width <= 1024px) {
grid-template-columns: repeat(2, 1fr);
}
@media (width <= 600px) {
grid-template-columns: 1fr;
}
}
.lop-form-control {
display: flex;
flex-direction: column;
gap: 6px;
label {
font-size: 11.5px;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.04em;
color: #475569;
display: flex;
align-items: center;
gap: 5px;
}
.lop-input-wrap {
position: relative;
display: flex;
align-items: center;
.lop-input-icon {
position: absolute;
left: 12px;
color: #94a3b8;
pointer-events: none;
display: flex;
align-items: center;
}
input,
select {
width: 100%;
height: 42px;
border: 1px solid #cbd5e1;
border-radius: 10px;
font-size: 13.5px;
color: #0f172a;
background: #fff;
padding: 0 14px;
transition: all 0.2s ease;
&:hover {
border-color: #94a3b8;
}
&:focus {
outline: none;
border-color: #0d9488;
box-shadow: 0 0 0 3px rgb(13 148 136 / 15%);
}
}
input.has-icon {
padding-left: 38px;
}
select {
appearance: none;
padding-right: 36px;
cursor: pointer;
}
.lop-select-chevron {
position: absolute;
right: 12px;
pointer-events: none;
color: #64748b;
display: flex;
align-items: center;
}
}
}
// ---------------------------------------------------------------------------
// Awaiting Approval Priority Alert Card
// ---------------------------------------------------------------------------
.lop-priority-card {
border: 1px solid #fed7aa;
background: #fffbeb;
border-radius: 16px;
overflow: hidden;
box-shadow: 0 4px 12px -2px rgb(245 158 11 / 8%);
&__head {
padding: 16px 20px;
display: flex;
align-items: center;
justify-content: space-between;
background: linear-gradient(90deg, #fffbeb 0%, #fef3c7 100%);
border-bottom: 1px solid #fde68a;
}
&__headline {
font-size: 14.5px;
font-weight: 700;
color: #92400e;
display: flex;
align-items: center;
gap: 8px;
}
}
// ---------------------------------------------------------------------------
// Data Tables
// ---------------------------------------------------------------------------
.lop-table-scroll {
overflow-x: auto;
-webkit-overflow-scrolling: touch;
position: relative;
}
.lop-table {
width: 100%;
border-collapse: separate;
border-spacing: 0;
font-size: 13px;
text-align: left;
thead th {
background: #f8fafc;
color: #475569;
font-size: 11px;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.06em;
padding: 12px 16px;
border-bottom: 1px solid #e2e8f0;
white-space: nowrap;
position: sticky;
top: 0;
z-index: 2;
&.num {
text-align: right;
}
&.col-in {
color: #0f766e;
}
}
tbody tr {
transition: background 0.15s ease;
td {
padding: 14px 16px;
border-bottom: 1px solid #f1f5f9;
color: #1e293b;
vertical-align: middle;
&.num {
text-align: right;
font-variant-numeric: tabular-nums;
font-weight: 500;
}
&.col-in {
font-weight: 600;
color: #0f766e;
}
&.col-out {
font-weight: 600;
color: #dc2626;
}
}
&:last-child td {
border-bottom: none;
}
}
// Clickable interactive rows
tbody tr.cctr-branch-row {
cursor: pointer;
&:hover {
background: #f0fdf4;
.lop-app-no {
border-color: #0d9488;
color: #0f766e;
}
}
}
tfoot tr.cctr-total-row {
background: #f8fafc;
td {
padding: 14px 16px;
font-weight: 700;
color: #0f172a;
border-top: 2px solid #cbd5e1;
border-bottom: none;
&.num {
text-align: right;
font-variant-numeric: tabular-nums;
}
}
}
}
// Application Code Monospace Badge
.lop-app-no {
display: inline-flex;
align-items: center;
gap: 5px;
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
font-size: 12px;
font-weight: 700;
padding: 3px 8px;
border-radius: 6px;
background: #f1f5f9;
border: 1px solid #cbd5e1;
color: #0f172a;
letter-spacing: -0.01em;
transition: all 0.2s ease;
}
// Progress Bar in Table
.lop-progress-cell {
display: flex;
align-items: center;
justify-content: flex-end;
gap: 8px;
}
.lop-progress-track {
width: 56px;
height: 6px;
background: #e2e8f0;
border-radius: 999px;
overflow: hidden;
position: relative;
}
.lop-progress-bar {
height: 100%;
border-radius: 999px;
background: linear-gradient(90deg, #3b82f6 0%, #10b981 100%);
transition: width 0.3s ease;
}
.lop-progress-text {
font-size: 12px;
font-weight: 600;
color: #334155;
min-width: 34px;
text-align: right;
font-variant-numeric: tabular-nums;
}
// Table Status Badges
.loan-badge {
display: inline-flex;
align-items: center;
gap: 5px;
padding: 4px 10px;
border-radius: 999px;
font-size: 11.5px;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.04em;
white-space: nowrap;
&::before {
content: '';
width: 6px;
height: 6px;
border-radius: 50%;
background: currentcolor;
opacity: 0.8;
}
&--progress {
background: #eff6ff;
color: #1d4ed8;
border: 1px solid #bfdbfe;
}
&--hold {
background: #fffbeb;
color: #b45309;
border: 1px solid #fde68a;
}
&--rejected {
background: #fef2f2;
color: #dc2626;
border: 1px solid #fecaca;
}
&--disbursed {
background: #f0fdf4;
color: #15803d;
border: 1px solid #bbf7d0;
}
&--verified {
background: #f0fdf4;
color: #15803d;
border: 1px solid #bbf7d0;
}
&--missing {
background: #fffbeb;
color: #b45309;
border: 1px solid #fde68a;
}
&--sm {
font-size: 10.5px;
padding: 2px 7px;
margin-left: 4px;
}
}
// Channel Tag
.lop-channel-pill {
display: inline-flex;
align-items: center;
gap: 4px;
font-size: 11.5px;
font-weight: 600;
padding: 2px 8px;
border-radius: 6px;
background: #f8fafc;
border: 1px solid #e2e8f0;
color: #475569;
}
// Empty State inside Table
.lop-empty-state {
padding: 48px 24px !important;
text-align: center !important;
color: #64748b;
&__icon {
width: 48px;
height: 48px;
margin: 0 auto 12px;
color: #94a3b8;
display: flex;
align-items: center;
justify-content: center;
background: #f1f5f9;
border-radius: 50%;
}
&__title {
font-size: 15px;
font-weight: 700;
color: #1e293b;
margin: 0 0 4px;
}
&__desc {
font-size: 13px;
color: #64748b;
margin: 0;
}
}
// ---------------------------------------------------------------------------
// Pagination Bar
// ---------------------------------------------------------------------------
.lop-pagination {
padding: 14px 20px;
border-top: 1px solid #e2e8f0;
display: flex;
align-items: center;
justify-content: space-between;
gap: 16px;
flex-wrap: wrap;
background: #f8fafc;
&__info {
font-size: 12.5px;
color: #64748b;
font-weight: 500;
}
&__controls {
display: flex;
align-items: center;
gap: 8px;
}
&__page {
font-size: 12.5px;
font-weight: 600;
color: #1e293b;
padding: 0 6px;
}
}
// ---------------------------------------------------------------------------
// Buttons
// ---------------------------------------------------------------------------
.pg-btn {
height: 40px;
padding: 0 16px;
border-radius: 10px;
font-size: 13px;
font-weight: 600;
display: inline-flex;
align-items: center;
justify-content: center;
gap: 8px;
border: 1px solid transparent;
cursor: pointer;
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
text-decoration: none;
white-space: nowrap;
&:disabled {
opacity: 0.5;
cursor: not-allowed;
pointer-events: none;
}
&--ghost {
background: #fff;
border-color: #cbd5e1;
color: #334155;
&:hover:not(:disabled) {
background: #f8fafc;
border-color: #94a3b8;
color: #0f172a;
}
}
&--primary {
background: linear-gradient(135deg, #0f766e 0%, #0d9488 100%);
color: #fff;
box-shadow: 0 2px 8px rgb(13 148 136 / 25%);
&:hover:not(:disabled) {
background: linear-gradient(135deg, #0d9488 0%, #047857 100%);
box-shadow: 0 4px 14px rgb(13 148 136 / 35%);
transform: translateY(-1px);
}
}
}
// ---------------------------------------------------------------------------
// New Application Intake Form
// ---------------------------------------------------------------------------
.lop-form-section {
margin-bottom: 24px;
&__title {
font-size: 13px;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.05em;
color: #0f766e;
margin-bottom: 12px;
padding-bottom: 6px;
border-bottom: 1px solid #f1f5f9;
display: flex;
align-items: center;
gap: 6px;
}
}
.lop-form-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 20px;
@media (width <= 900px) {
grid-template-columns: repeat(2, 1fr);
}
@media (width <= 600px) {
grid-template-columns: 1fr;
}
}
.lop-form-actions {
display: flex;
align-items: center;
justify-content: flex-end;
gap: 12px;
padding-top: 20px;
border-top: 1px solid #f1f5f9;
margin-top: 24px;
}
// Existing Client Selected Pill
.loi-selected-client {
display: flex;
align-items: center;
justify-content: space-between;
height: 42px;
padding: 0 12px;
border-radius: 10px;
background: #f0fdf4;
border: 1px solid #bbf7d0;
font-size: 13.5px;
font-weight: 600;
color: #15803d;
button {
height: 28px;
padding: 0 10px;
font-size: 12px;
border-radius: 6px;
border: 1px solid #86efac;
background: #fff;
color: #15803d;
cursor: pointer;
&:hover {
background: #ecfdf5;
}
}
}
// Search Results Dropdown
.loi-search-results {
margin-top: 8px;
border: 1px solid #e2e8f0;
border-radius: 12px;
background: #fff;
box-shadow: 0 10px 25px -5px rgb(0 0 0 / 10%);
overflow: hidden;
max-height: 260px;
overflow-y: auto;
}
.loi-search-row {
width: 100%;
display: flex;
align-items: center;
justify-content: space-between;
padding: 10px 14px;
border: none;
background: transparent;
border-bottom: 1px solid #f1f5f9;
text-align: left;
cursor: pointer;
transition: background 0.15s ease;
&:hover {
background: #f8fafc;
}
&:last-child {
border-bottom: none;
}
}
.loi-search-name {
font-size: 13.5px;
font-weight: 600;
color: #0f172a;
}
.loi-search-meta {
font-size: 12px;
color: #64748b;
}
.loi-search-hint {
font-size: 12.5px;
color: #64748b;
margin: 6px 0 0;
font-style: italic;
}
// ---------------------------------------------------------------------------
// Informational Callout / Note Card
// ---------------------------------------------------------------------------
.lop-info-banner {
display: flex;
align-items: flex-start;
gap: 12px;
padding: 14px 18px;
background: #f0fdf4;
border: 1px solid #bbf7d0;
border-radius: 12px;
margin-bottom: 16px;
&__icon {
color: #0f766e;
flex-shrink: 0;
margin-top: 2px;
}
&__text {
font-size: 13px;
line-height: 1.5;
color: #14532d;
margin: 0;
}
}
// Target vs Actual visual achievement bar
.lop-achievement-track {
width: 100px;
height: 6px;
background: #e2e8f0;
border-radius: 999px;
overflow: hidden;
display: inline-block;
vertical-align: middle;
margin-left: 8px;
}
.lop-achievement-fill {
height: 100%;
border-radius: 999px;
background: #10b981;
&--behind {
background: #f59e0b;
}
}
// ---------------------------------------------------------------------------
// Toast Notification
// ---------------------------------------------------------------------------
.inv-toast {
position: fixed;
bottom: 24px;
right: 24px;
z-index: 9999;
background: rgb(15 23 42 / 95%);
backdrop-filter: blur(8px);
color: #fff;
padding: 12px 20px;
border-radius: 12px;
font-size: 13.5px;
font-weight: 500;
box-shadow: 0 10px 25px -5px rgb(0 0 0 / 30%);
border: 1px solid rgb(255 255 255 / 10%);
transform: translateY(100px);
opacity: 0;
pointer-events: none;
transition: all 0.3s cubic-bezier(0.16, 1, 0.3, 1);
&.show {
transform: translateY(0);
opacity: 1;
pointer-events: auto;
}
}