diff --git a/src/app/current-accounts/current-account-view/passbook-tab/passbook-tab.component.ts b/src/app/current-accounts/current-account-view/passbook-tab/passbook-tab.component.ts
index 71517bdfd..697d53a5c 100644
--- a/src/app/current-accounts/current-account-view/passbook-tab/passbook-tab.component.ts
+++ b/src/app/current-accounts/current-account-view/passbook-tab/passbook-tab.component.ts
@@ -152,46 +152,294 @@ export class PassbookTabComponent implements OnInit, OnDestroy {
}
printPassbook(): void {
- const content = this.passbookContent?.nativeElement?.innerHTML;
- if (!content) return;
+ const source = this.passbookContent?.nativeElement as HTMLElement;
+ if (!source) return;
+
+ /** Work on a copy so the on-screen statement is untouched */
+ const clone = source.cloneNode(true) as HTMLElement;
+ clone.querySelectorAll('.no-print').forEach((el: Element) => el.remove());
+
+ /** Material icon fonts are not available in the popup, so swap them for inline SVG */
+ clone.querySelectorAll('mat-icon, .mat-icon').forEach((el: Element) => {
+ const insideLogo = !!el.closest('.bank-logo-circle');
+ if (insideLogo) {
+ el.outerHTML = PassbookTabComponent.BANK_LOGO_SVG;
+ } else {
+ el.remove();
+ }
+ });
+
+ const printWindow = window.open('', 'Passbook', 'height=800,width=1100');
+ if (!printWindow) return;
- const printWindow = window.open('', 'Passbook', 'height=700,width=900');
printWindow.document.write(`
+
Current Account Passbook - ${this.accountNo}
-
+
- ${content}
+ ${clone.outerHTML}
+
`);
printWindow.document.close();
printWindow.focus();
- printWindow.print();
- printWindow.close();
}
+ /** Material "account_balance" glyph, inlined so the print window needs no icon font */
+ private static readonly BANK_LOGO_SVG = `
+ `;
+
+ /**
+ * Mirrors passbook-tab.component.scss so the printed statement looks like the
+ * on-screen one. Kept in sync manually - component styles are scoped and are
+ * not reachable from the popup window.
+ */
+ private static readonly PRINT_STYLES = `
+ @page { size: A4 portrait; margin: 10mm; }
+
+ * { margin: 0; padding: 0; box-sizing: border-box; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
+
+ body {
+ font-family: 'Segoe UI', Arial, sans-serif;
+ color: #333;
+ background: #fff;
+ }
+
+ .statement-print-page { padding: 0; }
+
+ .statement-wrapper {
+ background: #fff;
+ border: 1px solid #d0d7e3;
+ border-radius: 6px;
+ overflow: hidden;
+ }
+
+ /* Bank header */
+ .bank-header {
+ background: #1a3a6b;
+ padding: 14px 20px;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ border-bottom: 4px solid #c8a951;
+ }
+
+ .bank-logo-area { display: flex; align-items: center; gap: 12px; }
+
+ .bank-logo-circle {
+ width: 44px;
+ height: 44px;
+ border-radius: 50%;
+ background: #c8a951;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ }
+
+ .bank-logo-svg { fill: #1a3a6b; display: block; }
+
+ .bank-name-block .bank-title {
+ color: #fff;
+ font-size: 16px;
+ font-weight: 700;
+ letter-spacing: 0.3px;
+ }
+
+ .bank-name-block .bank-subtitle {
+ color: #c8a951;
+ font-size: 10px;
+ font-weight: 500;
+ letter-spacing: 1.5px;
+ text-transform: uppercase;
+ margin-top: 2px;
+ }
+
+ .statement-label { text-align: right; }
+
+ .statement-label .stmt-label-text {
+ color: #c8a951;
+ font-size: 12px;
+ font-weight: 700;
+ letter-spacing: 2px;
+ text-transform: uppercase;
+ }
+
+ .statement-label .stmt-period {
+ color: rgba(255, 255, 255, 0.75);
+ font-size: 10px;
+ margin-top: 3px;
+ }
+
+ /* Account details band */
+ .account-details-band {
+ background: #f0f3f9;
+ border-bottom: 1px solid #d0d7e3;
+ padding: 12px 20px;
+ }
+
+ .account-details-grid {
+ display: grid;
+ grid-template-columns: repeat(3, 1fr);
+ gap: 10px 24px;
+ }
+
+ .detail-block .detail-label {
+ font-size: 8.5px;
+ font-weight: 700;
+ color: #7a8aaa;
+ text-transform: uppercase;
+ letter-spacing: 0.8px;
+ margin-bottom: 2px;
+ }
+
+ .detail-block .detail-value { font-size: 12px; color: #222; }
+ .detail-block .detail-value.bold { font-weight: 600; }
+ .detail-block .detail-value.mono { font-family: 'Courier New', monospace; letter-spacing: 1px; }
+
+ .detail-block .detail-value.status-badge {
+ display: inline-block;
+ padding: 1px 8px;
+ border-radius: 10px;
+ font-size: 10px;
+ font-weight: 600;
+ background: #eee;
+ color: #555;
+ }
+
+ .detail-block .detail-value.status-badge.active { background: #d4edda; color: #155724; }
+
+ /* Balance summary strip */
+ .balance-summary-strip {
+ display: flex;
+ align-items: stretch;
+ background: #1a3a6b;
+ }
+
+ .balance-box { flex: 1; padding: 10px 18px; text-align: center; }
+
+ .balance-box .balance-box-label {
+ font-size: 9px;
+ font-weight: 600;
+ color: rgba(255, 255, 255, 0.65);
+ text-transform: uppercase;
+ letter-spacing: 1px;
+ margin-bottom: 3px;
+ }
+
+ .balance-box .balance-box-value { font-size: 15px; font-weight: 700; color: #c8a951; }
+
+ .balance-divider { width: 1px; background: rgba(255, 255, 255, 0.15); margin: 6px 0; }
+
+ /* Transactions table */
+ .statement-table { width: 100%; border-collapse: collapse; font-size: 11px; }
+
+ .statement-table thead { display: table-header-group; }
+ .statement-table tfoot { display: table-row-group; }
+ .statement-table tr { page-break-inside: avoid; break-inside: avoid; }
+
+ .statement-table thead tr {
+ background: #e8edf5;
+ border-top: 1px solid #d0d7e3;
+ border-bottom: 2px solid #1a3a6b;
+ }
+
+ .statement-table thead th {
+ padding: 8px 9px;
+ font-size: 10px;
+ font-weight: 700;
+ color: #1a3a6b;
+ text-transform: uppercase;
+ letter-spacing: 0.4px;
+ white-space: nowrap;
+ text-align: left;
+ }
+
+ .statement-table tbody tr { border-bottom: 1px solid #e8ecf3; }
+ .statement-table tbody tr:nth-child(even) { background: #f4f7fb; }
+ .statement-table tbody tr.reversed-row { opacity: 0.55; text-decoration: line-through; }
+ .statement-table tbody td { padding: 6px 9px; vertical-align: middle; color: #333; }
+
+ .statement-table tfoot .total-row { background: #e8edf5; border-top: 2px solid #1a3a6b; }
+ .statement-table tfoot .total-row td { padding: 8px 9px; }
+
+ /* Column widths */
+ .col-sr { width: 34px; }
+ .col-date { width: 100px; white-space: nowrap; }
+ .col-desc { min-width: 150px; }
+ .col-ref { width: 74px; }
+ .col-amount { width: 100px; }
+ .col-balance { width: 110px; }
+
+ /* Amount colors */
+ .debit-amount { color: #c0392b; font-weight: 500; }
+ .credit-amount { color: #1a7a3f; font-weight: 500; }
+ .balance-amount { color: #1a3a6b; font-weight: 600; font-family: 'Courier New', monospace; }
+
+ .total-label {
+ font-size: 11px;
+ font-weight: 700;
+ color: #1a3a6b;
+ text-transform: uppercase;
+ letter-spacing: 0.5px;
+ }
+
+ .closing-balance {
+ font-size: 13px;
+ font-weight: 700;
+ color: #1a3a6b;
+ font-family: 'Courier New', monospace;
+ }
+
+ /* Badges & misc */
+ .txn-desc { font-weight: 500; }
+
+ .reversed-badge {
+ display: inline-block;
+ margin-left: 6px;
+ font-size: 8px;
+ font-weight: 700;
+ color: #fff;
+ background: #e74c3c;
+ padding: 1px 5px;
+ border-radius: 3px;
+ letter-spacing: 0.5px;
+ }
+
+ .text-right { text-align: right; }
+ .text-center { text-align: center; }
+ .text-muted { color: #999; }
+ .mono { font-family: 'Courier New', monospace; font-size: 10px; }
+
+ /* No data */
+ .no-data-block { padding: 40px; text-align: center; color: #aaa; font-size: 13px; }
+
+ /* Footer */
+ .statement-footer {
+ background: #f0f3f9;
+ border-top: 1px solid #d0d7e3;
+ padding: 10px 20px;
+ text-align: center;
+ }
+
+ .statement-footer .footer-note {
+ font-size: 9px;
+ color: #888;
+ margin-bottom: 3px;
+ font-style: italic;
+ }
+
+ .statement-footer .footer-meta { font-size: 9px; color: #aaa; letter-spacing: 0.3px; }
+ `;
+
ngOnDestroy(): void {
this.destroy$.next();
this.destroy$.complete();
diff --git a/src/app/savings/savings-account-view/passbook-tab/passbook-tab.component.ts b/src/app/savings/savings-account-view/passbook-tab/passbook-tab.component.ts
index 6be1eca86..be2127a28 100644
--- a/src/app/savings/savings-account-view/passbook-tab/passbook-tab.component.ts
+++ b/src/app/savings/savings-account-view/passbook-tab/passbook-tab.component.ts
@@ -142,46 +142,294 @@ export class PassbookTabComponent implements OnInit, OnDestroy {
}
printPassbook(): void {
- const content = this.passbookContent?.nativeElement?.innerHTML;
- if (!content) return;
+ const source = this.passbookContent?.nativeElement as HTMLElement;
+ if (!source) return;
+
+ /** Work on a copy so the on-screen statement is untouched */
+ const clone = source.cloneNode(true) as HTMLElement;
+ clone.querySelectorAll('.no-print').forEach((el: Element) => el.remove());
+
+ /** Material icon fonts are not available in the popup, so swap them for inline SVG */
+ clone.querySelectorAll('mat-icon, .mat-icon').forEach((el: Element) => {
+ const insideLogo = !!el.closest('.bank-logo-circle');
+ if (insideLogo) {
+ el.outerHTML = PassbookTabComponent.BANK_LOGO_SVG;
+ } else {
+ el.remove();
+ }
+ });
+
+ const printWindow = window.open('', 'Passbook', 'height=800,width=1100');
+ if (!printWindow) return;
- const printWindow = window.open('', 'Passbook', 'height=700,width=900');
printWindow.document.write(`
+
Savings Account Passbook - ${this.accountNo}
-
+
- ${content}
+ ${clone.outerHTML}
+
`);
printWindow.document.close();
printWindow.focus();
- printWindow.print();
- printWindow.close();
}
+ /** Material "account_balance" glyph, inlined so the print window needs no icon font */
+ private static readonly BANK_LOGO_SVG = `
+ `;
+
+ /**
+ * Mirrors passbook-tab.component.scss so the printed statement looks like the
+ * on-screen one. Kept in sync manually - component styles are scoped and are
+ * not reachable from the popup window.
+ */
+ private static readonly PRINT_STYLES = `
+ @page { size: A4 portrait; margin: 10mm; }
+
+ * { margin: 0; padding: 0; box-sizing: border-box; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
+
+ body {
+ font-family: 'Segoe UI', Arial, sans-serif;
+ color: #333;
+ background: #fff;
+ }
+
+ .statement-print-page { padding: 0; }
+
+ .statement-wrapper {
+ background: #fff;
+ border: 1px solid #d0d7e3;
+ border-radius: 6px;
+ overflow: hidden;
+ }
+
+ /* Bank header */
+ .bank-header {
+ background: #1a3a6b;
+ padding: 14px 20px;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ border-bottom: 4px solid #c8a951;
+ }
+
+ .bank-logo-area { display: flex; align-items: center; gap: 12px; }
+
+ .bank-logo-circle {
+ width: 44px;
+ height: 44px;
+ border-radius: 50%;
+ background: #c8a951;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ }
+
+ .bank-logo-svg { fill: #1a3a6b; display: block; }
+
+ .bank-name-block .bank-title {
+ color: #fff;
+ font-size: 16px;
+ font-weight: 700;
+ letter-spacing: 0.3px;
+ }
+
+ .bank-name-block .bank-subtitle {
+ color: #c8a951;
+ font-size: 10px;
+ font-weight: 500;
+ letter-spacing: 1.5px;
+ text-transform: uppercase;
+ margin-top: 2px;
+ }
+
+ .statement-label { text-align: right; }
+
+ .statement-label .stmt-label-text {
+ color: #c8a951;
+ font-size: 12px;
+ font-weight: 700;
+ letter-spacing: 2px;
+ text-transform: uppercase;
+ }
+
+ .statement-label .stmt-period {
+ color: rgba(255, 255, 255, 0.75);
+ font-size: 10px;
+ margin-top: 3px;
+ }
+
+ /* Account details band */
+ .account-details-band {
+ background: #f0f3f9;
+ border-bottom: 1px solid #d0d7e3;
+ padding: 12px 20px;
+ }
+
+ .account-details-grid {
+ display: grid;
+ grid-template-columns: repeat(3, 1fr);
+ gap: 10px 24px;
+ }
+
+ .detail-block .detail-label {
+ font-size: 8.5px;
+ font-weight: 700;
+ color: #7a8aaa;
+ text-transform: uppercase;
+ letter-spacing: 0.8px;
+ margin-bottom: 2px;
+ }
+
+ .detail-block .detail-value { font-size: 12px; color: #222; }
+ .detail-block .detail-value.bold { font-weight: 600; }
+ .detail-block .detail-value.mono { font-family: 'Courier New', monospace; letter-spacing: 1px; }
+
+ .detail-block .detail-value.status-badge {
+ display: inline-block;
+ padding: 1px 8px;
+ border-radius: 10px;
+ font-size: 10px;
+ font-weight: 600;
+ background: #eee;
+ color: #555;
+ }
+
+ .detail-block .detail-value.status-badge.active { background: #d4edda; color: #155724; }
+
+ /* Balance summary strip */
+ .balance-summary-strip {
+ display: flex;
+ align-items: stretch;
+ background: #1a3a6b;
+ }
+
+ .balance-box { flex: 1; padding: 10px 18px; text-align: center; }
+
+ .balance-box .balance-box-label {
+ font-size: 9px;
+ font-weight: 600;
+ color: rgba(255, 255, 255, 0.65);
+ text-transform: uppercase;
+ letter-spacing: 1px;
+ margin-bottom: 3px;
+ }
+
+ .balance-box .balance-box-value { font-size: 15px; font-weight: 700; color: #c8a951; }
+
+ .balance-divider { width: 1px; background: rgba(255, 255, 255, 0.15); margin: 6px 0; }
+
+ /* Transactions table */
+ .statement-table { width: 100%; border-collapse: collapse; font-size: 11px; }
+
+ .statement-table thead { display: table-header-group; }
+ .statement-table tfoot { display: table-row-group; }
+ .statement-table tr { page-break-inside: avoid; break-inside: avoid; }
+
+ .statement-table thead tr {
+ background: #e8edf5;
+ border-top: 1px solid #d0d7e3;
+ border-bottom: 2px solid #1a3a6b;
+ }
+
+ .statement-table thead th {
+ padding: 8px 9px;
+ font-size: 10px;
+ font-weight: 700;
+ color: #1a3a6b;
+ text-transform: uppercase;
+ letter-spacing: 0.4px;
+ white-space: nowrap;
+ text-align: left;
+ }
+
+ .statement-table tbody tr { border-bottom: 1px solid #e8ecf3; }
+ .statement-table tbody tr:nth-child(even) { background: #f4f7fb; }
+ .statement-table tbody tr.reversed-row { opacity: 0.55; text-decoration: line-through; }
+ .statement-table tbody td { padding: 6px 9px; vertical-align: middle; color: #333; }
+
+ .statement-table tfoot .total-row { background: #e8edf5; border-top: 2px solid #1a3a6b; }
+ .statement-table tfoot .total-row td { padding: 8px 9px; }
+
+ /* Column widths */
+ .col-sr { width: 34px; }
+ .col-date { width: 100px; white-space: nowrap; }
+ .col-desc { min-width: 150px; }
+ .col-ref { width: 74px; }
+ .col-amount { width: 100px; }
+ .col-balance { width: 110px; }
+
+ /* Amount colors */
+ .debit-amount { color: #c0392b; font-weight: 500; }
+ .credit-amount { color: #1a7a3f; font-weight: 500; }
+ .balance-amount { color: #1a3a6b; font-weight: 600; font-family: 'Courier New', monospace; }
+
+ .total-label {
+ font-size: 11px;
+ font-weight: 700;
+ color: #1a3a6b;
+ text-transform: uppercase;
+ letter-spacing: 0.5px;
+ }
+
+ .closing-balance {
+ font-size: 13px;
+ font-weight: 700;
+ color: #1a3a6b;
+ font-family: 'Courier New', monospace;
+ }
+
+ /* Badges & misc */
+ .txn-desc { font-weight: 500; }
+
+ .reversed-badge {
+ display: inline-block;
+ margin-left: 6px;
+ font-size: 8px;
+ font-weight: 700;
+ color: #fff;
+ background: #e74c3c;
+ padding: 1px 5px;
+ border-radius: 3px;
+ letter-spacing: 0.5px;
+ }
+
+ .text-right { text-align: right; }
+ .text-center { text-align: center; }
+ .text-muted { color: #999; }
+ .mono { font-family: 'Courier New', monospace; font-size: 10px; }
+
+ /* No data */
+ .no-data-block { padding: 40px; text-align: center; color: #aaa; font-size: 13px; }
+
+ /* Footer */
+ .statement-footer {
+ background: #f0f3f9;
+ border-top: 1px solid #d0d7e3;
+ padding: 10px 20px;
+ text-align: center;
+ }
+
+ .statement-footer .footer-note {
+ font-size: 9px;
+ color: #888;
+ margin-bottom: 3px;
+ font-style: italic;
+ }
+
+ .statement-footer .footer-meta { font-size: 9px; color: #aaa; letter-spacing: 0.3px; }
+ `;
+
private recalculateRunningBalances(transactions: SavingsAccountTransaction[]): SavingsAccountTransaction[] {
let balance = 0;
return transactions.map((txn) => {
diff --git a/src/app/shares/shares-account-view/passbook-tab/passbook-tab.component.ts b/src/app/shares/shares-account-view/passbook-tab/passbook-tab.component.ts
index da843b90a..e2aa7545e 100644
--- a/src/app/shares/shares-account-view/passbook-tab/passbook-tab.component.ts
+++ b/src/app/shares/shares-account-view/passbook-tab/passbook-tab.component.ts
@@ -133,36 +133,284 @@ export class SharesPassbookTabComponent implements OnInit {
}
printPassbook(): void {
- const content = this.passbookContent?.nativeElement?.innerHTML;
- if (!content) return;
+ const source = this.passbookContent?.nativeElement as HTMLElement;
+ if (!source) return;
+
+ /** Work on a copy so the on-screen passbook is untouched */
+ const clone = source.cloneNode(true) as HTMLElement;
+ clone.querySelectorAll('.no-print').forEach((el: Element) => el.remove());
+
+ /** Material icon fonts are not available in the popup, so swap them for inline SVG */
+ clone.querySelectorAll('mat-icon, .mat-icon').forEach((el: Element) => {
+ const insideLogo = !!el.closest('.bank-logo-circle');
+ if (insideLogo) {
+ el.outerHTML = SharesPassbookTabComponent.BANK_LOGO_SVG;
+ } else {
+ el.remove();
+ }
+ });
+
+ const printWindow = window.open('', 'SharePassbook', 'height=800,width=1200');
+ if (!printWindow) return;
- const printWindow = window.open('', 'SharePassbook', 'height=700,width=900');
printWindow.document.write(`
+
Share Account Passbook - ${this.accountNo}
-
+
- ${content}
+ ${clone.outerHTML}
+
`);
printWindow.document.close();
printWindow.focus();
- printWindow.print();
- printWindow.close();
}
+ /** Material "account_balance" glyph, inlined so the print window needs no icon font */
+ private static readonly BANK_LOGO_SVG = `
+ `;
+
+ /**
+ * Mirrors passbook-tab.component.scss so the printed passbook looks like the
+ * on-screen one. Kept in sync manually - component styles are scoped and are
+ * not reachable from the popup window. Landscape, because the share ledger
+ * carries nine columns including the Resolution No. / Meeting column.
+ */
+ private static readonly PRINT_STYLES = `
+ @page { size: A4 landscape; margin: 8mm; }
+
+ * { margin: 0; padding: 0; box-sizing: border-box; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
+
+ body {
+ font-family: 'Segoe UI', Arial, sans-serif;
+ color: #333;
+ background: #fff;
+ }
+
+ .statement-print-page { padding: 0; }
+
+ .statement-wrapper {
+ background: #fff;
+ border: 1px solid #d0d7e3;
+ border-radius: 6px;
+ overflow: hidden;
+ }
+
+ /* Bank header */
+ .bank-header {
+ background: #1a3a6b;
+ padding: 14px 20px;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ border-bottom: 4px solid #c8a951;
+ }
+
+ .bank-logo-area { display: flex; align-items: center; gap: 12px; }
+
+ .bank-logo-circle {
+ width: 44px;
+ height: 44px;
+ border-radius: 50%;
+ background: #c8a951;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ }
+
+ .bank-logo-svg { fill: #1a3a6b; display: block; }
+
+ .bank-name-block .bank-title {
+ color: #fff;
+ font-size: 16px;
+ font-weight: 700;
+ letter-spacing: 0.3px;
+ }
+
+ .bank-name-block .bank-subtitle {
+ color: #c8a951;
+ font-size: 10px;
+ font-weight: 500;
+ letter-spacing: 1.5px;
+ text-transform: uppercase;
+ margin-top: 2px;
+ }
+
+ .statement-label { text-align: right; }
+
+ .statement-label .stmt-label-text {
+ color: #c8a951;
+ font-size: 12px;
+ font-weight: 700;
+ letter-spacing: 2px;
+ text-transform: uppercase;
+ }
+
+ .statement-label .stmt-period {
+ color: rgba(255, 255, 255, 0.75);
+ font-size: 10px;
+ margin-top: 3px;
+ }
+
+ /* Account details band */
+ .account-details-band {
+ background: #f0f3f9;
+ border-bottom: 1px solid #d0d7e3;
+ padding: 12px 20px;
+ }
+
+ .account-details-grid {
+ display: grid;
+ grid-template-columns: repeat(4, 1fr);
+ gap: 10px 24px;
+ }
+
+ .detail-block .detail-label {
+ font-size: 8.5px;
+ font-weight: 700;
+ color: #7a8aaa;
+ text-transform: uppercase;
+ letter-spacing: 0.8px;
+ margin-bottom: 2px;
+ }
+
+ .detail-block .detail-value { font-size: 12px; color: #222; }
+ .detail-block .detail-value.bold { font-weight: 600; }
+ .detail-block .detail-value.mono { font-family: 'Courier New', monospace; letter-spacing: 1px; }
+
+ .detail-block .detail-value.status-badge {
+ display: inline-block;
+ padding: 1px 8px;
+ border-radius: 10px;
+ font-size: 10px;
+ font-weight: 600;
+ background: #eee;
+ color: #555;
+ }
+
+ .detail-block .detail-value.status-badge.active { background: #d4edda; color: #155724; }
+
+ /* Share summary strip */
+ .balance-summary-strip {
+ display: flex;
+ align-items: stretch;
+ background: #1a3a6b;
+ }
+
+ .balance-box { flex: 1; padding: 10px 18px; text-align: center; }
+
+ .balance-box .balance-box-label {
+ font-size: 9px;
+ font-weight: 600;
+ color: rgba(255, 255, 255, 0.65);
+ text-transform: uppercase;
+ letter-spacing: 1px;
+ margin-bottom: 3px;
+ }
+
+ .balance-box .balance-box-value { font-size: 15px; font-weight: 700; color: #c8a951; }
+
+ .balance-divider { width: 1px; background: rgba(255, 255, 255, 0.15); margin: 6px 0; }
+
+ /* Ledger table - no horizontal scroll on paper, the landscape page holds every column */
+ .statement-table-scroll { width: 100%; overflow: visible; }
+
+ .statement-table { width: 100%; border-collapse: collapse; font-size: 10.5px; }
+
+ .statement-table thead { display: table-header-group; }
+ .statement-table tfoot { display: table-row-group; }
+ .statement-table tr { page-break-inside: avoid; break-inside: avoid; }
+
+ .statement-table thead tr {
+ background: #e8edf5;
+ border-top: 1px solid #d0d7e3;
+ border-bottom: 2px solid #1a3a6b;
+ }
+
+ .statement-table thead th {
+ padding: 8px 9px;
+ font-size: 9.5px;
+ font-weight: 700;
+ color: #1a3a6b;
+ text-transform: uppercase;
+ letter-spacing: 0.4px;
+ white-space: nowrap;
+ }
+
+ .statement-table tbody tr { border-bottom: 1px solid #e8ecf3; }
+ .statement-table tbody tr:nth-child(even) { background: #f4f7fb; }
+ .statement-table tbody td { padding: 6px 9px; vertical-align: middle; color: #333; }
+
+ .statement-table tfoot .total-row { background: #e8edf5; border-top: 2px solid #1a3a6b; }
+ .statement-table tfoot .total-row td { padding: 8px 9px; }
+
+ /* Column widths */
+ .col-sr { width: 32px; }
+ .col-date { width: 96px; white-space: nowrap; }
+ .col-desc { width: auto; min-width: 140px; }
+ .col-ref { width: 70px; white-space: nowrap; }
+ .col-amount { width: 108px; white-space: nowrap; }
+ .col-balance { width: 96px; white-space: nowrap; }
+ .col-resolution { width: 170px; white-space: nowrap; padding-left: 14px; }
+
+ /* Share movement colors */
+ .debit-amount { color: #c0392b; font-weight: 500; }
+ .credit-amount { color: #1a7a3f; font-weight: 500; }
+ .balance-amount { color: #1a3a6b; font-weight: 600; font-family: 'Courier New', monospace; }
+
+ .total-label {
+ font-size: 10.5px;
+ font-weight: 700;
+ color: #1a3a6b;
+ text-transform: uppercase;
+ letter-spacing: 0.5px;
+ }
+
+ .closing-balance {
+ font-size: 12.5px;
+ font-weight: 700;
+ color: #1a3a6b;
+ font-family: 'Courier New', monospace;
+ }
+
+ /* Misc */
+ .txn-desc { font-weight: 500; }
+ .text-right { text-align: right; }
+ .text-center { text-align: center; }
+ .text-left { text-align: left; }
+ .text-muted { color: #999; }
+ .mono { font-family: 'Courier New', monospace; font-size: 10px; }
+
+ /* No data */
+ .no-data-block { padding: 40px; text-align: center; color: #aaa; font-size: 13px; }
+
+ /* Footer */
+ .statement-footer {
+ background: #f0f3f9;
+ border-top: 1px solid #d0d7e3;
+ padding: 10px 20px;
+ text-align: center;
+ }
+
+ .statement-footer .footer-note {
+ font-size: 9px;
+ color: #888;
+ margin-bottom: 3px;
+ font-style: italic;
+ }
+
+ .statement-footer .footer-meta { font-size: 9px; color: #aaa; letter-spacing: 0.3px; }
+ `;
+
private recalculateRunningBalances(transactions: any[]): any[] {
let balance = 0;
return transactions.map((txn) => {