ClubLedger/static/style.css
Claude 7dfe66f5a1
feat: cashier stat widgets — outstanding credit and period summary
Adds two widgets at the top of the Cashier view:
- Total outstanding credit across all member accounts
- Transaction summary (top-ups / withdrawals / charges / net) with
  period selector: today, this week, month, quarter, year, or custom
  date range. Backed by new GET /cashier/stats endpoint that respects
  the configured display timezone for period boundaries.

https://claude.ai/code/session_01JuRTR5Xjx8emQsyerBgGU7
2026-05-31 03:37:15 +00:00

714 lines
16 KiB
CSS
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* ClubLedger GitHub-style theme */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
:root {
--canvas: #ffffff;
--canvas-subtle: #f6f8fa;
--border: #d0d7de;
--border-muted: #d8dee4;
--fg: #1f2328;
--fg-muted: #59636e;
--fg-subtle: #818b98;
--accent: #0969da;
--accent-muted: #ddf4ff;
--success: #1a7f37;
--success-muted: #dafbe1;
--danger: #d1242f;
--danger-muted: #ffebe9;
--nav-bg: #24292f;
--nav-text: #f0f6fc;
--radius: 6px;
}
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Noto Sans", Helvetica, Arial, sans-serif;
font-size: 14px;
line-height: 1.5;
background: var(--canvas-subtle);
color: var(--fg);
min-height: 100vh;
}
/* ---- Nav ---- */
nav {
background: var(--nav-bg);
color: var(--nav-text);
display: flex;
align-items: stretch;
padding: 0 16px;
height: 48px;
gap: 0;
position: sticky;
top: 0;
z-index: 100;
}
/* On desktop the wrapper is invisible — buttons behave as direct nav children */
.nav-tabs { display: contents; }
.brand {
font-size: 1rem;
font-weight: 600;
color: #fff;
margin-right: 16px;
padding-right: 16px;
border-right: 1px solid rgba(240,246,252,.15);
white-space: nowrap;
display: inline-flex;
align-items: center;
gap: 8px;
align-self: center;
}
.brand::before {
content: "";
display: inline-block;
width: 18px;
height: 18px;
background: #fff;
border-radius: 50%;
opacity: .85;
flex-shrink: 0;
}
.nav-btn, .nav-link {
display: inline-flex;
align-items: center;
gap: 6px;
padding: 0 14px;
align-self: stretch;
background: transparent;
border: none;
border-bottom: 2px solid transparent;
border-radius: 0;
color: rgba(240,246,252,.65);
cursor: pointer;
font-size: .875rem;
font-family: inherit;
font-weight: 400;
white-space: nowrap;
text-decoration: none;
transition: color .1s, border-color .1s, background .1s;
}
.nav-btn:hover, .nav-link:hover {
color: var(--nav-text);
background: rgba(177,186,196,.1);
border-bottom-color: rgba(240,246,252,.35);
}
.nav-btn.active, .nav-link.active {
color: #fff;
font-weight: 600;
border-bottom-color: #fff;
}
/* Material Symbols inside nav tabs */
.nav-icon {
font-size: 18px;
line-height: 1;
font-variation-settings: 'FILL' 0, 'wght' 300, 'GRAD' 0, 'opsz' 20;
transition: font-variation-settings .1s;
}
.nav-btn.active .nav-icon, .nav-link.active .nav-icon {
font-variation-settings: 'FILL' 1, 'wght' 400, 'GRAD' 0, 'opsz' 20;
}
/* ---- Views ---- */
.view { max-width: 960px; margin: 24px auto; padding: 0 16px; display: flex; flex-direction: column; gap: 20px; }
.hidden { display: none !important; }
/* ---- Panel ---- */
.panel {
background: var(--canvas);
border: 1px solid var(--border);
border-radius: var(--radius);
padding: 20px 24px;
}
.panel h2 {
font-size: 1rem;
font-weight: 600;
padding-bottom: 12px;
margin-bottom: 16px;
border-bottom: 1px solid var(--border);
color: var(--fg);
}
/* ---- Forms ---- */
.form-row { display: flex; flex-direction: column; gap: 4px; margin-bottom: 12px; }
.form-row label {
font-size: .8125rem;
font-weight: 600;
color: var(--fg);
}
.form-row input,
.form-row select,
.form-row textarea {
padding: 5px 12px;
border: 1px solid var(--border);
border-radius: var(--radius);
font-size: .875rem;
font-family: inherit;
background: var(--canvas);
color: var(--fg);
outline: none;
transition: border-color .15s, box-shadow .15s;
line-height: 20px;
}
.form-row input:focus,
.form-row select:focus,
.form-row textarea:focus {
border-color: var(--accent);
box-shadow: 0 0 0 3px rgba(9,105,218,.12);
}
.form-row select { cursor: pointer; }
.form-row textarea { resize: vertical; min-height: 64px; }
.search-row { display: flex; gap: 8px; margin-bottom: 12px; }
.search-row input {
flex: 1;
padding: 5px 12px;
border: 1px solid var(--border);
border-radius: var(--radius);
font-size: .875rem;
font-family: inherit;
background: var(--canvas);
outline: none;
transition: border-color .15s, box-shadow .15s;
}
.search-row input:focus {
border-color: var(--accent);
box-shadow: 0 0 0 3px rgba(9,105,218,.12);
}
/* ---- Buttons ---- */
.btn {
display: inline-flex;
align-items: center;
justify-content: center;
gap: 6px;
padding: 5px 16px;
border: 1px solid var(--border);
border-radius: var(--radius);
background: var(--canvas-subtle);
color: var(--fg);
cursor: pointer;
font-size: .875rem;
font-family: inherit;
font-weight: 500;
line-height: 20px;
white-space: nowrap;
transition: background .1s, border-color .1s;
margin-right: 4px;
}
.btn:hover { background: #f3f4f6; border-color: rgba(31,35,40,.3); }
.btn-primary {
background: #1f883d;
color: #fff;
border-color: rgba(31,35,40,.15);
}
.btn-primary:hover { background: #1a7f37; }
.btn-danger {
background: #d1242f;
color: #fff;
border-color: rgba(31,35,40,.15);
}
.btn-danger:hover { background: #b91c28; }
/* ---- Data table ---- */
.data-table { width: 100%; border-collapse: collapse; font-size: .8125rem; margin-top: 4px; }
.data-table th {
background: var(--canvas-subtle);
padding: 8px 12px;
text-align: left;
font-weight: 600;
color: var(--fg-muted);
font-size: .75rem;
text-transform: uppercase;
letter-spacing: .04em;
border-top: 1px solid var(--border);
border-bottom: 1px solid var(--border);
}
.data-table td { padding: 10px 12px; border-bottom: 1px solid var(--border-muted); }
.data-table tr:last-child td { border-bottom: none; }
.data-table tbody tr:hover td { background: var(--canvas-subtle); }
.num { text-align: right; font-variant-numeric: tabular-nums; }
.balance-pos { color: var(--success); font-weight: 600; }
.balance-neg { color: var(--danger); font-weight: 600; }
/* ---- Member pick list ---- */
.member-pick-list { margin-bottom: 12px; display: flex; flex-direction: column; gap: 1px; }
.member-pick-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px 14px;
background: var(--canvas);
border: 1px solid var(--border);
border-radius: var(--radius);
cursor: pointer;
transition: background .1s, border-color .1s;
}
.member-pick-item:hover { background: var(--canvas-subtle); border-color: var(--accent); }
.member-pick-name { font-weight: 600; font-size: .875rem; }
.member-pick-sub { font-size: .75rem; color: var(--fg-muted); }
/* ---- Selected member box ---- */
.selected-member-box {
background: var(--accent-muted);
border: 1px solid #b6e3ff;
border-radius: var(--radius);
padding: 10px 14px;
margin-bottom: 14px;
font-size: .875rem;
color: var(--fg);
}
.selected-member-box strong { font-size: .9375rem; font-weight: 600; }
/* ---- Cashier dual-action panels ---- */
.cashier-action-panel {
border: 1px solid var(--border);
border-radius: var(--radius);
padding: 16px;
margin-bottom: 10px;
background: var(--canvas);
}
.cashier-action-panel h3 {
margin: 0 0 12px;
font-size: .6875rem;
font-weight: 600;
color: var(--fg-muted);
text-transform: uppercase;
letter-spacing: .06em;
}
/* ---- Product results ---- */
.product-results { margin-bottom: 12px; }
.product-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 8px 12px;
border: 1px solid var(--border);
border-radius: var(--radius);
margin-bottom: 4px;
cursor: pointer;
font-size: .875rem;
transition: background .1s;
}
.product-item:hover { background: var(--canvas-subtle); border-color: var(--accent); }
.product-price { font-weight: 700; color: var(--accent); }
/* ---- Staff chips ---- */
.staff-chips { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
.staff-chip {
display: inline-flex;
align-items: center;
gap: 4px;
background: var(--canvas-subtle);
border: 1px solid var(--border);
border-radius: 2em;
padding: 2px 8px 2px 10px;
font-size: .8125rem;
color: var(--fg);
}
.chip-del {
background: none;
border: none;
cursor: pointer;
color: var(--fg-subtle);
font-size: .9rem;
line-height: 1;
padding: 0 1px;
}
.chip-del:hover { color: var(--danger); }
/* ---- Select / dropdown (standalone, outside form-row) ---- */
select {
font-family: inherit;
}
/* ---- Row action buttons ---- */
.row-actions { white-space: nowrap; }
.row-btn { padding: 3px 10px !important; font-size: .75rem !important; margin-right: 4px !important; }
/* ---- Edit modal ---- */
.modal-overlay {
position: fixed;
inset: 0;
background: rgba(31,35,40,.5);
display: flex;
align-items: center;
justify-content: center;
z-index: 200;
}
.modal {
background: var(--canvas);
border: 1px solid var(--border);
border-radius: 12px;
padding: 24px 28px;
width: 440px;
max-width: calc(100vw - 32px);
box-shadow: 0 8px 24px rgba(140,149,159,.2);
}
.modal h3 {
font-size: 1rem;
font-weight: 600;
padding-bottom: 12px;
margin-bottom: 16px;
border-bottom: 1px solid var(--border);
}
.modal-actions { display: flex; gap: 8px; margin-top: 16px; }
/* ---- Messages / flash ---- */
.msg {
margin-top: 10px;
padding: 8px 14px;
border-radius: var(--radius);
font-size: .8125rem;
border: 1px solid transparent;
}
.msg:empty { display: none; }
.msg.ok { background: var(--success-muted); color: #0a3622; border-color: #a4e6b8; }
.msg.err { background: var(--danger-muted); color: #67060c; border-color: #ffcec7; }
/* ---- Login overlay ---- */
.login-overlay {
position: fixed;
inset: 0;
background: var(--canvas-subtle);
display: flex;
align-items: center;
justify-content: center;
z-index: 500;
}
.login-card {
background: var(--canvas);
border: 1px solid var(--border);
border-radius: 12px;
padding: 36px 40px;
width: 360px;
max-width: calc(100vw - 32px);
box-shadow: 0 8px 24px rgba(140,149,159,.2);
}
.login-card h1 {
font-size: 1.25rem;
font-weight: 600;
text-align: center;
margin-bottom: 4px;
}
.login-sub { text-align: center; color: var(--fg-muted); font-size: .8125rem; margin-bottom: 20px; }
/* ---- Nav right (user + logout) ---- */
.nav-right { margin-left: auto; display: flex; align-items: center; gap: 10px; align-self: center; }
.nav-user { color: rgba(240,246,252,.7); font-size: .8125rem; }
.nav-logout {
background: transparent;
border: 1px solid rgba(240,246,252,.3);
color: rgba(240,246,252,.7);
padding: 3px 12px;
border-radius: var(--radius);
cursor: pointer;
font-size: .8125rem;
font-family: inherit;
transition: color .1s, border-color .1s;
}
.nav-logout:hover { color: var(--nav-text); border-color: rgba(240,246,252,.5); }
/* ---- Admin form extras ---- */
.label-hint { font-weight: 400; color: var(--fg-subtle); font-size: .75rem; }
.form-row-check { flex-direction: row !important; align-items: center; gap: 8px; }
.form-row-check label { font-weight: 400; color: var(--fg); font-size: .875rem; }
.panel-divider { border: none; border-top: 1px solid var(--border); margin: 18px 0; }
.sub-heading { font-size: .875rem; font-weight: 600; margin-bottom: 12px; color: var(--fg); }
/* ---- PIN confirmation overlay ---- */
.pin-overlay {
position: fixed;
inset: 0;
background: var(--canvas);
display: flex;
align-items: center;
justify-content: center;
z-index: 150;
padding: 24px 16px;
}
.pin-card {
display: flex;
flex-direction: column;
align-items: center;
gap: 16px;
width: 100%;
max-width: 380px;
}
.pin-charge-amount {
font-size: clamp(2rem, 8vw, 3rem);
font-weight: 700;
color: var(--fg);
text-align: center;
line-height: 1.15;
}
.pin-member-name {
font-size: 1.0625rem;
color: var(--fg-muted);
text-align: center;
}
.pin-instruction {
font-size: .875rem;
color: var(--fg-subtle);
text-align: center;
margin-top: 8px;
}
.pin-input {
width: 100%;
max-width: 260px;
padding: 14px 16px;
font-size: 1.5rem;
letter-spacing: .25em;
text-align: center;
border: 2px solid var(--border);
border-radius: var(--radius);
outline: none;
background: var(--canvas);
color: var(--fg);
transition: border-color .15s, box-shadow .15s;
}
.pin-input:focus {
border-color: var(--accent);
box-shadow: 0 0 0 3px rgba(9,105,218,.15);
}
.pin-actions {
display: flex;
gap: 12px;
width: 100%;
max-width: 260px;
}
.pin-cancel-btn {
flex: 1;
}
.pin-ok-btn {
flex: 2;
font-size: 1rem;
padding: 10px 0;
}
/* ---- Hamburger button (hidden on desktop) ---- */
.hamburger {
display: none;
align-items: center;
justify-content: center;
background: transparent;
border: 1px solid rgba(240,246,252,.3);
border-radius: var(--radius);
color: var(--nav-text);
width: 34px;
height: 30px;
cursor: pointer;
padding: 0;
transition: background .1s;
}
.hamburger:hover { background: rgba(177,186,196,.15); }
.hamburger .material-symbols-outlined { font-size: 20px; line-height: 1; }
/* ---- Mobile nav ---- */
@media (max-width: 640px) {
/* Hide desktop tabs, show hamburger */
.nav-tabs {
display: none;
position: fixed;
top: 48px;
left: 0;
right: 0;
background: var(--nav-bg);
flex-direction: column;
padding: 6px 0 10px;
border-bottom: 1px solid rgba(240,246,252,.12);
box-shadow: 0 8px 16px rgba(0,0,0,.35);
z-index: 99;
}
.nav-tabs.open { display: flex; }
.hamburger { display: inline-flex; }
/* Hide username text to save space */
.nav-user { display: none; }
/* Mobile tab items: full-width rows with left accent border */
.nav-btn, .nav-link {
align-self: auto;
width: 100%;
padding: 13px 20px;
font-size: .9375rem;
border-bottom: none;
border-left: 3px solid transparent;
border-radius: 0;
justify-content: flex-start;
gap: 12px;
}
.nav-btn:hover, .nav-link:hover {
border-bottom-color: transparent;
border-left-color: rgba(240,246,252,.35);
background: rgba(177,186,196,.12);
}
.nav-btn.active, .nav-link.active {
border-bottom-color: transparent;
border-left-color: #fff;
background: rgba(177,186,196,.12);
}
.nav-icon { font-size: 20px; }
}
/* ---- Cashier stat widgets ---- */
.stats-row {
display: flex;
gap: 16px;
}
.stat-card {
flex: 1;
background: var(--canvas);
border: 1px solid var(--border);
border-radius: var(--radius);
padding: 16px 20px;
}
.stat-label {
font-size: .75rem;
font-weight: 600;
color: var(--fg-muted);
text-transform: uppercase;
letter-spacing: .04em;
margin-bottom: 6px;
}
.stat-value {
font-size: 1.75rem;
font-weight: 700;
color: var(--fg);
font-variant-numeric: tabular-nums;
}
.stats-panel h2 {
margin-bottom: 0;
border-bottom: none;
padding-bottom: 0;
}
.stats-header {
display: flex;
align-items: center;
justify-content: space-between;
flex-wrap: wrap;
gap: 10px;
padding-bottom: 14px;
margin-bottom: 16px;
border-bottom: 1px solid var(--border);
}
.stats-period-row {
display: flex;
align-items: center;
gap: 8px;
flex-wrap: wrap;
}
.stats-period-row select {
padding: 4px 8px;
border: 1px solid var(--border);
border-radius: var(--radius);
font-size: .8125rem;
font-family: inherit;
background: var(--canvas);
cursor: pointer;
}
.stats-custom {
display: flex;
align-items: center;
gap: 6px;
font-size: .8125rem;
color: var(--fg-muted);
}
.stats-custom input[type="date"] {
padding: 4px 8px;
border: 1px solid var(--border);
border-radius: var(--radius);
font-size: .8125rem;
font-family: inherit;
background: var(--canvas);
color: var(--fg);
}
.stats-summary {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 1px;
background: var(--border);
border: 1px solid var(--border);
border-radius: var(--radius);
overflow: hidden;
}
.stats-col {
background: var(--canvas);
padding: 14px 16px;
display: flex;
flex-direction: column;
gap: 4px;
}
.stats-col-net {
background: var(--canvas-subtle);
}
.stats-col-label {
font-size: .6875rem;
font-weight: 600;
color: var(--fg-muted);
text-transform: uppercase;
letter-spacing: .05em;
}
.stats-col-value {
font-size: 1.125rem;
font-weight: 700;
font-variant-numeric: tabular-nums;
color: var(--fg);
}
.stats-col-count {
font-size: .75rem;
color: var(--fg-subtle);
}
.stats-positive { color: var(--success); }
.stats-negative { color: var(--danger); }
@media (max-width: 600px) {
.stats-summary {
grid-template-columns: 1fr 1fr;
}
}
@media (max-width: 380px) {
.stats-summary {
grid-template-columns: 1fr;
}
}