/** * 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/. */ /* stylelint-disable no-duplicate-selectors -- the compact-density pass below deliberately re-opens earlier rules; kept in cascade order */ $primary: #0f766e; $primary-dark: #0f4f3c; $primary-light: #e6f4ee; $border: #e2e8f0; $text-dark: #0f172a; $text-mid: #475569; $text-soft: #94a3b8; $danger: #b91c1c; .dte-container { // Wider than a normal form page: a collection row carries six fields side by side, and a clerk // keying a round should see the whole of it. max-width: 1280px; margin: 0 auto; padding: 20px 16px; } .dte-header { display: flex; align-items: center; gap: 14px; margin-bottom: 20px; &__icon { display: grid; place-items: center; flex: 0 0 auto; width: 46px; height: 46px; border-radius: 14px; background: linear-gradient(135deg, $primary 0%, $primary-dark 100%); color: #fff; font-size: 19px; box-shadow: 0 6px 16px rgb(15 79 60 / 22%); } &__text { min-width: 0; } &__title { margin: 0; font-size: 22px; font-weight: 600; color: $text-dark; } &__sub { margin: 2px 0 0; font-size: 13px; color: $text-mid; } } .dte-back { color: $primary; } .dte-card { background: var(--md-sys-color-surface, #fff); border: 1px solid $border; border-radius: 14px; box-shadow: 0 2px 10px rgb(15 23 42 / 6%); padding: 20px 24px 24px; } .dte-info-panels { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; margin-bottom: 18px; } .dte-info-panel { border: 1px solid $border; border-radius: 12px; padding: 14px 18px 12px; background: linear-gradient(180deg, #f8fafc 0%, #fff 100%); &__title { display: flex; align-items: center; gap: 8px; margin-bottom: 10px; padding-bottom: 8px; border-bottom: 1px solid $border; font-weight: 700; font-size: 12.5px; text-transform: uppercase; letter-spacing: 0.06em; color: $primary-dark; i { display: grid; place-items: center; width: 26px; height: 26px; border-radius: 8px; background: $primary-light; color: $primary-dark; font-size: 12px; } } &__hint { display: flex; align-items: flex-start; gap: 8px; margin: 0; color: $text-mid; font-size: 13px; line-height: 1.5; i { margin-top: 3px; color: $text-soft; } } dl { display: grid; grid-template-columns: minmax(96px, auto) 1fr; gap: 0 14px; margin: 0; } dt, dd { padding: 6px 0; border-bottom: 1px dashed #edf2f7; } dt { font-weight: 600; color: $text-soft; font-size: 12px; text-transform: uppercase; letter-spacing: 0.03em; } dd { margin: 0; font-size: 13.5px; color: $text-dark; word-break: break-word; } } // The round at a glance: parties, entries, what to count, what the agent holds. .dte-kpis { display: grid; grid-template-columns: repeat(auto-fit, minmax(170px, 1fr)); gap: 12px; margin-bottom: 18px; } .dte-kpi { display: flex; flex-direction: column; gap: 3px; padding: 12px 16px; border: 1px solid $border; border-radius: 12px; background: #fff; box-shadow: 0 1px 3px rgb(15 23 42 / 5%); &__label { display: flex; align-items: center; gap: 6px; font-size: 11px; font-weight: 700; letter-spacing: 0.05em; text-transform: uppercase; color: $text-soft; i { color: $primary; } } &__value { font-size: 21px; font-weight: 700; color: $text-dark; font-variant-numeric: tabular-nums; } &__hint { font-size: 12px; color: $text-mid; } &--accent { background: $primary-light; border-color: #b7ddd0; .dte-kpi__value { color: $primary-dark; } } } .dte-controls { display: flex; align-items: flex-start; gap: 12px; flex-wrap: wrap; margin-bottom: 12px; padding: 14px 16px 0; border: 1px solid $border; border-radius: 12px; background: #f8fafc; } // A sensible floor for the fields laid out with flex in .dte-controls, where there is room to spare. .dte-field { min-width: 180px; &--wide { grid-column: span 2; } } // Inside the collection grid the track decides the width, not the field. Left to its own 180px // floor a field refuses to shrink into a narrower track and overruns the one beside it. .dte-collection-row .dte-field { width: 100%; min-width: 0; } .dte-section { margin-top: 16px; padding: 16px 18px 18px; border: 1px solid $border; border-radius: 12px; background: #fff; // A very narrow window scrolls the grid sideways rather than the whole page. overflow-x: auto; &__header { display: flex; align-items: center; gap: 10px; margin-bottom: 14px; padding-bottom: 12px; border-bottom: 1px solid $border; > i { display: grid; place-items: center; width: 30px; height: 30px; border-radius: 9px; background: $primary-light; color: $primary-dark; font-size: 13px; } h3 { margin: 0; font-size: 16px; font-weight: 600; color: $text-dark; flex: 1; } } } .dte-add-row { color: $primary; } .dte-empty { margin: 0; padding: 18px 16px; border: 1.5px dashed #cbd5e1; border-radius: 10px; background: #f8fafc; color: $text-mid; font-size: 14px; text-align: center; } .dte-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px 16px; // Withdraw Deposite: the two accounts each in a card of their own, then the amount and description. &--transfer { grid-template-columns: 1fr; } } .dte-party-card { padding: 12px 16px 2px; border: 1px solid $border; border-radius: 12px; background: #f8fafc; &__title { display: flex; align-items: center; gap: 8px; margin-bottom: 10px; font-size: 12px; font-weight: 700; letter-spacing: 0.05em; text-transform: uppercase; color: $text-mid; } &--to &__title i { color: #16a34a; } &--from &__title i { color: #d97706; } &__fields { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 0 16px; } } @media (width <= 900px) { .dte-party-card__fields { grid-template-columns: 1fr; } } /* * One collection per row. Fixed columns rather than an even split, so the row holds its shape as * fields come and go - Cheque No and Token No only appear for a non-cash entry - and the party * picker gets the width its "code · name · daily amount" needs. */ .dte-collection-row { display: grid; grid-template-columns: minmax(0, 2.2fr) /* Party */ minmax(0, 1fr) /* TRTP */ minmax(0, 1fr) /* AC Type */ minmax(0, 1.4fr) /* A/C No. */ minmax(0, 1fr) /* Amount */ minmax(0, 1.6fr) /* Description */ auto; /* remove */ gap: 8px 12px; align-items: start; padding: 10px 0; border-top: 1px dashed rgb(0 0 0 / 10%); &:first-of-type { border-top: none; } // Cheque No and Token No push Description and the remove button onto a second line, which is // what a non-cash entry should look like rather than a row running off the screen. &:has(.dte-field--instrument) { grid-template-columns: minmax(0, 2.2fr) minmax(0, 1fr) minmax(0, 1fr) minmax(0, 1.4fr) minmax(0, 1fr) minmax(0, 1fr) minmax(0, 1fr) minmax(0, 1.6fr) auto; } } .dte-collection-row .dte-field--wide { grid-column: span 2; } @media (width <= 1200px) { .dte-collection-row, .dte-collection-row:has(.dte-field--instrument) { grid-template-columns: repeat(3, minmax(0, 1fr)) auto; } } .dte-remove-row { color: #b91c1c; margin-top: 8px; } .dte-action-bar { display: flex; justify-content: flex-end; gap: 12px; margin-top: 20px; padding: 14px 16px; border: 1px solid $border; border-radius: 12px; background: #f8fafc; flex-wrap: wrap; } @media (width <= 1000px) { .dte-info-panels { grid-template-columns: 1fr; } .dte-grid { grid-template-columns: repeat(2, 1fr); } .dte-collection-row { grid-template-columns: repeat(2, 1fr); } } /* Resolved name under an Agent / Party Code field — the check that the right record was found. */ .dte-hint--found { color: #15803d; font-weight: 500; } .dte-hint--missing { color: #b91c1c; font-weight: 500; } /* Marks an agent in the list who is no longer collecting - only offered for settlement. */ .dte-agent-off { color: #b45309; font-size: 12px; font-style: italic; margin-left: 6px; } /* The figure the clerk actually verifies against the passbook before saving. */ .dte-after { font-weight: 600; color: #0f766e; } /* What the agent should be handing over for this round. */ .dte-total { display: flex; justify-content: flex-end; align-items: baseline; gap: 14px; margin-top: 6px; padding: 12px 14px; border-radius: 10px; background: $primary-light; font-size: 0.88rem; color: $text-mid; strong { font-size: 1.15rem; color: $primary-dark; font-variant-numeric: tabular-nums; } } /* Marks a transaction type the system does not handle yet, so it reads as pending rather than broken. */ .dte-soon { font-size: 0.78rem; font-style: italic; color: rgb(0 0 0 / 45%); } /* * Marks a party this agent has already collected from today, on the row where it is picked. * * Amber, not red: a customer paying twice in a day is legitimate - arrears, or two days at once - * so this is a second look, not an error. Blocking it would stop real work; saying nothing lets a * whole round be credited twice. */ .dte-hint--again { color: #b45309; font-weight: 500; } /* * Where a party stands against its instalments. Three states rather than one colour, because they * call for three different things from the clerk: ahead means take nothing, behind means take more * than the daily amount, level means take the daily amount as usual. * * Behind is amber, not red - falling a few days behind is ordinary in daily collection and is the * agent's job to recover, not an error. Red here would cry wolf on most rows. */ .dte-hint--ahead, .dte-sched--ahead { color: #15803d; font-weight: 500; } .dte-hint--behind, .dte-sched--behind { color: #b45309; font-weight: 500; } .dte-hint--level, .dte-sched--level { color: rgb(0 0 0 / 55%); } /* In the party panel the schedule line carries more weight than the fields around it. */ .dte-sched { font-weight: 500; } /* Says why a party in the list cannot be picked, beside the party rather than in a tooltip. */ .dte-covered { color: #15803d; font-size: 0.8rem; } /* * An amount that looks like a slip. Red rather than the amber used for arrears: arrears are ordinary * and the agent's job to recover, while this is a figure that probably was not handed over at all, * and once saved it cannot be taken back. It still does not block - the clerk decides. */ .dte-hint--overpay { color: #b91c1c; font-weight: 500; } /* The agent's written-down round, as the counter reads it. Laid out as lines rather than as the input grid this replaced: there is nothing to fill in here, only a list to check a bag of cash against, and controls would invite editing something the clerk has no business editing. */ .dte-pending-row { display: flex; align-items: center; gap: 12px; padding: 11px 12px; border-bottom: 1px solid #eef2f6; &:last-of-type { border-bottom: none; } &:hover { background: #f8fafc; } /* First, and in the quieter weight: the date is context for the line, not what is being read. */ &__date { min-width: 96px; color: $text-mid; font-variant-numeric: tabular-nums; } &__code { font-weight: 700; min-width: 84px; color: $primary-dark; font-family: ui-monospace, 'SF Mono', 'Cascadia Mono', Consolas, monospace; font-size: 13px; } &__name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: $text-dark; } // The mode of payment as a small label rather than loose capitals. &__mode { padding: 2px 10px; border-radius: 999px; background: #eef2ff; color: #3730a3; font-size: 11px; font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase; white-space: nowrap; } /* Amounts are read down the column and compared, so the digits have to line up. */ &__amount { font-variant-numeric: tabular-nums; font-weight: 700; min-width: 96px; text-align: right; color: $text-dark; } } /* A line that can be clicked to show its party above, and the one currently shown. */ .dte-pending-row--pick { cursor: pointer; } .dte-pending-row--active { background: #eef6f3; box-shadow: inset 3px 0 0 $primary; } /* Names the columns of the lines below, in the same widths so they sit over them. */ .dte-pending-head { display: flex; align-items: center; gap: 12px; padding: 8px 12px; border-radius: 8px; background: #f1f5f9; span { font-size: 11px; font-weight: 700; letter-spacing: 0.05em; text-transform: uppercase; color: $text-soft; } .dte-pending-row__mode { padding: 0; background: none; color: $text-soft; } } /* The one figure the clerk acts on, said as a sentence so it is not read as another column total. */ .dte-expected { margin: 14px 0 0; padding: 10px 14px; border-left: 3px solid $primary; border-radius: 0 8px 8px 0; background: #f0fdf9; font-size: 14px; line-height: 1.5; color: $text-dark; strong { font-variant-numeric: tabular-nums; } } /* Quieter than the figure above it: a note about how the screen behaves, not part of the count. */ .dte-expected--note { border-left-color: #cbd5e1; background: #f8fafc; font-size: 13px; color: $text-mid; margin-top: 8px; } .dte-apply-receipt { margin-left: 8px; } /* Agent Tran: what the agent owes, what the cashier has taken in, and what is left. */ .dte-money { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px; margin: 12px 0; &__box { padding: 14px 18px; border: 1px solid $border; border-radius: 12px; display: flex; flex-direction: column; gap: 6px; background: #fff; box-shadow: 0 1px 3px rgb(15 23 42 / 5%); font-variant-numeric: tabular-nums; strong { font-size: 22px; color: $text-dark; } &--owed { background: #eff6ff; border-color: #bfdbfe; strong { color: #1d4ed8; } } &--received { background: #f0fdf4; border-color: #bbf7d0; strong { color: #15803d; } } &--due { border-color: rgb(198 40 40 / 40%); background: #fef2f2; strong { color: $danger; } } } &__label { display: flex; align-items: center; gap: 7px; font-size: 11px; font-weight: 700; color: $text-mid; text-transform: uppercase; letter-spacing: 0.05em; } } @media (width <= 720px) { .dte-money { grid-template-columns: 1fr; } } .dte-subhead { display: flex; align-items: center; gap: 8px; margin: 20px 0 8px; font-size: 13px; font-weight: 700; letter-spacing: 0.04em; text-transform: uppercase; color: $text-mid; i { color: $primary; } } .dte-pending-row--day { cursor: pointer; background: #f8fafc; border-radius: 8px; margin-top: 4px; &:hover { background: #eef6f3; } } .dte-day-lines { margin: 0 0 6px 24px; max-height: 280px; overflow-y: auto; border-left: 3px solid #b7ddd0; padding-left: 10px; } .dte-status { font-size: 12px; font-weight: 600; padding: 3px 11px; border-radius: 999px; background: rgb(237 108 2 / 12%); color: #b45309; &--ok { background: rgb(46 125 50 / 12%); color: #2e7d32; } } .dte-list-arrow { cursor: pointer; } .dte-same-party { color: #c62828; font-weight: 600; } // ── Compact density ───────────────────────────────────────────────────────────────────────────────── // The whole screen a step smaller: type, spacing and the height of every field. It is a working screen // kept open all day, and at full size a round needed scrolling to be read. Everything above states the // look; this states the size, so one place says how big the page is. .dte-container { max-width: 1200px; padding: 10px 12px; font-size: 13px; // Material sizes every field on the page from these. --mat-form-field-container-height: 38px; --mat-form-field-container-vertical-padding: 8px; --mat-form-field-container-text-size: 13px; --mat-form-field-container-text-line-height: 20px; --mat-form-field-outlined-label-text-populated-size: 11px; --mat-form-field-subscript-text-size: 11px; --mat-select-trigger-text-size: 13px; // The datepicker's toggle and a field's icon buttons default to a 48px touch target, which reopens // the height just saved - and is why the Date box stood taller than the two beside it. ::ng-deep .mat-mdc-form-field-icon-suffix .mat-mdc-icon-button.mat-mdc-button-base { --mat-icon-button-state-layer-size: 30px; width: 30px; height: 30px; padding: 4px; } ::ng-deep .mat-mdc-form-field-icon-suffix .mat-datepicker-toggle svg { width: 16px; height: 16px; } ::ng-deep .mat-mdc-form-field-hint, ::ng-deep .mat-mdc-form-field-error { font-size: 11px; } ::ng-deep .mat-mdc-button-base { font-size: 12.5px; } } .dte-header { gap: 10px; margin-bottom: 10px; &__icon { width: 36px; height: 36px; border-radius: 11px; font-size: 15px; } &__title { font-size: 18px; } &__sub { font-size: 11.5px; } } .dte-card { padding: 12px 14px 14px; border-radius: 12px; } .dte-info-panels { gap: 10px; margin-bottom: 10px; } .dte-info-panel { padding: 8px 12px 6px; border-radius: 10px; &__title { gap: 7px; margin-bottom: 6px; padding-bottom: 6px; font-size: 11px; i { width: 22px; height: 22px; border-radius: 7px; font-size: 10.5px; } } &__hint { font-size: 12px; } dl { gap: 0 12px; } dt, dd { padding: 3px 0; } dt { font-size: 10.5px; } dd { font-size: 12.5px; } } .dte-kpis { grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 8px; margin-bottom: 10px; } .dte-kpi { gap: 1px; padding: 7px 12px; border-radius: 10px; &__label { font-size: 10px; } &__value { font-size: 16px; } &__hint { font-size: 11px; } } // The three controls the same size, whatever each holds: one width, one height, side by side. .dte-controls { align-items: flex-start; gap: 10px; margin-bottom: 8px; padding: 10px 12px; border-radius: 10px; .dte-field { flex: 0 0 240px; width: 240px; min-width: 0; } } // The button that opens the round: the same height as the fields beside it. .dte-view-btn { height: 38px; margin-left: auto; padding: 0 14px; border-radius: 8px; color: $primary-dark; border-color: #b7ddd0; background: $primary-light; i { margin-right: 6px; } &__count { margin-left: 8px; padding: 1px 8px; border-radius: 999px; background: $primary; color: #fff; font-size: 11px; font-weight: 700; } } .dte-section { margin-top: 10px; padding: 10px 12px 12px; border-radius: 10px; &__header { gap: 8px; margin-bottom: 8px; padding-bottom: 8px; > i { width: 24px; height: 24px; border-radius: 7px; font-size: 11px; } h3 { font-size: 14px; } } } .dte-empty { padding: 12px; font-size: 12.5px; } .dte-money { gap: 8px; margin: 8px 0; &__box { padding: 8px 12px; gap: 3px; border-radius: 10px; strong { font-size: 17px; } } &__label { font-size: 10px; } } .dte-subhead { margin: 12px 0 6px; font-size: 11.5px; } .dte-expected { margin-top: 8px; padding: 7px 10px; font-size: 12.5px; } .dte-expected--note { font-size: 12px; } .dte-pending-row { padding: 6px 10px; font-size: 12.5px; &__code { font-size: 12px; } &__mode { font-size: 10.5px; } } .dte-pending-head { padding: 6px 10px; span { font-size: 10px; } } .dte-party-card { padding: 8px 12px 0; border-radius: 10px; &__title { margin-bottom: 6px; font-size: 11px; } } .dte-action-bar { gap: 8px; margin-top: 12px; padding: 8px 12px; border-radius: 10px; } // ── Agent Tran summary tiles and the actions beside the Date ──────────────────────────────────────── // To take in blue, Received in green, Still to take in red once something is left: the colours the // Agent's cash section used, now on the summary tiles. .dte-kpi { &--owed { background: #eff6ff; border-color: #bfdbfe; .dte-kpi__value { color: #1d4ed8; } } &--received { background: #f0fdf4; border-color: #bbf7d0; .dte-kpi__value { color: #15803d; } } &--due { background: #fef2f2; border-color: rgb(198 40 40 / 40%); .dte-kpi__value { color: $danger; } } } // Notes under the summary: the GL the cash goes into, and anything that looks wrong. .dte-notes { display: grid; gap: 6px; margin: 0 0 8px; .dte-expected { margin: 0; } } // Refresh and Apply DDS Receipt, at the end of the row and the same height as the fields beside them. .dte-agent-actions { display: flex; align-items: center; gap: 8px; margin-left: auto; .dte-refresh-btn, .dte-apply-btn { height: 38px; padding: 0 14px; border-radius: 8px; font-size: 12.5px; i { margin-right: 6px; } } .dte-refresh-btn { color: $primary; } } // ── Party Information, wider and two pairs to a line ─────────────────────────────────────────────── // A party carries twice what an agent does, so listing it one pair to a line made the card the taller of // the two and pushed the rest of the screen down. It takes the larger share of the row and sets its // details out as two columns of label and value, which brings it level with the agent's card. .dte-info-panels { grid-template-columns: minmax(0, 1fr) minmax(0, 1.8fr); } .dte-info-panel--party { dl { grid-template-columns: minmax(64px, auto) minmax(0, 1fr) minmax(64px, auto) minmax(0, 1fr); gap: 0 14px; } // The schedule is a sentence, so it takes the rest of the line rather than being squeezed into half of it. dd.dte-sched { grid-column: span 3; } } @media (width <= 1000px) { .dte-info-panels { grid-template-columns: 1fr; } } @media (width <= 640px) { .dte-info-panel--party dl { grid-template-columns: minmax(64px, auto) minmax(0, 1fr); dd.dte-sched { grid-column: span 1; } } }