add payment_link and banks

This commit is contained in:
javad committed 2026-10-06 10:03:22 +03:30
1 parent 2ae79b1ca4
commit de3135b588
100 files changed
+6167 -47

No files matched your search

+121
View File
@@ -0,0 +1,121 @@
/* Chaharsu tokens follow design-prototypes/chaharsu/STYLE_GUIDE.md.
Page-scoped components: no global form or ticket composer overrides. */
.chaharsu{max-width:900px;margin:auto;color:#08376b;font-size:14px;line-height:1.7;overflow-wrap:anywhere}.chaharsu h1{font-size:24px;font-weight:900;line-height:1.5}.chaharsu h2{font-size:18px;font-weight:900}.chaharsu h3{font-size:14px;font-weight:800}.chaharsu p{margin-block:8px}.chaharsu-heading{margin-bottom:20px}.chaharsu-heading>a,.chaharsu-heading>span{color:#526c86;font-size:12px}.chaharsu-heading p{color:#526c86}.pay-card{background:#fff;border:1px solid #dce5ed;border-radius:20px;padding:16px;margin-block:12px}.pay-button,.pay-copy{display:inline-flex;align-items:center;justify-content:center;min-height:44px;padding:8px 16px;border:1px solid #08376b;border-radius:12px;background:#08376b;color:#fff;font:inherit;font-weight:800;text-decoration:none;cursor:pointer}.pay-button.secondary,.pay-copy{background:#fff;color:#08376b}.pay-actions,.service-actions{display:flex;gap:8px;flex-wrap:wrap;align-items:center}.pay-actions{margin-block:16px}.pay-button:focus-visible,.pay-copy:focus-visible,.chaharsu a:focus-visible,.chaharsu input:focus-visible,.chaharsu select:focus-visible,.chaharsu textarea:focus-visible,.payment-notice summary:focus-visible{outline:3px solid #1977ce;outline-offset:3px}.pay-button:disabled{opacity:.6;cursor:wait}.pay-form input:not([type=radio]):not([type=checkbox]),.pay-form select,.pay-form textarea,.pay-filters input,.pay-filters select,.pay-search input{width:100%;min-height:44px;border:1px solid #a1b4c7;border-radius:12px;padding:8px;font:inherit;font-size:16px;background:#fff;color:#08376b}.pay-form input[type=file]{padding:12px;border-style:dashed}.pay-form textarea{min-height:90px}.pay-field{margin-block:16px}.pay-field label{display:block;margin-bottom:6px;font-weight:700}.pay-field [type=radio],.pay-field [type=checkbox]{width:20px;height:20px;margin-inline:6px}.field-error,.pay-errors{color:#9f1f1f;font-size:14px;line-height:1.8}.pay-errors{border:1px solid #9f1f1f;background:#fff4f3;padding:12px;border-radius:12px;margin-block:12px}.pay-errors a{color:inherit;text-decoration:underline}.pay-form [aria-invalid=true]{border-color:#9f1f1f}.pay-today{font:inherit;color:#08376b;border:1px solid #dce5ed;border-radius:8px;min-height:44px;padding:4px 12px;background:#fff;margin-top:6px}.pay-supplement{background:#f6fbff;border-radius:12px;padding:12px;margin-block:12px}.payment-notice summary{cursor:pointer;min-height:44px;list-style-position:inside;display:flex;flex-wrap:wrap;gap:8px;align-items:center}.payment-notice summary strong{flex:1;min-width:120px}.payment-notice summary b{font-size:18px}.payment-notice summary small{width:100%;color:#526c86;font-size:12px}.payment-values>div{display:grid;grid-template-columns:1fr auto;gap:8px;padding-block:9px;border-bottom:1px solid #e7edf2}.payment-values dt{grid-column:1/-1;font-weight:700}.payment-values dd{font-size:16px;text-align:right;overflow-wrap:anywhere}.pay-search,.pay-filters{display:flex;gap:8px;flex-wrap:wrap}.pay-search input{flex:1;min-width:140px}.pay-filters>*{flex:1;min-width:130px}.pay-row{display:flex;flex-wrap:wrap;gap:12px;align-items:center;min-height:60px}.pay-row time{font-size:12px;color:#526c86}.pay-tabs,.pay-pagination{display:flex;gap:16px;margin-block:16px;align-items:center}.pay-tabs a,.pay-pagination a{min-height:44px;padding:8px}.receipt-preview{max-width:100%;max-height:600px;object-fit:contain;display:block;margin-block:12px}.service-grid{display:grid;grid-template-columns:1fr 1fr;gap:10px}.expert-service{grid-column:1/-1;border-radius:20px;background:#08376b;border-bottom:3px solid #fa9f00;padding:12px 14px;color:#fff}.expert-service p{color:#cadbea;font-size:14px;line-height:1.65}.expert-service h2{color:#fff}.service-actions>a{flex:1;padding-inline:8px;white-space:nowrap}.pay-button.light{color:#08376b;background:#fff;border-color:#fff}.pay-button.outline-light{background:transparent;border-color:#cadbea}.financial-service{display:block;padding:12px;background:#fff;border:1px solid #dce5ed;border-radius:20px;color:#08376b}.financial-service h2{font-size:14px;line-height:1.7;margin-block:6px}.financial-service p{font-size:14px;color:#526c86;line-height:1.65;margin:0}.financial-service svg{width:24px;height:24px;stroke:currentColor;stroke-width:1.7;fill:none;stroke-linecap:round;stroke-linejoin:round}.chaharsu-home .chaharsu-heading{margin-bottom:12px}.chaharsu-home h1{font-size:22px}.chaharsu-home .chaharsu-heading p{margin:0}.pay-copy-status{position:fixed;bottom:100px;right:16px;background:#08376b;color:#fff;padding:12px;border-radius:12px;z-index:100}.pay-manual-copy{max-width:520px;width:calc(100% - 24px);border:1px solid #dce5ed;border-radius:20px;padding:20px;color:#08376b}.pay-manual-copy textarea{width:100%;min-height:200px;font:inherit}.pay-manual-copy::backdrop{background:#0009}.pay-form [data-field=paid_day],.pay-form [data-field=paid_month],.pay-form [data-field=paid_year]{display:inline-block;width:calc(33.33% - 8px);vertical-align:top}.pay-form [data-field=paid_day] .field-error{miLine truncated
@media(min-width:640px){.chaharsu h1{font-size:28px}.chaharsu h2{font-size:20px}.pay-card{padding:22px}.payment-values>div{grid-template-columns:130px 1fr auto;align-items:center}.payment-values dt{grid-column:auto}.chaharsu-home{max-width:1120px}.financial-service{padding:24px}.financial-service h2{font-size:17px}.expert-service{padding:20px}.service-grid{gap:16px}.pay-form{max-width:700px;margin-inline:auto}}
@media(min-width:900px){.service-grid{grid-template-columns:repeat(4,1fr)}.expert-service{grid-column:span 2}}
@media(prefers-reduced-motion:reduce){.chaharsu *{scroll-behavior:auto}}
.chaharsu-dock{grid-template-columns:repeat(3,minmax(0,1fr))}.chaharsu-dock a{font-size:12px;gap:4px}.chaharsu-dock svg{flex-shrink:0}
/* Prototype-aligned customer shell. Loaded only by payment templates. */
.cs-icon{width:22px;height:22px;flex-shrink:0}
.cs-header{position:sticky;top:0;z-index:40;background:#eeeeeeed;border-bottom:1px solid #dce5ed;backdrop-filter:blur(14px)}
.cs-header-inner{max-width:1120px;margin:auto;min-height:76px;padding:0 24px;display:flex;align-items:center;justify-content:space-between;gap:20px}
.cs-brand{display:flex;align-items:center;gap:14px;color:#08376b;flex-shrink:0}
.cs-brand img{width:85px;height:auto;object-fit:contain}.cs-brand-divider{height:32px;width:1px;background:#cdd7e0}
.cs-brand b{display:block;font-size:20px;font-weight:900;line-height:1.4}.cs-brand small{display:block;margin-top:3px;font-size:11px;color:#526c86}
.cs-nav,.cs-header-actions{display:flex;align-items:center;gap:12px}.cs-nav a{min-height:44px;padding:10px 16px;border-radius:12px;color:#526c86;font-size:14px;font-weight:700}.cs-nav a[aria-current]{background:white;color:#08376b}
.cs-profile{display:flex;align-items:center;gap:8px;min-height:44px;padding:8px 12px;background:#fff;border:1px solid #dce5ed;border-radius:14px;color:#08376b;font-size:14px;font-weight:700}
.cs-header-actions form{margin:0}.cs-logout{min-height:44px;padding:8px;color:#526c86;background:transparent;border:0;box-shadow:none;font-size:14px}.cs-logout:hover{background:#fff;color:#08376b;transform:none;box-shadow:none}
.cs-header a:focus-visible,.cs-header button:focus-visible{outline:3px solid #1977ce;outline-offset:3px}
.customer-main:has(.chaharsu){max-width:1120px;padding:30px 24px 16px}.customer-main:has(.chaharsu-home){padding-top:28px}
.cs-footer{max-width:1120px;margin:12px auto 0;padding:0 24px 24px;text-align:center;font-size:12px;line-height:1.9;color:#526c86}
.chaharsu-home .chaharsu-heading{margin-bottom:20px}.chaharsu-home h1{font-size:28px}.chaharsu-home .chaharsu-heading p{margin-top:4px;font-size:14px}
.chaharsu-home .service-grid{align-items:stretch}.expert-service{display:flex;flex-direction:column;min-width:0;padding:24px 20px 20px;border-radius:22px}
.expert-service-head{display:grid;grid-template-columns:34px minmax(0,1fr);column-gap:12px;align-items:center}.expert-service-head h2{margin:0;font-size:20px}.expert-service-head p{grid-column:2;margin:6px 0 0;line-height:1.7}
.service-icon{display:grid;place-items:center;width:48px;height:48px;border-radius:14px;background:#e5f4ff;color:#1977ce}.expert-service-head .service-icon{width:34px;height:34px;background:#1977ce;color:#fff}
.service-actions{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px;margin-top:auto;padding-top:24px}
.service-actions .pay-button{gap:8px;font-size:14px;font-weight:800}.service-actions .pay-button.light{background:#1977ce;color:#fff;border-color:#1977ce}.service-actions .outline-light{background:#ffffff08;border-color:#ffffff40;color:white}
.service-actions .light:hover{background:#1566b2;border-color:#1566b2}.service-actions .outline-light:hover{background:#ffffff15;border-color:#ffffff70}
.financial-service{display:flex;flex-direction:column;min-width:0;padding:24px;border-radius:22px;transition:border-color .18s,box-shadow .18s,transform .18s}
.financial-service h2{margin:20px 0 6px;font-size:17px;font-weight:900}.financial-service p{line-height:1.8}.financial-service .cs-icon{width:23px;height:23px}
.service-link{display:flex;justify-content:space-between;align-items:center;gap:8px;margin-top:auto;padding-top:20px;color:#08376b;font-size:14px;font-weight:700}.service-link .cs-icon{width:18px;height:18px}
.financial-service:hover{border-color:#91bfdd;box-shadow:0 15px 35px -25px #08376b70;transform:translateY(-3px)}
.chaharsu .pay-button{gap:8px;transition:background .15s,border-color .15s}.chaharsu .pay-button:hover{background:#0b4c8c;color:#fff;box-shadow:none;transform:none}.chaharsu .pay-button.secondary:hover{background:#e5f4ff;color:#08376b}
.chaharsu .pay-button:disabled{cursor:not-allowed;opacity:.5}.chaharsu .pay-button:disabled:hover{background:#08376b}
.chaharsu-dock a.active{background:#0b4c8c}.chaharsu-dock a{min-height:52px;color:#cadbea}
/* Staff payment workspace: one reading order across desktop and mobile. */
.pay-workspace{max-width:1200px}.pay-page-head{display:flex;justify-content:space-between;align-items:center;gap:24px;flex-wrap:wrap;margin-bottom:24px}
.pay-page-title{display:flex;align-items:center;gap:14px;min-width:0;flex:1}.pay-page-title>div{min-width:0}.pay-page-title h1{font-size:24px;line-height:1.6;margin:0}.pay-page-title p{margin:4px 0 0;color:#526c86;font-size:14px}
.pay-page-icon{display:grid;place-items:center;width:52px;height:52px;flex-shrink:0;border:1px solid #cde6f7;border-radius:16px;background:#e5f4ff;color:#08376b}.pay-page-icon .cs-icon{width:26px;height:26px}
.pay-head-actions{display:flex;gap:8px;flex-wrap:wrap}.pay-head-actions .pay-button{white-space:nowrap}
.pay-desk-tabs{display:flex;gap:4px;padding:5px;margin:0 0 16px;background:#e3e9ef;border:1px solid #d5dfe8;border-radius:16px;width:fit-content;max-width:100%}
.pay-desk-tabs a{display:flex;align-items:center;justify-content:center;padding:10px 18px;font-size:14px;font-weight:700;border-radius:12px;color:#526c86;text-align:center}.pay-desk-tabs a[aria-current]{background:#fff;color:#08376b;box-shadow:0 2px 6px #08376b08}.pay-desk-tabs a:hover{color:#08376b;background:#ffffff80}
.pay-filter-panel{margin:0 0 20px;padding:20px}.pay-filter-grid{display:grid;grid-template-columns:minmax(220px,2fr) repeat(2,minmax(140px,1fr)) auto;align-items:end;gap:12px}
.pay-bank-filters{grid-template-columns:minmax(220px,2fr) repeat(3,minmax(115px,1fr)) auto}
.pay-filter-grid label,.pay-extra-filters label,.pay-bulk-bar label{display:flex;flex-direction:column;gap:6px;font-size:14px;font-weight:700;min-width:0}
.pay-workspace input:not([type=checkbox]):not([type=hidden]),.pay-workspace select{width:100%;min-width:0;min-height:44px;border:1px solid #c6d3df;border-radius:12px;padding:9px 12px;background:#fff;color:#08376b;font:inherit;font-size:14px;box-shadow:none}
.pay-workspace input::placeholder{color:#526c86;opacity:1}.pay-workspace input:focus,.pay-workspace select:focus{border-color:#1977ce;box-shadow:0 0 0 3px #1977ce12}
.pay-search-input{display:flex;align-items:center;gap:8px;background:#f6f8fa;border:1px solid #c6d3df;border-radius:12px;padding-inline:12px;min-height:44px}.pay-search-input .cs-icon{color:#526c86;width:20px;height:20px}.pay-workspace .pay-search-input input[type=search]{border:0;background:transparent;padding-inline:0}.pay-workspace .pay-search-input input[type=search]:focus{box-shadow:none}.pay-search-input:focus-within{outline:3px solid #1977ce;outline-offset:2px}
.pay-filter-bottom{display:flex;justify-content:space-between;align-items:flex-start;gap:16px;margin-top:12px}.pay-more-filters{flex:1;min-width:0}.pay-more-filters summary{display:flex;align-items:center;gap:6px;min-height:44px;width:fit-content;cursor:pointer;font-weight:700;color:#08376b;list-style:none}.pay-more-filters summary::-webkit-details-marker{display:none}.pay-more-filters summary::after{content:'⌄';margin-inline-start:4px;transition:transform .15s}.pay-more-filters[open] summary::after{transform:rotate(180deg)}.pay-more-filters summary:focus-visible{outline:3px solid #1977ce;outline-offset:3px}
.pay-extra-filters{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:12px;padding-top:8px}.pay-extra-filters label small{display:contents;font-size:12px;font-weight:400}.pay-extra-filters input[type=date]{direction:ltr;text-align:right}.pay-reset{display:flex;align-items:center;min-height:44px;white-space:nowrap;color:#526c86;text-decoration:underline;text-underline-offset:4px}
.pay-records,.pay-bank-panel{border:1px solid #dce5ed;border-radius:20px;background:#fff;overflow:hidden}.pay-list-head{display:flex;align-items:center;justify-content:space-between;gap:16px;min-height:64px;padding:16px 20px;border-bottom:1px solid #e7edf2}.pay-list-head h2{font-size:16px;margin:0;font-weight:800}.pay-list-head>span{font-size:12px;color:#526c86;background:#f0f4f7;border-radius:20px;padding:4px 10px;white-space:nowrap}
.pay-record{display:grid;grid-template-columns:44px minmax(0,1fr) minmax(155px,auto) minmax(165px,auto);align-items:center;gap:16px;padding:20px;border-bottom:1px solid #e7edf2}.pay-record:last-child{border-bottom:0}.pay-record:hover{background:#fbfdff}
.pay-record-icon{display:grid;place-items:center;width:44px;height:44px;flex-shrink:0;border-radius:14px;background:#f0f5f9;color:#1977ce}.pay-record-main{display:flex;flex-direction:column;gap:4px;min-width:0}.pay-record-main h3{font-size:16px;margin:0;font-weight:800}.pay-record-main h3 a:hover{text-decoration:underline;text-underline-offset:4px}.pay-record-meta{font-size:12px;color:#526c86}.pay-record-customer{display:flex;align-items:center;gap:6px;font-size:14px;color:#526c86}.pay-record-customer .cs-icon{width:16px;height:16px}
.pay-record-amount{display:flex;flex-direction:column;gap:6px}.pay-record-amount strong{font-size:18px;line-height:1.7;font-weight:800;white-space:nowrap}.pay-record-amount small{font-size:12px;font-weight:400}.pay-record-amount time{font-size:12px;color:#526c86}.pay-record-side{display:flex;flex-direction:column;align-items:flex-end;gap:8px}
.pay-status{display:inline-flex;align-items:center;gap:6px;min-height:28px;max-width:100%;padding:4px 10px;border-radius:20px;font-size:12px;font-weight:700;background:#f0f3f6;color:#526c86;white-space:nowrap}.pay-status::before{content:'';width:5px;height:5px;flex-shrink:0;border-radius:50%;background:currentColor}.pay-status.pending{background:#fff3da;color:#805300}.pay-status.partial,.pay-status.info{background:#e5f4ff;color:#125587}.pay-status.approved{background:#eaf5ef;color:#216345}.pay-status.rejected{background:#fff0ee;color:#9f1f1f}
.pay-open{display:flex;align-items:center;justify-content:center;gap:8px;min-height:44px;color:#08376b;font-size:14px;font-weight:700}.pay-open .cs-icon{width:18px;height:18px}.pay-open:hover{color:#1977ce;text-decoration:underline;text-underline-offset:4px}
.pay-empty{text-align:center;padding:40px 20px;color:#526c86}.pay-empty-icon{display:grid;place-items:center;width:56px;height:56px;border-radius:18px;background:#f0f5f9;color:#526c86;margin:0 auto 12px}.pay-empty-icon .cs-icon{width:26px;height:26px}.pay-empty h3{font-size:18px;color:#08376b;margin:0}.pay-empty p{margin:6px 0 0}
.pay-bank-table-head,.pay-bank-row{display:grid;grid-template-columns:44px minmax(190px,1fr) repeat(3,100px) 90px;align-items:center;gap:12px}.pay-bank-table-head{padding:12px 20px;background:#f6f8fa;color:#526c86;font-size:12px;border-bottom:1px solid #e7edf2}.pay-select-all{display:flex;align-items:center;gap:8px}.pay-select-all span{display:none}.pay-bank-row{padding:20px;border-bottom:1px solid #e7edf2}.pay-bank-select{display:flex;align-items:center;min-height:44px;cursor:pointer}.pay-bank-panel input[type=checkbox]{width:20px;height:20px;accent-color:#08376b;cursor:pointer;margin:0;flex-shrink:0}
.pay-bank-identity{display:flex;gap:12px;align-items:center;min-width:0}.pay-bank-identity h3{font-size:16px;margin:0}.pay-bank-identity p{font-size:14px;color:#526c86;margin:3px 0}.pay-identifier-badge{display:inline-block;font-size:12px;color:#805300;background:#fff3da;border:1px solid #f3ddae;border-radius:8px;padding:2px 7px;margin-top:4px}
.pay-bank-edit{display:flex;align-items:center;justify-content:center;gap:6px;min-height:44px;border:1px solid #dce5ed;border-radius:12px;font-size:14px;font-weight:700;color:#08376b}.pay-bank-edit:hover{background:#e5f4ff;border-color:#91bfdd}.pay-bank-edit .cs-icon{width:17px;height:17px}.pay-mobile-label{display:none}
.pay-bulk-bar{display:grid;grid-template-columns:minmax(180px,1fr) minmax(155px,auto) minmax(100px,auto) auto;align-items:end;gap:12px;padding:20px;background:#f6f8fa}.pay-bulk-label{display:flex;flex-direction:column;gap:6px;align-self:center}.pay-bulk-label strong{font-size:14px}.pay-bulk-label span{font-size:12px;color:#526c86}.pay-bank-hint{padding:0 20px 14px;margin:0!important;background:#f6f8fa;color:#526c86;font-size:12px}
.pay-pagination{justify-content:center;flex-wrap:wrap;margin-top:20px}.pay-pagination a{display:flex;align-items:center;justify-content:center;gap:8px;min-width:90px;min-height:44px;background:#fff;border:1px solid #dce5ed;border-radius:12px;font-weight:700}.pay-pagination span{font-size:14px;color:#526c86}
.pay-staff-dock{grid-template-columns:repeat(2,minmax(0,1fr));gap:4px}.pay-staff-dock.has-banks{grid-template-columns:repeat(3,minmax(0,1fr))}.pay-staff-dock a{gap:5px;min-height:54px;font-size:12px;color:#cadbea}.pay-staff-dock a.active{background:#0b4c8c}.pay-staff-dock .cs-icon{width:20px;height:20px}
@media(min-width:900px){.chaharsu-home .service-grid>*{min-height:232px}}
@media(max-width:1199px){.pay-bank-filters{grid-template-columns:repeat(3,minmax(0,1fr))}.pay-bank-filters .pay-search-field{grid-column:span 2}.pay-bank-filters button{width:100%}.pay-page-head{gap:16px}.pay-bank-table-head,.pay-bank-row{grid-template-columns:32px minmax(160px,1fr) repeat(3,85px) 80px;gap:8px}.pay-bulk-bar{grid-template-columns:repeat(3,minmax(0,1fr))}.pay-bulk-label{grid-column:1/-1}}
@media(max-width:899px){.pay-filter-grid{grid-template-columns:repeat(2,minmax(0,1fr))}.pay-search-field{grid-column:1/-1}.pay-bank-filters .pay-search-field{grid-column:1/-1}.pay-record{grid-template-columns:44px minmax(0,1fr) auto}.pay-record-side{grid-column:2/-1;flex-direction:row;justify-content:space-between;align-items:center}.pay-head-actions{width:100%}.pay-page-title h1{font-size:22px}.cs-nav{gap:4px}.cs-nav a{padding-inline:10px}.cs-header-inner{gap:12px}.cs-profile span{display:none}}
@media(max-width:767px){.pay-bank-table-head{display:flex;padding:10px 16px}.pay-bank-table-head>span{display:none}.pay-select-all span{display:inline}.pay-bank-row{grid-template-columns:24px repeat(3,minmax(0,1fr));gap:12px;padding:16px}.pay-bank-select{grid-column:1;grid-row:1;align-self:start}.pay-bank-identity{grid-column:2/-1}.pay-bank-flag{display:flex;flex-direction:column;gap:6px;align-items:flex-start}.pay-bank-flag:nth-of-type(2){grid-column:2}.pay-mobile-label{display:block;font-size:12px;color:#526c86}.pay-bank-edit{grid-column:2/-1;justify-self:end;padding-inline:14px}.pay-bank-identity .pay-record-icon{display:none}.pay-bulk-bar{grid-template-columns:repeat(2,minmax(0,1fr));padding:16px}.pay-bulk-bar button{grid-column:1/-1}.pay-bank-hint{padding-inline:16px}}
@media(max-width:639px){
.cs-header-inner{min-height:64px;padding-inline:16px;gap:8px}.cs-brand{gap:10px}.cs-brand img{width:64px}.cs-brand-divider{height:28px}.cs-brand b{font-size:18px}.cs-brand small{font-size:11px}.cs-nav{display:none}.cs-profile{padding:0;width:40px;min-height:40px;border-radius:12px}.cs-profile .cs-icon{margin:auto;width:20px;height:20px}.cs-header-actions{gap:4px}.cs-logout{font-size:12px;padding-inline:6px}
.customer-main:has(.chaharsu){padding:18px 12px 12px}.customer-main:has(.chaharsu-home){padding:12px 16px 8px}.chaharsu-home .chaharsu-heading{margin-bottom:12px}.chaharsu-home h1{font-size:22px}.chaharsu-home .chaharsu-heading p{display:none}
.expert-service{padding:12px 14px;border-radius:20px}.expert-service-head{grid-template-columns:minmax(0,1fr) 30px;gap:0 8px}.expert-service-head h2{grid-column:1;grid-row:1;font-size:18px}.expert-service-head .service-icon{grid-column:2;grid-row:1;width:30px;height:30px;border-radius:10px}.expert-service-head .cs-icon{width:18px;height:18px}.expert-service-head p{grid-column:1/-1;margin-top:6px;line-height:1.65}.service-actions{padding-top:10px;gap:8px}.service-actions .pay-button{padding-inline:6px;gap:5px}.service-actions .cs-icon{width:18px;height:18px}
.financial-service{padding:11px 12px;border-radius:20px}.financial-service .service-icon{width:30px;height:30px;border-radius:10px}.financial-service .cs-icon{width:20px;height:20px}.financial-service h2{font-size:14px;margin:7px 0 4px}.financial-service p{font-size:14px;line-height:1.65}.service-link{display:none}.cs-footer{padding:0 16px calc(96px + env(safe-area-inset-bottom));margin-top:16px}
.pay-page-head{margin-bottom:16px;gap:12px}.pay-page-title{gap:10px;align-items:flex-start}.pay-page-icon{width:40px;height:40px;border-radius:12px}.pay-page-icon .cs-icon{width:22px;height:22px}.pay-page-title h1{font-size:20px}.pay-page-title p{line-height:1.7;margin-top:4px}.pay-head-actions .pay-button{flex:1;padding-inline:10px}.pay-page-head>.pay-button{width:100%}
.pay-desk-tabs{width:100%;gap:2px}.pay-desk-tabs a{flex:1;min-width:0;padding:8px 6px;line-height:1.6;font-size:14px}.pay-filter-panel{padding:14px;margin-bottom:16px}.pay-filter-grid{gap:10px}.pay-filter-grid button{width:100%;align-self:end}.pay-extra-filters{grid-template-columns:1fr}.pay-filter-bottom{gap:8px;flex-wrap:wrap}.pay-reset{font-size:12px}.pay-list-head{padding:14px 16px}.pay-list-head h2{font-size:14px}
.pay-record{grid-template-columns:minmax(0,1fr);gap:10px;padding:16px}.pay-record>.pay-record-icon{display:none}.pay-record-main h3{font-size:14px}.pay-record-amount{flex-direction:row;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:6px}.pay-record-amount strong{font-size:16px}.pay-record-side{grid-column:auto;gap:8px;flex-wrap:wrap;border-top:1px solid #e7edf2;padding-top:8px}.pay-record-meta{font-size:12px}.pay-empty{padding:30px 16px}.pay-pagination{gap:8px}
}
@media(max-width:359px){.cs-header-inner{padding-inline:12px}.cs-brand img{width:54px}.cs-brand{gap:8px}.cs-brand small{font-size:10px}.customer-main:has(.chaharsu-home){padding-inline:12px}.service-actions .cs-icon{display:none}.pay-bank-row{gap:10px}.pay-bank-flag .pay-status{font-size:12px;padding-inline:7px}}
@media(max-width:639px) and (max-height:650px){.customer-main:has(.chaharsu-home)+.cs-footer{margin-top:96px}}
@media(prefers-reduced-motion:reduce){.financial-service,.chaharsu .pay-button{transition:none}.financial-service:hover{transform:none}}
/* Every staff payment form/detail uses the same local component family. */
.pay-form-workspace{max-width:1000px}.pay-detail-workspace{max-width:1200px}
.pay-back{display:inline-flex;align-items:center;gap:6px;min-height:44px;margin-bottom:8px;font-size:14px;font-weight:700;color:#526c86}.pay-back .cs-icon{width:18px;height:18px}.pay-back:hover{color:#08376b}
.pay-staff-form{max-width:none!important;margin:0;padding:24px}.pay-form-section{margin:0;padding:0 0 24px;border:0;min-width:0}.pay-form-section+.pay-form-section{border-top:1px solid #e7edf2;padding-top:24px}.pay-form-section legend{float:right;width:100%;font-size:18px;font-weight:800;color:#08376b;margin-bottom:12px}.pay-form-section::after{content:'';display:block;clear:both}
.pay-section-help,.pay-field-hint{font-size:14px;font-weight:400;color:#526c86;line-height:1.8}.pay-section-help{clear:both;margin:0 0 12px!important}.pay-field-hint{margin:6px 0 0!important;font-size:12px}.pay-form-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:20px 24px;clear:both}.pay-form-grid .pay-field{margin:0;min-width:0}.pay-field-wide{grid-column:1/-1}.pay-staff-form .pay-field label{display:flex;align-items:center;flex-wrap:wrap;gap:8px;font-size:14px;margin-bottom:8px}.pay-required{font-size:12px;font-weight:400;color:#526c86}.pay-optional{font-size:12px;font-weight:400;color:#526c86}
.pay-staff-form input:not([type=checkbox]):not([type=radio]):not([type=hidden]),.pay-staff-form select,.pay-staff-form textarea{min-height:48px;padding:10px 12px;border:1px solid #b8c9d8;border-radius:12px;font-size:16px;box-shadow:none}.pay-staff-form textarea{min-height:120px;resize:vertical}.pay-staff-form input[id=id_iban],.pay-staff-form input[id=id_card_number],.pay-staff-form input[id=id_account_number],.pay-staff-form input[id=id_amount],.pay-staff-form input[id=id_deposit_id]{direction:ltr;text-align:right}.pay-staff-form .has-error input,.pay-staff-form .has-error select,.pay-staff-form .has-error textarea{border-color:#9f1f1f}.chaharsu .errorlist{list-style:none;padding:0;margin:6px 0;color:#9f1f1f;font-size:14px;line-height:1.8}.pay-staff-form .pay-field .errorlist{margin:0}.pay-inline-note{clear:both;background:#f6fbff;border:1px solid #cde6f7;border-radius:12px;padding:12px 14px;color:#526c86;font-size:14px;line-height:1.8;margin:16px 0 0!important}
.pay-check-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px;clear:both}.pay-check-card{display:flex;align-items:flex-start;gap:12px;padding:16px;border:1px solid #dce5ed;border-radius:14px;background:#fafcfe;cursor:pointer;min-width:0}.pay-check-card:has(input:checked){border-color:#91bfdd;background:#f0f8fd}.pay-check-card input[type=checkbox]{width:20px;height:20px;margin:3px 0 0;flex-shrink:0;accent-color:#08376b}.pay-check-card strong{display:block;font-size:14px;font-weight:800}.pay-check-card small{display:block;font-size:12px;line-height:1.8;font-weight:400;color:#526c86;margin-top:5px}.pay-sort-field{max-width:300px;margin-top:20px}.pay-sort-field .pay-field{margin:0}
.pay-form-footer{display:flex;align-items:center;gap:12px;flex-wrap:wrap;border-top:1px solid #e7edf2;padding-top:20px;margin-top:4px}.pay-form-footer .pay-button{min-width:120px}.pay-delete-panel{border:1px solid #ecd4d2;background:#fff;border-radius:16px;margin-top:20px;color:#9f1f1f}.pay-delete-panel summary{padding:14px 20px;cursor:pointer;min-height:48px;font-size:14px;font-weight:700}.pay-delete-panel form{padding:0 20px 20px;color:#526c86;font-size:14px}.chaharsu .pay-danger,.chaharsu .pay-danger.secondary{background:#fff4f3;border-color:#d9a4a0;color:#9f1f1f}.chaharsu .pay-danger:hover{background:#9f1f1f;border-color:#9f1f1f;color:#fff}
.pay-receipt-grid{display:grid;grid-template-columns:repeat(6,minmax(0,1fr));gap:18px 24px;margin-top:20px}.pay-staff-form .pay-receipt-grid>.pay-field{grid-column:span 3;margin:0;min-width:0;display:block;width:auto}.pay-staff-form .pay-receipt-grid>[data-field=receipt_mode],.pay-staff-form .pay-receipt-grid>[data-field=notice_id],.pay-staff-form .pay-receipt-grid>[data-field=description],.pay-staff-form .pay-receipt-grid>[data-field=receipt_image]{grid-column:1/-1}.pay-staff-form .pay-receipt-grid>[data-field=paid_day],.pay-staff-form .pay-receipt-grid>[data-field=paid_month],.pay-staff-form .pay-receipt-grid>[data-field=paid_year]{grid-column:span 2}.pay-date-heading{grid-column:1/-1;display:flex;gap:8px;flex-wrap:wrap;margin-top:8px!important;border-top:1px solid #e7edf2;padding-top:20px}.pay-staff-form #id_receipt_mode{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px}.pay-staff-form #id_receipt_mode label{min-height:52px;padding:12px;margin:0;border:1px solid #dce5ed;border-radius:12px;cursor:pointer;background:#fafcfe;flex-wrap:nowrap;align-items:flex-start}.pay-staff-form #id_receipt_mode label:has(input:checked){background:#e5f4ff;border-color:#91bfdd}.pay-staff-form #id_receipt_mode input{margin:2px 0 0;flex-shrink:0;accent-color:#08376b}.pay-staff-form input[type=file]{padding:18px!important;background:#f6fbff;border:1px dashed #91bfdd!important}.pay-staff-form #amount-words{font-size:14px;color:#526c86}.pay-staff-form .pay-today{font-size:12px;min-height:36px;padding:4px 10px;margin-top:8px}.pay-staff-form #date-preview{font-size:12px;color:#526c86}
.pay-detail-grid{display:grid;grid-template-columns:minmax(0,1.6fr) minmax(300px,1fr);gap:24px;align-items:start}.pay-detail-grid>div,.pay-detail-aside{min-width:0}.pay-detail-grid .pay-card{margin:0 0 20px}.pay-detail-grid .pay-card h2{font-size:18px;margin-bottom:12px}.pay-detail-grid .pay-form{max-width:none}.pay-notice-main .payment-notice summary{padding-bottom:16px;border-bottom:1px solid #e7edf2;margin-bottom:16px}.pay-notice-main .payment-values>div{grid-template-columns:125px minmax(0,1fr) auto}.pay-notice-main .payment-values dd{font-size:16px}.pay-notice-main .pay-copy{padding-inline:12px;min-height:40px;font-size:14px}.pay-linked-record{display:flex;align-items:center;gap:8px;flex-wrap:wrap;border-top:1px solid #e7edf2;padding:12px 0;min-height:48px;font-size:14px;font-weight:700}.pay-linked-record>.cs-icon{margin-inline-start:auto;width:18px;height:18px}.pay-notification-row{display:flex;flex-direction:column;gap:4px;padding:12px 0;border-top:1px solid #e7edf2}.pay-notification-row span{font-size:12px;color:#526c86}
.pay-warning{background:#fff3da;border:1px solid #f3ddae;color:#805300;padding:14px 16px;border-radius:14px;font-size:14px;line-height:1.8;margin:0 0 16px!important}.pay-receipt-total{background:#f6fbff;border:1px solid #cde6f7;border-radius:14px;padding:16px;margin-bottom:16px}.pay-receipt-total>span{font-size:12px;color:#526c86}.pay-receipt-total h2{font-size:26px!important;margin:4px 0!important;line-height:1.6}.pay-receipt-total h2 small{font-size:14px;font-weight:400}.pay-receipt-total p{font-size:14px;color:#526c86;margin:0}.pay-facts>div{display:grid;grid-template-columns:150px minmax(0,1fr);gap:12px;padding:10px 0;border-bottom:1px solid #e7edf2}.pay-facts dt{color:#526c86;font-size:14px}.pay-facts dd{font-size:14px;font-weight:700;min-width:0;overflow-wrap:anywhere}.pay-facts dd[dir=ltr]{text-align:right}.pay-section-title{font-size:14px!important;margin:20px 0 8px;font-weight:800}.pay-card-title{display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap;margin-bottom:16px}.pay-card-title h2{margin:0!important}.pay-image-card .receipt-preview{margin:0 auto 12px;max-height:650px;width:auto;border-radius:12px;border:1px solid #e7edf2;background:#f6f8fa}.pay-decision-form{border-top:3px solid #1977ce}.pay-decision-form label{font-size:14px}.pay-decision-form textarea{margin-top:8px;min-height:110px}.pay-decision-actions{display:flex;flex-direction:column;gap:10px;margin-top:16px}.pay-decision-actions .pay-button{width:100%}.pay-timeline-item{position:relative;padding:0 16px 20px 0;border-inline-start:2px solid #dce5ed;display:flex;flex-direction:column;gap:4px}.pay-timeline-item:before{content:'';position:absolute;inset-inline-start:-5px;top:5px;background:#1977ce;width:8px;height:8px;border-radius:50%}.pay-timeline-item strong{font-size:14px}.pay-timeline-item span,.pay-timeline-item time{font-size:12px;color:#526c86}.pay-timeline-item p{font-size:14px;margin:4px 0}.pay-version-row{display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap;padding:10px 0;border-bottom:1px solid #e7edf2}.pay-version-row a{font-size:14px;font-weight:700}.pay-version-row time{font-size:12px;color:#526c86}.pay-reviewer{display:flex;align-items:center;gap:8px;flex-wrap:wrap;font-size:14px}.pay-reviewer>.cs-icon{width:18px;height:18px;color:#526c86}
@media(max-width:899px){.pay-detail-grid{grid-template-columns:minmax(0,1fr);gap:0}.pay-detail-grid .pay-card{margin-bottom:16px}}
@media(max-width:639px){.pay-staff-form{padding:16px}.pay-form-grid{grid-template-columns:minmax(0,1fr);gap:18px}.pay-form-section{padding-bottom:20px}.pay-form-section+.pay-form-section{padding-top:20px}.pay-form-section legend{font-size:16px}.pay-check-grid{grid-template-columns:minmax(0,1fr);gap:10px}.pay-check-card{padding:14px}.pay-sort-field{max-width:none}.pay-form-footer{gap:8px}.pay-form-footer .pay-button{flex:1;min-width:0}.pay-receipt-grid{gap:16px 8px}.pay-staff-form .pay-receipt-grid>.pay-field{grid-column:1/-1}.pay-staff-form .pay-receipt-grid>[data-field=paid_day],.pay-staff-form .pay-receipt-grid>[data-field=paid_month],.pay-staff-form .pay-receipt-grid>[data-field=paid_year]{grid-column:span 2}.pay-staff-form .pay-receipt-grid select{padding-inline:6px}.pay-staff-form #id_receipt_mode{grid-template-columns:minmax(0,1fr);gap:8px}.pay-staff-form [data-field=paid_day] .field-error{min-width:0}.pay-facts>div{grid-template-columns:1fr;gap:4px}.pay-receipt-total h2{font-size:24px!important}.pay-notice-main .payment-values>div{grid-template-columns:minmax(0,1fr) auto}.pay-notice-main .payment-values dt{grid-column:1/-1}.pay-detail-grid .pay-card h2{font-size:16px}.pay-delete-panel summary{padding-inline:16px}.pay-delete-panel form{padding-inline:16px}.pay-card-title .pay-button{min-height:40px;padding-inline:12px}}
/* Native radios must not inherit the workspace text-input width and height. */
.pay-staff-form #id_receipt_mode input[type=radio]{width:20px;height:20px;min-height:20px;padding:0;border:0;border-radius:50%;background:transparent;box-shadow:none;flex:0 0 20px}
.pay-staff-form textarea{height:128px;min-height:128px}.pay-date-status{grid-column:1/-1;margin:-6px 0 0!important}
.pay-customer-picker{min-width:0}.pay-customer-picker>label{display:flex;align-items:center;gap:8px;font-weight:700;font-size:14px;margin-bottom:8px}.pay-workspace .pay-customer-picker .pay-search-input input[type=search]{border:0;background:transparent;padding-inline:0}.pay-customer-results{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px;margin-top:16px;max-height:520px;overflow-y:auto;padding:4px}.pay-customer-result{padding:16px;border:1px solid #dce5ed;border-radius:14px;background:#fafcfe;min-width:0;display:flex;flex-direction:column;gap:10px}.pay-customer-identity{display:flex;flex-direction:column;gap:4px;min-width:0}.pay-customer-identity strong{font-size:16px;font-weight:800}.pay-customer-identity bdi{font-size:16px;font-weight:700;text-align:right}.pay-customer-identity span{font-size:14px}.pay-customer-identity small{font-size:12px;color:#526c86}.pay-customer-result>.pay-button{margin-top:auto}.pay-customer-history{border-top:1px solid #dce5ed;padding-top:6px}.pay-customer-history summary{font-size:14px;cursor:pointer;min-height:40px;display:list-item;list-style-position:inside}.pay-customer-history div{display:flex;flex-direction:column;gap:3px;padding:8px 0;border-top:1px solid #e7edf2}.pay-customer-history a{font-size:14px;color:#08376b;text-decoration:underline;text-underline-offset:3px}.pay-customer-history small,.pay-customer-history p{font-size:12px;color:#526c86}.pay-selected-customer{margin-top:16px;padding:16px 20px;border:1px solid #91bfdd;border-radius:16px;background:#f0f8fd;display:grid;grid-template-columns:minmax(0,1fr) auto;gap:8px 16px}.pay-selected-label{font-size:12px;color:#526c86;grid-column:1/-1}.pay-selected-customer .pay-customer-identity{grid-column:1;grid-row:2}.pay-selected-customer>.pay-button{grid-column:2;grid-row:2;align-self:start}.pay-selected-customer .pay-customer-history{grid-column:1/-1}.pay-customer-history summary:focus-visible{outline:3px solid #1977ce;outline-offset:2px}
@media(max-width:639px){.pay-customer-results{grid-template-columns:1fr;max-height:440px}.pay-selected-customer{padding:14px;gap:12px}.pay-selected-customer>.pay-button{grid-column:1/-1;grid-row:auto}.pay-customer-result{padding:14px}}
/* Customer financial pages follow the standalone prototypes and STYLE_GUIDE.
All rules are scoped: staff forms and the ticket composer keep their styles. */
.customer-finance .pay-breadcrumb{display:flex;gap:10px;align-items:center;flex-wrap:wrap;font-size:12px;color:#526c86;margin-bottom:16px}
.customer-finance-title{display:flex;align-items:center;gap:16px;margin-bottom:24px}.customer-finance-title h1{margin:0}.customer-finance-title p{color:#526c86;margin:6px 0 0}.customer-finance .pay-page-icon{width:56px;height:56px;display:grid;place-items:center;background:#e5f4ff;border:1px solid #cde6f7;border-radius:18px;flex-shrink:0}.customer-finance .pay-page-icon svg{width:28px;height:28px}
.customer-finance .finance-guidance{background:#f0f8fd;border:1px solid #cde6f7;border-radius:12px;padding:12px 14px;font-size:14px;line-height:1.8;color:#526c86;margin:12px 0 20px}.customer-finance .pay-text-link{display:inline-flex;align-items:center;gap:6px;min-height:44px;font-size:14px;font-weight:700;text-decoration:underline;text-underline-offset:4px}.customer-finance .pay-text-link svg{width:18px;height:18px}.customer-service-footer{display:flex;justify-content:space-between;gap:12px;flex-wrap:wrap;margin:20px 0}
.customer-receipt-form.pay-form{max-width:none;margin:0;padding:0;border:0;background:transparent;box-shadow:none}.customer-receipt-form .pay-card{margin:0 0 20px;padding:22px;border-radius:23px}.customer-receipt-form h2{margin:0 0 16px}.customer-receipt-form .pay-field{min-width:0}.customer-receipt-form .pay-field label{font-size:14px}.customer-receipt-form .pay-optional{margin-inline-start:8px}.customer-receipt-form input:not([type=hidden]):not([type=radio]):not([type=file]),.customer-receipt-form select,.customer-receipt-form textarea{padding:10px 12px;font-size:16px;min-height:48px;box-shadow:none;border-color:#b8c9d8}.customer-receipt-form textarea{height:112px;min-height:112px;resize:vertical}.customer-field-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:20px 24px;margin-top:20px}.customer-field-grid .pay-field{margin:0}.customer-receipt-form .pay-field-hint{font-size:12px;line-height:1.8}.customer-receipt-form #amount-words{font-size:14px;color:#526c86;line-height:1.8}
.customer-receipt-modes{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px}.customer-mode{border:1px solid #dce5ed;border-radius:14px;padding:12px 14px;background:#fafcfe}.customer-mode.recommended-mode{border-color:#91bfdd}.customer-mode:has(input:checked){background:#e5f4ff;border-color:#1977ce}.customer-receipt-form .customer-mode label{display:flex;align-items:center;gap:10px;cursor:pointer;min-height:36px;margin:0;padding:0}.customer-mode small{display:block;margin-inline-start:30px;font-size:12px;color:#526c86}.customer-receipt-form .customer-mode input[type=radio]{width:20px;height:20px;min-height:20px;margin:0;padding:0;flex:0 0 20px;accent-color:#08376b;box-shadow:none}.customer-receipt-form .receipt-mode-field{padding:0;border:0}.customer-receipt-form #selected-payment h3{font-size:16px;margin:0}.customer-receipt-form #selected-payment p{font-size:14px;color:#526c86}
.customer-date{padding:20px 0 0;margin-top:24px;border:0;border-top:1px solid #e7edf2;min-width:0}.customer-date legend{font-size:14px;font-weight:700;padding-inline:0 10px}.customer-date-selects{display:grid;grid-template-columns:.7fr 1.3fr 1fr;gap:12px}.customer-receipt-form .customer-date-selects>.pay-field{display:block;width:auto;margin:0;min-width:0}.customer-receipt-form [data-field=paid_day] .field-error{min-width:0}.customer-date-tools{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-top:8px}.customer-date-tools .pay-today{margin:0;font-size:12px;min-height:44px;padding:4px 12px}.customer-receipt-form #date-preview{font-size:12px;color:#526c86;min-height:22px}
.customer-upload-zone{position:relative;border:1px dashed #91bfdd;background:#f6fbff;border-radius:16px;display:flex;flex-direction:column;align-items:center;padding:24px 16px;text-align:center;gap:12px}.customer-upload-zone>.cs-icon{width:32px;height:32px;color:#1977ce}.customer-receipt-form .customer-file-button{display:inline-flex;align-items:center;gap:8px;min-height:44px;padding:8px 16px;border-radius:12px;background:#08376b;color:#fff;cursor:pointer;margin:0}.customer-file-button span{font-size:12px;font-weight:400}.customer-upload-zone p{font-size:12px;color:#526c86;margin:0}.customer-receipt-form .customer-upload-zone input[type=file]{position:absolute;width:1px;height:1px;min-height:0;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.customer-upload-zone:focus-within .customer-file-button{outline:3px solid #1977ce;outline-offset:3px}.customer-file-selection{display:flex;align-items:center;justify-content:space-between;gap:12px;font-size:12px;margin-top:12px}.customer-file-selection p{overflow-wrap:anywhere}.customer-file-selection button{min-height:44px;flex-shrink:0;background:#fff;border:1px solid #dce5ed;border-radius:10px;font:inherit;color:#9f1f1f;padding:8px 12px}.customer-receipt-form #receipt-file-preview{display:block;width:100%;max-height:240px;object-fit:contain;border:1px solid #dce5ed;border-radius:12px;background:#fafcfe;margin-top:12px}.customer-receipt-form [hidden]{display:none!important}.customer-receipt-actions{display:flex;align-items:center;gap:16px;flex-wrap:wrap;margin-top:20px}.customer-receipt-actions .pay-button{min-width:180px}
.customer-list-heading{display:flex;align-items:center;justify-content:space-between;gap:12px;margin:24px 0 12px}.customer-list-heading h2{margin:0}.customer-list-heading>span{font-size:12px;color:#526c86;background:#fff;border-radius:20px;padding:4px 12px}.customer-search-box{display:flex;align-items:center;gap:10px;background:#fff;border:1px solid #b8c9d8;border-radius:12px;padding-inline:12px;flex:1;min-width:0}.customer-notice-search{margin-bottom:20px;align-items:center}.customer-finance .customer-search-box input{border:0;background:transparent;min-width:0;padding-inline:0;box-shadow:none}.customer-search-box:focus-within{outline:3px solid #1977ce;outline-offset:2px}.customer-empty{text-align:center;padding:32px 20px}.customer-empty>.cs-icon{width:36px;height:36px;color:#526c86}.customer-empty p{color:#526c86}
.customer-accounts .payment-notice{padding:0;overflow:hidden;border-radius:23px;margin:16px 0}.customer-accounts .payment-notice summary{position:relative;display:grid;grid-template-columns:minmax(0,1fr) auto 22px;gap:8px 16px;padding:20px 22px;list-style:none}.payment-notice summary::-webkit-details-marker{display:none}.customer-accounts .payment-notice summary strong{min-width:0;grid-column:1;grid-row:1;font-size:16px}.customer-accounts .payment-notice summary b{grid-column:2;grid-row:1;font-size:20px;white-space:nowrap}.customer-accounts .payment-notice summary b span{font-size:12px;font-weight:400}.customer-accounts .payment-notice summary small{grid-column:1;grid-row:2;width:auto}.customer-accounts .notice-state{grid-column:2;grid-row:2;font-size:12px;color:#1977ce;justify-self:end}.customer-accounts .payment-notice summary>.cs-icon{grid-column:3;grid-row:1/3;width:20px;align-self:center}.customer-accounts .payment-notice[open] summary>.cs-icon{transform:rotate(180deg)}.customer-accounts .payment-notice[open] summary{border-bottom:1px solid #e7edf2}.customer-accounts .pay-details{padding:0 22px 6px}.customer-accounts .notice-bank{font-size:14px;color:#526c86;margin:16px 0}.customer-accounts .payment-values{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px;margin:16px 0}.customer-accounts .payment-values>div{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:4px 12px;border:1px solid #dce5ed;border-radius:12px;padding:12px 14px;background:#fafcfe;align-items:center}.customer-accounts .payment-values dt{grid-column:1;grid-row:1;font-size:12px;color:#526c86;font-weight:400}.customer-accounts .payment-values dd{grid-column:1/-1;grid-row:2;font-size:16px;margin:0;line-height:1.8;letter-spacing:.3px}.customer-accounts .pay-copy{grid-column:2;grid-row:1;font-size:12px;padding:4px 8px;min-height:44px;border-color:#dce5ed;gap:6px}.customer-accounts .pay-copy svg{width:16px;height:16px}.customer-accounts .pay-details>p:not(.notice-bank){font-size:12px;color:#526c86}.customer-accounts .pay-supplement{font-size:14px;line-height:1.9}.customer-accounts .pay-supplement h3{margin:0 0 8px}.customer-accounts .pay-actions{gap:12px}
@media(max-width:639px){.customer-finance-title{gap:12px;margin-bottom:20px;align-items:flex-start}.customer-finance-title h1{font-size:24px}.customer-finance .pay-page-icon{width:48px;height:48px;border-radius:14px}.customer-receipt-form .pay-card{padding:16px;border-radius:20px;margin-bottom:16px}.customer-receipt-form h2{font-size:18px}.customer-field-grid{grid-template-columns:minmax(0,1fr);gap:18px}.customer-receipt-modes{grid-template-columns:minmax(0,1fr);gap:8px}.customer-date-selects{gap:8px}.customer-receipt-form .customer-date-selects select{padding-inline:6px}.customer-receipt-actions{gap:8px}.customer-receipt-actions .pay-button{width:100%}.customer-service-footer{flex-direction:column;gap:0}.customer-accounts .payment-notice{border-radius:20px}.customer-accounts .payment-notice summary{grid-template-columns:minmax(0,1fr) 20px;padding:16px;gap:6px 8px}.customer-accounts .payment-notice summary strong{grid-column:1;grid-row:1}.customer-accounts .payment-notice summary b{grid-column:1;grid-row:2;justify-self:start;font-size:20px}.customer-accounts .payment-notice summary small{grid-column:1;grid-row:3}.customer-accounts .notice-state{grid-column:1;grid-row:4;justify-self:start}.customer-accounts .payment-notice summary>.cs-icon{grid-column:2;grid-row:1/5}.customer-accounts .pay-details{padding:0 16px 4px}.customer-accounts .payment-values{grid-template-columns:minmax(0,1fr)}.customer-accounts .pay-actions>.pay-button{width:100%}}
/* Review identity and history: names identify actual decisions, not access lists. */
.pay-customer-summary{display:flex;flex-direction:column;gap:3px;margin-top:8px;min-width:0}.pay-customer-summary strong{font-size:14px;font-weight:800}.pay-customer-summary>span{font-size:14px;color:#526c86;line-height:1.8}.pay-record-review{display:flex;flex-direction:column;gap:3px;margin-top:6px;font-size:12px;color:#526c86;line-height:1.8}.pay-linked-receipts{border-top:1px solid #dce5ed;margin-top:20px;padding-top:16px}.pay-linked-receipts>h3{font-size:16px;margin:0 0 12px}.pay-linked-receipt{padding:14px 16px;background:#fafcfe;border:1px solid #dce5ed;border-radius:14px;margin:12px 0}.pay-linked-receipt-head{display:flex;align-items:center;justify-content:space-between;gap:8px;flex-wrap:wrap}.pay-linked-receipt-meta{font-size:14px;color:#526c86}.pay-linked-decision{display:flex;flex-direction:column;gap:4px;padding:10px 0;border-top:1px solid #e7edf2;font-size:14px}.pay-linked-decision time{font-size:12px;color:#526c86}.customer-receipt-detail .pay-page-head{gap:16px;margin-bottom:20px}.customer-receipt-detail .pay-card{padding:22px;border-radius:23px}.customer-receipt-detail .pay-detail-aside .pay-timeline-item{margin-top:12px}.customer-receipt-detail .pay-timeline-item p{overflow-wrap:anywhere}.customer-receipt-detail .pay-page-icon{width:48px;height:48px}.customer-receipt-detail .pay-version-row>div{text-align:end}.pay-version-row .pay-field-hint{margin:4px 0!important}
@media(max-width:639px){.customer-receipt-detail .pay-card{padding:16px;border-radius:20px}.customer-receipt-detail h1{font-size:24px}.pay-linked-receipt{padding:12px}.customer-receipt-detail .pay-version-row>div{text-align:start;width:100%}}
@media(max-width:359px){.customer-accounts .payment-values dd{font-size:14px;letter-spacing:0}}
.pay-notice-permalink{margin:0 12px 12px}.customer-notice-detail .payment-notice>summary{cursor:pointer}.staff-receipt-workspace .customer-finance-title{align-items:flex-start}.staff-receipt-workspace .pay-customer-summary{padding:10px 14px;margin-top:12px;background:#fff;border:1px solid #dce5ed;border-radius:12px}.staff-receipt-workspace .customer-receipt-form{max-width:900px;margin:auto}
.customer-accounts .pay-notice-entry{background:#fff;border:1px solid #dce5ed;border-radius:23px;margin:16px 0;overflow:hidden}.customer-accounts .pay-notice-entry .payment-notice{border:0;border-radius:0;margin:0}.customer-accounts .pay-notice-entry .pay-notice-permalink{display:flex;justify-content:space-between;border-top:1px solid #e7edf2;margin:0;padding:12px 20px;min-height:48px;text-decoration:none;background:#fafcfe}
.pay-identifier-control{display:flex;align-items:stretch;gap:12px}.pay-identifier-control>input{flex:1;min-width:0}.pay-identifier-control>.pay-button{gap:8px;flex-shrink:0;white-space:nowrap;font-size:14px}.pay-identifier-control>.pay-button:disabled{opacity:.6;cursor:not-allowed}.pay-staff-form #id_deposit_id{letter-spacing:.5px}.pay-staff-form #identifier-replacement p{font-size:14px}.pay-staff-form #identifier-replacement .pay-text-link{font:inherit;background:transparent;border:0;color:#526c86;min-height:44px;padding:8px 12px;cursor:pointer}.pay-staff-form #identifier-replacement[hidden]{display:none}
@media(max-width:639px){.pay-identifier-control{flex-direction:column;gap:8px}.pay-identifier-control>.pay-button{align-self:stretch}}
+24
View File
@@ -0,0 +1,24 @@
.magic-confirmation { color: var(--color-ink, #08376b); background: var(--color-cream, #eeeeee); }
.magic-confirmation-shell { width: min(100%, 36rem); margin-inline: auto; padding: clamp(1.5rem, 7vh, 4rem) 1rem max(1.5rem, env(safe-area-inset-bottom)); }
.magic-confirmation-brand { display: flex; justify-content: center; margin-bottom: 1.5rem; }
.magic-confirmation-brand .auth-brand { margin: 0; }
.magic-confirmation-brand img { width: 8.5rem; height: auto; object-fit: contain; }
.magic-confirmation-card { padding: 1.5rem; border: 1px solid #dce5ed; border-top: 3px solid var(--color-coral, #fa9f00); border-radius: 1.25rem; background: #fff; }
.magic-confirmation-icon { display: grid; place-items: center; width: 3rem; height: 3rem; margin-bottom: 1rem; border-radius: .875rem; background: var(--color-mint, #e5f4ff); }
.magic-confirmation-icon svg { width: 1.5rem; height: 1.5rem; }
.magic-confirmation-card h1 { margin: 0; font-size: 1.5rem; font-weight: 900; line-height: 1.6; letter-spacing: normal; }
.magic-confirmation-card p { margin: 1rem 0 0; font-size: 1rem; font-weight: 400; line-height: 1.9; color: #526c86; }
.magic-confirmation-actions { display: grid; gap: .75rem; margin-top: 1.5rem; }
.magic-confirmation-primary, .magic-confirmation-cancel { display: flex; align-items: center; justify-content: center; min-height: 3rem; min-width: 2.75rem; padding: .75rem 1rem; border: 1px solid transparent; border-radius: .75rem; font-size: .875rem; font-weight: 800; line-height: 1.7; text-align: center; white-space: normal; overflow-wrap: anywhere; text-decoration: none; box-shadow: none; transform: none; }
.magic-confirmation-primary { color: #fff; background: var(--color-ink, #08376b); }
.magic-confirmation-primary:hover { background: var(--color-ink-soft, #0b4c8c); box-shadow: none; transform: none; }
.magic-confirmation-cancel { color: var(--color-ink, #08376b); background: #fff; border-color: #dce5ed; }
.magic-confirmation-cancel:hover { background: var(--color-mint, #e5f4ff); border-color: #91bfdd; }
.magic-confirmation-primary:focus-visible, .magic-confirmation-cancel:focus-visible { outline: 3px solid var(--color-sea, #0693e3); outline-offset: 4px; }
.magic-confirmation-primary:disabled { background: var(--color-ink-soft, #0b4c8c); color: #fff; opacity: 1; cursor: wait; }
.magic-confirmation-status:empty { display: none; }
.magic-confirmation-status { color: #526c86; font-size: .875rem; line-height: 1.7; text-align: center; }
.magic-confirmation .auth-footer { margin-top: 1.5rem; color: #526c86; font-size: .75rem; line-height: 1.9; text-align: center; overflow-wrap: anywhere; }
@media (min-width: 640px) { .magic-confirmation-card { padding: 2rem; } .magic-confirmation-card h1 { font-size: 1.75rem; } }
@media (max-width: 359px) { .magic-confirmation-shell { padding-inline: .75rem; } .magic-confirmation-card { padding: 1.25rem; } }
@media (prefers-reduced-motion: reduce) { .magic-confirmation-actions > * { transition: none; } }
+18
View File
@@ -99,3 +99,21 @@ body>.voip-call-status{position:fixed!important;z-index:2147483001;right:auto!im
.contact-history__empty strong{color:#274b65;font-size:.82rem}
.contact-history__empty p{margin:0;color:#78909f;font-size:.68rem}
@media(max-width:640px){.contact-history__heading{flex-wrap:wrap;padding:1rem}.contact-history__heading p{line-height:1.7}.contact-history__total{margin-inline-start:0;margin-inline-end:auto}.contact-history__timeline{padding:1rem .9rem 1rem .7rem}.contact-history__event{padding-right:1.25rem}.contact-history__summary{gap:.55rem;padding:.7rem}.contact-history__change{grid-template-columns:1fr;gap:.35rem}.contact-history__changes{padding:.7rem}.contact-history__values{gap:.3rem}.contact-history__value{padding:.4rem .45rem}}
/* Contextual financial action; local SVG, full customer identity passed by UUID. */
.payment-notice-shortcut{display:inline-flex;align-items:center;justify-content:center;gap:8px;min-height:44px;padding:9px 12px;border:1px solid #b8cfe3;border-radius:12px;background:#e5f4ff;color:#08376b;font-size:14px;font-weight:700;text-decoration:none}.payment-notice-shortcut svg{width:18px;height:18px;flex-shrink:0}.payment-notice-shortcut:hover{background:#d8ecfa;border-color:#91bfdd}.payment-notice-shortcut:focus-visible{outline:3px solid #1977ce;outline-offset:3px}.customer-side .payment-notice-shortcut{display:flex;width:100%;margin-top:16px}.contact-card footer .payment-notice-shortcut{width:100%;font-size:14px;min-height:44px}
.contact-card footer:has(.payment-notice-shortcut){flex-wrap:wrap;gap:8px}.contact-card footer .payment-notice-shortcut{flex-basis:100%;color:#08376b;font-weight:700}
.ticket-notices{margin-top:16px;border:1px solid #cbdce9;border-radius:14px;background:#f8fbfe;overflow:hidden}
.ticket-notices>summary{display:flex;align-items:center;justify-content:space-between;gap:8px;min-height:48px;padding:12px;color:#08376b;font-size:14px;font-weight:700;cursor:pointer;list-style:none;background:#e5f4ff}
.ticket-notices>summary::-webkit-details-marker{display:none}
.ticket-notices-title{display:flex;align-items:center;gap:8px}.ticket-notices-title svg{flex-shrink:0}
.ticket-notices-chevron{font-size:20px;line-height:1}.ticket-notices[open] .ticket-notices-chevron{transform:rotate(180deg)}
.ticket-notices>summary:hover{background:#d8ecfa}.ticket-notices>summary:focus-visible,.ticket-notice-item:focus-visible,.ticket-notices-more:focus-visible{outline:3px solid #1977ce;outline-offset:-3px}
.ticket-notices-content{padding:12px}.customer-side .ticket-notices .payment-notice-shortcut{margin-top:0;padding:8px;font-size:12px;gap:6px}.ticket-notices .payment-notice-shortcut span{white-space:nowrap}
.ticket-notices-caption{margin:14px 0 8px;font-size:12px;color:#536a80}
.ticket-notices-list{display:grid;gap:8px;margin:0;padding:0;list-style:none}
.ticket-notice-item{display:grid;gap:8px;padding:12px 10px;border:1px solid #dce6ee;border-radius:10px;background:#fff;text-decoration:none;color:#08376b}
.ticket-notice-item:hover{border-color:#91bfdd;background:#f0f8ff}.ticket-notice-item strong{font-size:13px;overflow-wrap:anywhere}
.ticket-notice-meta{display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:6px;font-size:11px;color:#536a80}.ticket-notice-meta bdi{font-size:10px}
.ticket-notice-status{padding:3px 7px;border-radius:6px;background:#fff3d8;color:#805b13;font-weight:700}.ticket-notice-status.is-settled{background:#e4f5eb;color:#216544}.ticket-notice-status.is-cancelled{background:#f0f1f4;color:#657080}
.ticket-notices-empty{padding:12px 0;font-size:12px;color:#536a80;line-height:1.8}
.ticket-notices-more{display:flex;align-items:center;flex-wrap:wrap;gap:6px;min-height:44px;margin-top:8px;color:#1977ce;font-size:13px;font-weight:700;text-decoration:none}.ticket-notices-more small{flex:1;font-size:10px;font-weight:400}.ticket-notices-more:hover{text-decoration:underline}
+10
View File
@@ -0,0 +1,10 @@
/* Temporary payment access follows the Chaharsu style guide. */
.pay-share-url{overflow-wrap:anywhere;font-size:14px;line-height:1.8;padding:12px;border:1px solid #dce5ed;border-radius:12px;background:#f6fbff}.pay-detail-aside .pay-card:has(.pay-share-url) form{margin-top:12px}
.pay-link-status{display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:8px 16px;margin-bottom:24px;padding:14px 18px;border:1px solid #cde6f7;border-radius:14px;background:#f6fbff;color:#08376b;line-height:1.8}
.pay-link-status>span{display:flex;align-items:center;gap:8px;font-size:14px;font-weight:700}.pay-link-status .cs-icon{width:20px;height:20px;flex-shrink:0}.pay-link-status small{color:#526c86;font-size:14px}.pay-link-session-label{font-size:14px;color:#526c86}
.payment-values .pay-deposit-required,.customer-accounts .payment-values .pay-deposit-required{background:#fff8f8;border-color:#edc5c5}
.payment-values .pay-deposit-required dt,.payment-values .pay-deposit-required dd,.customer-accounts .payment-values .pay-deposit-required dt,.customer-accounts .payment-values .pay-deposit-required dd{color:#9f1f1f;font-weight:700}
.pay-deposit-warning,.customer-accounts .pay-details>p.pay-deposit-warning{padding:12px 14px;border:1px solid #edc5c5;border-radius:12px;background:#fff8f8;color:#9f1f1f;font-size:14px;line-height:1.9}
.customer-receipt-form #selected-payment .pay-deposit-warning{margin-top:12px;color:#9f1f1f;font-size:14px}.customer-receipt-form #id_deposit_id.pay-deposit-emphasis{color:#9f1f1f;border-color:#d39090;font-weight:700}
.pay-link-message{max-width:620px;margin:48px auto}.pay-link-message .pay-card{padding:32px;border-radius:23px}.pay-link-message h1{margin:20px 0 12px;font-size:24px}.pay-link-message p{color:#526c86;font-size:16px;line-height:1.9;margin-bottom:24px}.pay-link-message .pay-actions{gap:12px;flex-wrap:wrap}
@media(max-width:639px){.pay-link-message{margin:24px auto}.pay-link-message .pay-card{padding:24px 18px}.pay-link-status{padding:12px 14px;margin-bottom:18px}.pay-link-session-label{display:none}.pay-link-message .pay-button{width:100%}}
+25
View File
@@ -0,0 +1,25 @@
/* Selection changes presentation only; permissions and updates remain server-side. */
(() => {
'use strict';
const form = document.querySelector('[data-bank-selection]');
if (!form) return;
const boxes = Array.from(form.querySelectorAll('input[name="accounts"]'));
const all = form.querySelector('[data-select-all]');
const count = form.querySelector('[data-selection-count]');
const submit = form.querySelector('[data-bulk-submit]');
if (!all || !count || !submit) return;
const update = () => {
const selected = boxes.filter(box => box.checked).length;
all.checked = selected > 0 && selected === boxes.length;
all.indeterminate = selected > 0 && selected < boxes.length;
count.textContent = selected ? `${selected.toLocaleString('fa-IR')} حساب انتخاب شده` : 'حساب‌های موردنظر را انتخاب کنید.';
submit.disabled = selected === 0;
};
all.addEventListener('change', () => {
boxes.forEach(box => { box.checked = all.checked; });
update();
});
boxes.forEach(box => box.addEventListener('change', update));
window.addEventListener('pageshow', update);
update();
})();
+94
View File
@@ -0,0 +1,94 @@
/* Local, server-filtered search. Explicit choice only; no customer data in storage. */
(() => {
'use strict';
const root = document.querySelector('[data-payment-customer-picker]');
if (!root) return;
const search = root.querySelector('input[type=search]');
const value = root.querySelector('#id_customer');
const results = root.querySelector('[data-customer-results]');
const selected = root.querySelector('[data-selected-customer]');
const status = root.querySelector('[role=status]');
let timer, controller, version = 0;
const node = (tag, text, className) => {
const element = document.createElement(tag);
if (text !== undefined) element.textContent = text;
if (className) element.className = className;
return element;
};
const history = customer => {
const details = node('details', undefined, 'pay-customer-history');
details.append(node('summary', `سوابق قابل مشاهده · ${customer.ticket_count.toLocaleString('fa-IR')} تیکت`));
if (!customer.history.length) details.append(node('p', 'سابقه تیکت قابل مشاهده‌ای وجود ندارد.'));
customer.history.forEach(ticket => {
const link = node('a', `${ticket.number} · ${ticket.subject}`);
link.href = ticket.url; link.target = '_blank'; link.rel = 'noopener';
const row = node('div'); row.append(link, node('small', ticket.status)); details.append(row);
});
return details;
};
const identity = customer => {
const container = node('div', undefined, 'pay-customer-identity');
container.append(node('strong', customer.name), node('bdi', customer.mobile));
if (customer.organization) container.append(node('span', customer.organization));
container.append(node('small', customer.location || 'موقعیت ثبت نشده'));
return container;
};
const choose = (customer, focus = true) => {
clearTimeout(timer); version++; controller?.abort();
value.value = customer.value; value.dispatchEvent(new Event('change', {bubbles:true}));
search.value = ''; results.hidden = true; results.replaceChildren();
selected.replaceChildren(node('span', 'مشتری انتخاب‌شده', 'pay-selected-label'), identity(customer), history(customer));
const change = node('button', 'تغییر مشتری', 'pay-button secondary'); change.type = 'button';
change.addEventListener('click', () => {
value.value = ''; value.dispatchEvent(new Event('change', {bubbles:true})); selected.hidden = true; search.focus();
status.textContent = 'مشتری جدید را جست‌وجو و انتخاب کنید.';
});
selected.append(change); selected.hidden = false;
status.textContent = 'قبل از صدور، نام و شماره تماس مشتری انتخاب‌شده را بررسی کنید.';
if (focus) change.focus({preventScroll:true});
};
const lookup = async () => {
const query = search.value.trim(), current = ++version;
controller?.abort(); controller = new AbortController();
if (query.length < 2) { results.hidden = true; status.textContent = 'حداقل دو حرف یا رقم وارد کنید.'; return; }
status.textContent = 'در حال جست‌وجو…';
try {
const response = await fetch(`${root.dataset.searchUrl}?q=${encodeURIComponent(query)}`, {
credentials: 'same-origin', cache: 'no-store', signal: controller.signal
});
if (!response.ok) throw new Error('lookup');
const data = await response.json();
if (current !== version) return;
results.replaceChildren();
data.results.forEach(customer => {
const card = node('article', undefined, 'pay-customer-result');
const button = node('button', 'انتخاب این مشتری', 'pay-button secondary'); button.type = 'button';
button.addEventListener('click', () => choose(customer));
card.append(identity(customer), history(customer), button); results.append(card);
});
results.hidden = !data.results.length;
status.textContent = data.results.length ? `${data.results.length.toLocaleString('fa-IR')} نتیجه${data.has_more ? '؛ برای نتایج دقیق‌تر نام یا شماره کامل‌تری وارد کنید.' : '؛ مشتری موردنظر را انتخاب کنید.'}` : 'مشتری فعالی پیدا نشد؛ نام یا شماره تماس را بررسی کنید.';
} catch (error) {
if (error.name === 'AbortError' || current !== version) return;
results.hidden = true;
status.textContent = 'جست‌وجو انجام نشد؛ اتصال را بررسی کنید و دوباره جست‌وجو کنید.';
}
};
search.addEventListener('input', () => {
clearTimeout(timer); version++; controller?.abort();
value.value = ''; value.dispatchEvent(new Event('change', {bubbles:true})); selected.hidden = true; results.hidden = true;
if (search.value.trim().length < 2) { status.textContent = 'حداقل دو حرف یا رقم وارد کنید.'; return; }
timer = setTimeout(lookup, 350);
});
search.addEventListener('keydown', event => {
if (event.key === 'Enter') { event.preventDefault(); clearTimeout(timer); lookup(); }
});
root.closest('form').addEventListener('submit', event => {
if (!value.value) {
event.preventDefault(); status.textContent = 'مشتری را از نتایج جست‌وجو انتخاب کنید.';
search.focus(); search.scrollIntoView({block:'center'});
}
});
const initial = JSON.parse(document.querySelector('#payment-selected-customer').textContent);
if (initial && String(initial.value) === value.value) choose(initial, false);
})();
+44
View File
@@ -0,0 +1,44 @@
/* Customer-only presentation. Financial and image validation remains in receipt-form.js.
Object URLs preview local files without uploading or persisting them. */
(() => {
const form = document.querySelector('.customer-receipt-form');
if (!form) return;
const input = form.elements.namedItem('receipt_image');
const preview = document.querySelector('#receipt-file-preview');
const selection = document.querySelector('#receipt-file-selection');
const status = document.querySelector('#receipt-file-status');
let previewUrl = null;
function releasePreview() {
if (previewUrl) URL.revokeObjectURL(previewUrl);
previewUrl = null;
preview.removeAttribute('src');
preview.hidden = true;
}
function updateFile() {
releasePreview();
const file = input.files[0];
selection.hidden = !file;
status.textContent = file ? file.name + ' · ' + new Intl.NumberFormat('fa-IR', {maximumFractionDigits: 1}).format(file.size / 1024) + ' کیلوبایت' : '';
if (file && /^image\/(jpeg|png|gif|webp)$/.test(file.type)) {
previewUrl = URL.createObjectURL(file);
preview.src = previewUrl;
preview.hidden = false;
}
}
input.addEventListener('change', updateFile);
document.querySelector('#receipt-clear-file').addEventListener('click', () => {
input.value = '';
input.dispatchEvent(new Event('change', {bubbles: true}));
input.focus();
});
window.addEventListener('pagehide', releasePreview);
const origin = form.elements.namedItem('origin_bank');
const other = form.elements.namedItem('origin_other');
function updateOrigin() {
const visible = origin.selectedOptions[0]?.textContent.trim() === 'سایر';
other.closest('[data-field]').hidden = !visible;
other.disabled = !visible;
}
origin.addEventListener('change', updateOrigin);
updateOrigin();
})();
+65
View File
@@ -0,0 +1,65 @@
/* Server calculates the identifier from the selected customer's stored mobile.
Manual values remain editable. Changing customer clears an unchanged auto value. */
(() => {
const button = document.querySelector('#generate-deposit-identifier');
if (!button) return;
const form = button.closest('form');
const customer = form.elements.namedItem('customer');
const input = form.elements.namedItem('deposit_id');
const status = document.querySelector('#identifier-generation-status');
const replacement = document.querySelector('#identifier-replacement');
const candidate = document.querySelector('#identifier-candidate');
const originalLabel = button.innerHTML;
let activeCustomer = customer.value, generated = '', pending = '', controller = null;
function customerChanged() {
if (activeCustomer !== customer.value) {
controller?.abort(); controller = null;
if (generated && input.value === generated) input.value = '';
generated = ''; pending = ''; replacement.hidden = true;
activeCustomer = customer.value;
}
button.disabled = !customer.value;
button.innerHTML = originalLabel;
status.textContent = customer.value ? 'شناسه بر اساس شماره موبایل مشتری انتخاب‌شده تولید می‌شود.' : 'ابتدا مشتری را انتخاب کنید؛ شناسه بر اساس شماره موبایل او تولید می‌شود.';
}
function applyIdentifier(value) {
input.value = value; generated = value; pending = '';
replacement.hidden = true;
input.dispatchEvent(new Event('input', {bubbles:true}));
input.dispatchEvent(new Event('change', {bubbles:true}));
input.focus();
status.textContent = 'شناسه تولید و در فیلد وارد شد؛ قبل از صدور اعلامیه آن را بررسی کنید.';
}
customer.addEventListener('change', customerChanged);
button.addEventListener('click', async () => {
if (!customer.value) return;
const selectedCustomer = customer.value;
const request = new AbortController(); controller = request;
button.disabled = true; button.textContent = 'در حال تولید…';
replacement.hidden = true;
status.textContent = 'در حال دریافت شناسه از سیستم…';
let failureMessage = 'شناسه دریافت نشد؛ اتصال را بررسی کنید و دوباره تلاش کنید.';
try {
const response = await fetch(button.dataset.url, {
method: 'POST', credentials: 'same-origin', cache: 'no-store', signal: request.signal,
headers: {'X-CSRFToken': form.elements.namedItem('csrfmiddlewaretoken').value},
body: new URLSearchParams({customer: selectedCustomer})
});
const data = await response.json();
if (request !== controller || customer.value !== selectedCustomer) return;
if (!response.ok) {failureMessage = data.error || 'شناسه تولید نشد؛ دوباره تلاش کنید.'; throw new Error('generation');}
if (data.customer !== selectedCustomer || !/^[0-9]{13}$/.test(data.identifier)) {failureMessage = 'پاسخ سیستم معتبر نیست؛ دوباره تلاش کنید.'; throw new Error('generation');}
if (input.value.trim() && input.value !== data.identifier) {
pending = data.identifier; candidate.textContent = pending; replacement.hidden = false;
status.textContent = 'شناسه آماده است؛ برای جایگزینی مقدار فعلی، دکمه جایگزینی را بزنید.';
} else applyIdentifier(data.identifier);
} catch (error) {
if (error.name !== 'AbortError' && request === controller) status.textContent = failureMessage;
} finally {
if (request === controller) {controller = null; button.disabled = !customer.value; button.innerHTML = originalLabel;}
}
});
document.querySelector('#apply-deposit-identifier').addEventListener('click', () => {if (pending) applyIdentifier(pending);});
document.querySelector('#cancel-deposit-identifier').addEventListener('click', () => {pending = ''; replacement.hidden = true; status.textContent = 'شناسه فعلی حفظ شد.'; button.focus();});
customerChanged();
})();
+20
View File
@@ -0,0 +1,20 @@
/* All assets and UI behavior are local. No CDN or financial data in persistent browser storage. */
(() => {
'use strict';
let toast;
function status(text){if(!toast){toast=document.createElement('div');toast.className='pay-copy-status';toast.setAttribute('role','status');document.body.append(toast);}toast.textContent=text;toast.hidden=false;setTimeout(()=>{toast.hidden=true;},3000);}
async function copy(text){
try{await navigator.clipboard.writeText(text);status('کپی شد');}
catch{
const dialog=document.createElement('dialog');dialog.className='pay-manual-copy';dialog.setAttribute('aria-label','کپی اطلاعات');
const title=document.createElement('h2');title.textContent='متن را انتخاب و کپی کنید';const area=document.createElement('textarea');area.readOnly=true;area.value=text;
const select=document.createElement('button');select.className='pay-button';select.textContent='انتخاب متن';select.onclick=()=>{area.focus();area.select();};
const close=document.createElement('button');close.className='pay-button secondary';close.textContent='بستن';close.onclick=()=>dialog.close();dialog.append(title,area,select,close);document.body.append(dialog);dialog.addEventListener('close',()=>dialog.remove());dialog.showModal();area.focus();area.select();
}
}
document.querySelectorAll('[data-copy]').forEach(button=>button.addEventListener('click',()=>copy(button.dataset.copy)));
const identifiers=document.querySelector('#identifier-accounts'),account=document.querySelector('#id_account'),deposit=document.querySelector('#id_deposit_id');
if(identifiers && account && deposit){const ids=JSON.parse(identifiers.textContent).map(String);function update(){deposit.required=ids.includes(account.value);document.querySelector('#identifier-help').textContent=deposit.required?'این حساب شناسه‌دار است؛ شناسه واریز مشتری الزامی است.':'شناسه واریز در صورت اعلام بانک وارد شود.';}account.addEventListener('change',update);update();}
const badge=document.querySelector('[data-payment-count]');
if(badge){const update=async()=>{if(document.hidden)return;try{const response=await fetch(badge.dataset.countUrl,{credentials:'same-origin',cache:'no-store'});if(!response.ok)return;const data=await response.json();document.querySelectorAll('[data-payment-count]').forEach(node=>{node.textContent=String(data.pending_receipts);});}catch{}};document.addEventListener('visibilitychange',update);setInterval(update,60000);}
})();
+78
View File
@@ -0,0 +1,78 @@
/* Local amount presentation: never convert rials to tomans for the server.
Exact BigInt arithmetic; preserve fractional toman (one rial = one tenth toman).
Shared with notice amounts; visible grouping does not replace server validation. */
(() => {
'use strict';
const input=document.querySelector('#id_paid_amount, #id_amount');if(!input)return;
input.inputMode='numeric';
const words=document.querySelector('#amount-words');
const small=['صفر','یک','دو','سه','چهار','پنج','شش','هفت','هشت','نه','ده','یازده','دوازده','سیزده','چهارده','پانزده','شانزده','هفده','هجده','نوزده'];
const tens=['','','بیست','سی','چهل','پنجاه','شصت','هفتاد','هشتاد','نود'];
const hundreds=['','صد','دویست','سیصد','چهارصد','پانصد','ششصد','هفتصد','هشتصد','نهصد'];
const scales=['','هزار','میلیون','میلیارد','تریلیون','کوادریلیون'];
const ascii=value=>value.replace(/[۰-۹]/g,digit=>String(digit.charCodeAt(0)-1776)).replace(/[٠-٩]/g,digit=>String(digit.charCodeAt(0)-1632));
const digitCount=value=>(ascii(value).match(/\d/g) || []).length;
const separators=/[,٬ \u00a0]/g;
const grouped=value=>value.replace(/\B(?=(\d{3})+(?!\d))/g,'٬').replace(/\d/g,digit=>'۰۱۲۳۴۵۶۷۸۹'[digit]);
function threeDigits(value){
const parts=[];
if(value>=100)parts.push(hundreds[Math.floor(value/100)]);
const rest=value%100;
if(rest && rest<20)parts.push(small[rest]);
if(rest>=20){parts.push(tens[Math.floor(rest/10)]);if(rest%10)parts.push(small[rest%10]);}
return parts.join(' و ');
}
function numberWords(value){
if(value===0n)return 'صفر';
const parts=[];let index=0;
while(value>0n){
const group=Number(value%1000n);
if(group){const text=group===1 && index===1?'هزار':threeDigits(group)+(scales[index]?' '+scales[index]:'');parts.unshift(text);}
value/=1000n;index++;
}
return parts.join(' و ');
}
function tomanWords(rials){
const whole=rials/10n,fraction=rials%10n;
if(!fraction)return numberWords(whole)+' تومان';
return (whole?numberWords(whole)+' و ':'')+numberWords(fraction)+' دهم تومان';
}
function caretAfterDigits(value,count){
if(!count)return 0;
for(let index=0;index<value.length;index++)if(/\d/.test(ascii(value[index])) && --count===0)return index+1;
return value.length;
}
function formatAmount(event){
if(event?.isComposing)return;
const raw=input.value,start=input.selectionStart ?? raw.length,end=input.selectionEnd ?? start;
const normalized=ascii(raw).trim();
const valid=/^\d+$/.test(normalized) || /^\d{1,3}(?:[,٬ \u00a0]\d{3})+$/.test(normalized);
// Re-group after genuine digit edits/deletion, but never sanitize letters, signs or decimal input.
const editing=event?.inputType?.startsWith('delete') || (event?.inputType==='insertText' && /^\d+$/.test(ascii(event.data || '')));
if(!valid && !(editing && /^[\d,٬ \u00a0]+$/.test(normalized))){if(words)words.textContent='';return;}
const digits=normalized.replace(separators,'').replace(/^0+(?=\d)/,'');
if(!digits || digits.length>16 || BigInt(digits)>BigInt(Number.MAX_SAFE_INTEGER)){if(words)words.textContent='';return;}
const leading=normalized.replace(separators,'').length-digits.length;
const left=Math.max(0,digitCount(raw.slice(0,start))-leading),right=Math.max(0,digitCount(raw.slice(0,end))-leading);
input.value=grouped(digits);
input.setSelectionRange(caretAfterDigits(input.value,left),caretAfterDigits(input.value,right));
if(words)words.textContent='معادل: '+tomanWords(BigInt(digits));
}
input.addEventListener('input',formatAmount);
input.addEventListener('compositionend',()=>formatAmount());
input.addEventListener('beforeinput',event=>{
const start=input.selectionStart,end=input.selectionEnd;
if(start!==end || event.isComposing)return;
const backward=event.inputType==='deleteContentBackward',forward=event.inputType==='deleteContentForward';
const adjacent=backward?start-1:start;
if((!backward && !forward) || !/[٬,]/.test(input.value[adjacent] || ''))return;
// Deleting a separator removes the adjacent digit, so grouping cannot trap the caret.
const target=backward?adjacent-1:adjacent+1;
const count=digitCount(input.value.slice(0,target));
const raw=input.value.slice(0,target)+input.value.slice(target+1);
event.preventDefault();input.value=ascii(raw).replace(separators,'');
input.setSelectionRange(count,count);input.dispatchEvent(new InputEvent('input',{bubbles:true,inputType:event.inputType}));
});
input.addEventListener('blur',()=>formatAmount());
formatAmount();
})();
+70
View File
@@ -0,0 +1,70 @@
/* Server remains authoritative. Display Jalali, submit an ASCII Gregorian date-only.
No dates, bank details or receipts are placed in localStorage/service-worker caches. */
(() => {
'use strict';
const form=document.querySelector('#receipt-form');if(!form)return;
const q=name=>form.elements.namedItem(name),button=document.querySelector('#submit-receipt');
const notices=JSON.parse(document.querySelector('#notice-data').textContent);
const day=q('paid_day'),month=q('paid_month'),year=q('paid_year');
const digits=value=>String(value).replace(/[۰-۹]/g,x=>String(x.charCodeAt(0)-1776)).replace(/[٠-٩]/g,x=>String(x.charCodeAt(0)-1632));
const formatter=new Intl.DateTimeFormat('en-US',{calendar:'persian',numberingSystem:'latn',timeZone:'Asia/Tehran',year:'numeric',month:'numeric',day:'numeric'});
const parts=date=>Object.fromEntries(formatter.formatToParts(date).map(p=>[p.type,p.value]));
function newYear(y){for(let d=18;d<=24;d++){const date=new Date(Date.UTC(y+621,2,d,12)),p=parts(date);if(Number(p.year)===y && Number(p.month)===1 && Number(p.day)===1)return date;}throw Error('تاریخ معتبر نیست.');}
function dateValue(){
const output=document.querySelector('#paid-date-iso');output.value='';
if(!day.value || !month.value || !year.value)return '';
try{const y=Number(year.value),m=Number(month.value),d=Number(day.value),offset=m<=6?(m-1)*31:186+(m-7)*30;const date=new Date(newYear(y).getTime()+(offset+d-1)*86400000),p=parts(date);if(Number(p.year)!==y || Number(p.month)!==m || Number(p.day)!==d)return '';output.value=date.toISOString().slice(0,10);return output.value;}catch{return '';}
}
function dateUpdate(){const iso=dateValue();document.querySelector('#date-preview').textContent=iso?'تاریخ انتخاب‌شده: '+day.options[day.selectedIndex].text+' '+month.options[month.selectedIndex].text+' '+year.value:'روز، ماه و سال پرداخت را کامل انتخاب کنید.';}
function monthUpdate(){
let length=31;
if(month.value && year.value){const m=Number(month.value),y=Number(year.value);length=m<=6?31:m<=11?30:(newYear(y+1)-newYear(y))/86400000===366?30:29;}
[...day.options].forEach(option=>{option.disabled=Number(option.value)>length;});if(Number(day.value)>length)day.value='';dateUpdate();
}
[month,year].forEach(control=>control.addEventListener('change',monthUpdate));day.addEventListener('change',dateUpdate);
document.querySelector('#date-today').addEventListener('click',()=>{const p=parts(new Date());year.value=p.year;month.value=p.month;monthUpdate();day.value=p.day;dateUpdate();day.focus();});monthUpdate();
function sync(){
const linked=q('receipt_mode').value==='linked';const select=q('notice_id');form.querySelector('[data-field=notice_id]').hidden=!linked;select.disabled=!linked;select.required=linked;
if(!linked)select.value='';
const notice=linked?notices.find(n=>n.id===select.value):null;const summary=document.querySelector('#selected-payment');summary.hidden=!notice;
const summaryText=notice?'مبلغ اعلام‌شده: '+new Intl.NumberFormat('fa-IR').format(BigInt(notice.amount))+' ریال · شناسه واریز: '+(notice.deposit || 'اعلام نشده')+(notice.invoice?' · فاکتور: '+notice.invoice:''):'';
const title=summary.querySelector('[data-selected-notice-title]');
if(title){title.textContent=notice?notice.subject:'';summary.querySelector('[data-selected-notice-summary]').textContent=summaryText;summary.querySelector('[data-selected-notice-link]').href=notice?notice.url:'#';}else summary.textContent=summaryText;
const finalSummary=document.querySelector('#receipt-summary');if(finalSummary)finalSummary.textContent=notice?'این فیش برای «'+notice.subject+'» ارسال می‌شود.':linked?'اعلامیه مرتبط را انتخاب کنید.':'این فیش به صورت واریز مستقل برای بررسی ارسال می‌شود.';
const depositWarning=summary.querySelector('[data-selected-deposit-warning]');
depositWarning.hidden=!notice?.deposit;
q('deposit_id').classList.toggle('pay-deposit-emphasis',Boolean(notice?.deposit));
q('deposit_id').required=false;
}
form.querySelectorAll('[name=receipt_mode]').forEach(control=>control.addEventListener('change',sync));q('notice_id').addEventListener('change',()=>{const notice=notices.find(n=>n.id===q('notice_id').value);if(notice){q('destination_account').value=String(notice.account);q('deposit_id').value=notice.deposit;}sync();});q('destination_account').addEventListener('change',sync);sync();
const fields=[...form.querySelectorAll('[data-field]')];
fields.forEach(field=>{const controls=field.querySelectorAll('input,select,textarea');controls.forEach(control=>{control.setAttribute('aria-describedby','error-'+field.dataset.field);if(field.querySelector('.field-error').textContent.trim())control.setAttribute('aria-invalid','true');});});
let busy=false;
function showErrors(errors){
fields.forEach(field=>{const name=field.dataset.field,message=errors.get(name)||'',error=field.querySelector('.field-error');error.textContent=message;error.hidden=!message;field.querySelectorAll('input,select,textarea').forEach(control=>control.setAttribute('aria-invalid',String(Boolean(message))));});
const summary=document.querySelector('#receipt-errors'),list=summary.querySelector('ul');list.replaceChildren();errors.forEach((message,name)=>{const item=document.createElement('li'),link=document.createElement('a');link.href='#id_'+name;link.textContent=message;link.onclick=event=>{event.preventDefault();q(name).focus();q(name).scrollIntoView({block:'center'});};item.append(link);list.append(item);});summary.hidden=!errors.size;
if(errors.size){const first=q(errors.keys().next().value);first.focus();first.scrollIntoView({block:'center'});}
}
async function validateImage(file){
if(!file)return 'تصویر فیش واریز را انتخاب کنید.';
if(!file.size || file.size>Number(form.dataset.maxBytes))return 'حجم تصویر بیش از حد مجاز است یا تصویر خالی است.';
const extension=file.name.split('.').pop().toLowerCase();if(!['jpg','jpeg','png','gif','webp'].includes(extension))return 'فقط تصویر JPG، PNG، GIF یا WEBP انتخاب کنید.';
const readable=await new Promise(resolve=>{const picture=new Image(),url=URL.createObjectURL(file);picture.onload=()=>{URL.revokeObjectURL(url);resolve(picture.naturalWidth*picture.naturalHeight<=25000000);};picture.onerror=()=>{URL.revokeObjectURL(url);resolve(false);};picture.src=url;});return readable?'':'تصویر باز نمی‌شود یا ابعاد آن بیش از حد مجاز است.';
}
let revision=0;form.addEventListener('input',()=>revision++);form.addEventListener('change',()=>revision++);
form.addEventListener('submit',async event=>{
event.preventDefault();if(busy)return;busy=true;button.disabled=true;const version=revision,errors=new Map();
try{
const value=digits(q('paid_amount').value).trim();if(!/^\d+$/.test(value) && !/^\d{1,3}(?:[,٬ ]\d{3})+$/.test(value))errors.set('paid_amount','مبلغ را به ریال و با عدد صحیح وارد کنید.');else{const amount=BigInt(value.replace(/[,٬ ]/g,''));if(amount<=0n || amount>9007199254740991n)errors.set('paid_amount','مبلغ باید مثبت و در محدوده مجاز باشد.');}
if(q('receipt_mode').value==='linked' && !q('notice_id').value)errors.set('notice_id','اعلامیه را انتخاب کنید یا واریز مستقل را بزنید.');
if(!q('destination_account').value)errors.set('destination_account','حساب مقصد را انتخاب کنید.');
const iso=dateValue();if(!iso)errors.set('paid_day','تاریخ را کامل و معتبر انتخاب کنید؛ روز، ماه و سال لازم‌اند.');
else{const now=Object.fromEntries(new Intl.DateTimeFormat('en-US',{timeZone:'Asia/Tehran',year:'numeric',month:'2-digit',day:'2-digit'}).formatToParts(new Date()).map(p=>[p.type,p.value]));if(iso>[now.year,now.month,now.day].join('-'))errors.set('paid_day','تاریخ واریز نمی‌تواند بعد از امروز باشد.');}
const imageError=await validateImage(q('receipt_image').files[0]);if(imageError)errors.set('receipt_image',imageError);
if(version!==revision){document.querySelector('#form-status').textContent='اطلاعات تغییر کرده است؛ دوباره ارسال را بزنید.';return;}
showErrors(errors);if(errors.size)return;
button.textContent='در حال ثبت…';HTMLFormElement.prototype.submit.call(form);return;
}finally{busy=false;if(button.textContent!=='در حال ثبت…')button.disabled=false;}
});
if(document.querySelector('#receipt-errors').hidden===false){const field=form.querySelector('[aria-invalid=true]');if(field){field.focus();field.scrollIntoView({block:'center'});}}
})();
+21
View File
@@ -0,0 +1,21 @@
const confirmationForm = document.querySelector('[data-magic-confirmation]');
if (confirmationForm) {
confirmationForm.addEventListener('submit', (event) => {
const button = confirmationForm.querySelector('button[type="submit"]');
if (button.disabled) {
event.preventDefault();
return;
}
button.disabled = true;
button.setAttribute('aria-busy', 'true');
button.textContent = 'در حال باز کردن تیکت…';
confirmationForm.querySelector('[role="status"]').textContent = button.textContent;
});
window.addEventListener('pageshow', () => {
const button = confirmationForm.querySelector('button[type="submit"]');
button.disabled = false;
button.removeAttribute('aria-busy');
button.textContent = 'خروج از حساب و مشاهده تیکت';
confirmationForm.querySelector('[role="status"]').textContent = '';
});
}
+16
View File
@@ -0,0 +1,16 @@
(() => {
const events = document.querySelector('#id_event_type');
const tags = document.querySelector('#sms-allowed-tags');
const data = document.querySelector('#sms-tag-map');
if (!events || !tags || !data) return;
const mapping = JSON.parse(data.textContent);
function showAllowedTags() {
tags.replaceChildren(...(mapping[events.value] || []).map(tag => {
const code = document.createElement('code');
code.textContent = '{' + tag + '}';
return code;
}));
}
events.addEventListener('change', showAllowedTags);
showAllowedTags();
})();