/* Behavision desktop — an instrument panel, not a website. A shop PC runs this all day on a cheap monitor, so: high contrast, dense but not cramped, and state readable at a glance from across a counter. */ :root { --ground: #0E1317; --surface: #161D23; --surface-2: #1D262D; --line: #27333B; --line-soft: #1F2A31; --ink: #E7EEF3; --ink-2: #B4C2CC; --muted: #7C8B97; --accent: #45B0C7; --accent-dim:#123039; --ok: #4FB37B; --warn: #E0A33A; --bad: #E0655A; --radius: 8px; --mono: "SFMono-Regular", ui-monospace, Menlo, Consolas, monospace; } * { box-sizing: border-box; margin: 0; } html, body, #root { height: 100%; } body { background: var(--ground); color: var(--ink); font: 14px/1.55 system-ui, -apple-system, "Segoe UI", sans-serif; -webkit-font-smoothing: antialiased; overflow: hidden; user-select: none; } button, input, select, textarea { font: inherit; color: inherit; } :focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; } /* ---------------------------------------------------------------- shell -- */ .shell { display: grid; grid-template-columns: 216px 1fr; height: 100%; } .side { background: var(--surface); border-right: 1px solid var(--line); display: flex; flex-direction: column; min-height: 0; } .side .brand { padding: 18px 18px 14px; border-bottom: 1px solid var(--line-soft); } .side .brand h1 { font-size: 15px; font-weight: 650; letter-spacing: -.01em; } .side .brand p { font-size: 11.5px; color: var(--muted); margin-top: 3px; } .nav { padding: 10px 10px; display: flex; flex-direction: column; gap: 2px; flex: 1; } .nav button { display: flex; align-items: center; gap: 10px; width: 100%; background: none; border: 0; border-radius: 6px; padding: 8px 10px; color: var(--ink-2); cursor: pointer; text-align: left; font-size: 13.5px; } .nav button:hover { background: var(--surface-2); color: var(--ink); } .nav button[aria-current="page"] { background: var(--accent-dim); color: var(--accent); font-weight: 550; } .nav .glyph { width: 16px; text-align: center; opacity: .85; font-size: 13px; } .enginebox { padding: 12px; border-top: 1px solid var(--line-soft); } .enginebox .row { display: flex; align-items: center; gap: 8px; font-size: 12px; } .enginebox .label { color: var(--muted); font-size: 11px; margin-top: 2px; display: block; line-height: 1.4; } .enginebox .actions { display: flex; gap: 6px; margin-top: 10px; } .main { min-width: 0; min-height: 0; overflow-y: auto; } .page { padding: 22px 26px 40px; max-width: 1180px; } .page > header { margin-bottom: 18px; } .page h2 { font-size: 19px; font-weight: 620; letter-spacing: -.01em; } .page header p { color: var(--muted); font-size: 13px; margin-top: 3px; } /* --------------------------------------------------------------- pieces -- */ .card { background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); padding: 16px; } .card h3 { font-size: 12px; text-transform: uppercase; letter-spacing: .07em; color: var(--muted); font-weight: 600; margin-bottom: 12px; } .grid { display: grid; gap: 14px; } .cols-4 { grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); } .cols-2 { grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); } .stat .value { font-size: 30px; font-weight: 620; letter-spacing: -.02em; font-variant-numeric: tabular-nums; line-height: 1.1; } .stat .unit { font-size: 15px; color: var(--muted); margin-left: 3px; } .stat .sub { color: var(--muted); font-size: 12px; margin-top: 5px; } .dot { width: 8px; height: 8px; border-radius: 50%; flex: none; } .dot.ok { background: var(--ok); } .dot.warn { background: var(--warn); } .dot.bad { background: var(--bad); } .dot.idle { background: var(--muted); } .pill { display: inline-flex; align-items: center; gap: 5px; font-size: 11px; padding: 3px 8px; border-radius: 99px; border: 1px solid var(--line); color: var(--muted); white-space: nowrap; } .pill.ok { color: var(--ok); border-color: #2b5c42; background: #12251b; } .pill.warn { color: var(--warn); border-color: #5c4a22; background: #241d0f; } .pill.bad { color: var(--bad); border-color: #5c2e2a; background: #241312; } .btn { background: var(--surface-2); border: 1px solid var(--line); border-radius: 6px; padding: 7px 13px; cursor: pointer; font-size: 13px; color: var(--ink); white-space: nowrap; } .btn:hover:not(:disabled) { background: #26323a; } .btn:disabled { opacity: .45; cursor: default; } .btn.primary { background: var(--accent); border-color: var(--accent); color: #06222a; font-weight: 600; } .btn.primary:hover:not(:disabled) { background: #5ac0d6; } .btn.danger { color: var(--bad); border-color: #4a2823; } .btn.sm { padding: 4px 9px; font-size: 12px; } .field { display: block; margin-bottom: 12px; } .field span { display: block; font-size: 11.5px; color: var(--muted); margin-bottom: 4px; letter-spacing: .01em; } .field input, .field select, .field textarea { width: 100%; background: var(--ground); border: 1px solid var(--line); border-radius: 6px; padding: 8px 10px; font-size: 13.5px; user-select: text; } .field input:focus, .field select:focus, .field textarea:focus { border-color: var(--accent); outline: none; } .field textarea { resize: vertical; min-height: 66px; } .fieldrow { display: grid; gap: 0 12px; grid-template-columns: 1fr 1fr; } table { width: 100%; border-collapse: collapse; font-size: 13px; } th { text-align: left; font-size: 10.5px; text-transform: uppercase; letter-spacing: .08em; color: var(--muted); font-weight: 600; padding: 8px 10px; border-bottom: 1px solid var(--line); } td { padding: 9px 10px; border-bottom: 1px solid var(--line-soft); vertical-align: middle; } tr:last-child td { border-bottom: 0; } tbody tr.click { cursor: pointer; } tbody tr.click:hover { background: var(--surface-2); } td.num { font-variant-numeric: tabular-nums; text-align: right; } .tablewrap { overflow-x: auto; } .empty { color: var(--muted); font-size: 13px; padding: 26px 4px; text-align: center; } .err { border: 1px solid #5c2e2a; background: #241312; color: #f0b3ad; border-radius: 6px; padding: 10px 12px; font-size: 13px; margin-bottom: 14px; } .note { color: var(--muted); font-size: 12.5px; } .mono { font-family: var(--mono); font-size: 12px; } /* --------------------------------------------------------------- login --- */ .login { height: 100%; display: grid; place-items: center; padding: 24px; } .login .box { width: 100%; max-width: 380px; } .login h1 { font-size: 21px; font-weight: 650; letter-spacing: -.015em; } .login .lead { color: var(--muted); font-size: 13px; margin: 6px 0 22px; } .login form { background: var(--surface); border: 1px solid var(--line); border-radius: 10px; padding: 20px; } .login .btn { width: 100%; margin-top: 6px; } .login .foot { color: var(--muted); font-size: 11.5px; margin-top: 14px; text-align: center; line-height: 1.5; } /* The second way out of the setup screen: a shop with no head office. Styled quieter than the form above it because linking is still the common case, but present, because for a single-till shop it is the only one that works. */ .login .alt { margin-top: 18px; padding-top: 16px; text-align: center; border-top: 1px solid var(--line-soft); } .login .alt .note { line-height: 1.55; margin-bottom: 12px; text-align: left; } .login .alt .btn { margin-top: 0; } .linkbtn { background: none; border: 0; padding: 0; cursor: pointer; font: inherit; font-size: 12.5px; color: var(--accent); text-decoration: underline; text-underline-offset: 3px; } .linkbtn:hover { color: var(--ink); } /* ---------------------------------------------------------------- live --- */ .feeds { display: grid; gap: 14px; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); } .feed { background: #000; border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden; } .feed img { width: 100%; display: block; aspect-ratio: 16/9; object-fit: cover; background: #000; } .feed .cap { display: flex; justify-content: space-between; align-items: center; padding: 8px 11px; background: var(--surface); font-size: 12.5px; } .events { list-style: none; max-height: 420px; overflow-y: auto; } .events li { display: flex; gap: 9px; align-items: baseline; padding: 7px 2px; border-bottom: 1px solid var(--line-soft); font-size: 12.5px; } .events li:last-child { border-bottom: 0; } .events .when { color: var(--muted); font-family: var(--mono); font-size: 11px; flex: none; } .tag { font-size: 10px; padding: 2px 6px; border-radius: 4px; flex: none; background: var(--surface-2); color: var(--muted); } .tag.new { background: #17364f; color: #86c2ec; } .tag.seen { background: #14301f; color: #7fcb9c; } .tag.miss { background: #3a1c1a; color: #eb9a92; } /* -------------------------------------------------------------- charts --- */ .bars { display: flex; align-items: flex-end; gap: 3px; height: 150px; margin-top: 4px; } .bars .col { flex: 1; display: flex; flex-direction: column; justify-content: flex-end; gap: 2px; min-width: 0; } .bars .seg { border-radius: 2px 2px 0 0; } .bars .seg.ret { background: var(--accent); } .bars .seg.new { background: #2f6f81; } .axis { display: flex; justify-content: space-between; color: var(--muted); font-size: 10.5px; margin-top: 6px; font-family: var(--mono); } .key { display: flex; gap: 14px; font-size: 11.5px; color: var(--muted); margin-top: 10px; } .key i { display: inline-block; width: 9px; height: 9px; border-radius: 2px; margin-right: 5px; vertical-align: -1px; } /* --------------------------------------------------------------- drawer -- */ .drawer { position: fixed; inset: 0; background: rgba(4,8,10,.6); display: flex; justify-content: flex-end; z-index: 30; } .drawer .panel { width: min(480px, 100%); height: 100%; background: var(--surface); border-left: 1px solid var(--line); overflow-y: auto; padding: 20px 22px 40px; } .drawer h3 { font-size: 16px; font-weight: 620; text-transform: none; letter-spacing: -.01em; color: var(--ink); margin-bottom: 2px; } /* Close lives in the sticky header (.who) now. Positioned against the fixed overlay it stayed put while the sheet scrolled underneath it, printing the button on top of whatever happened to be at the top of the viewport. */ /* -- customer record ---------------------------------------------------- */ /* Full-bleed sticky header: a customer record is long enough to scroll, and both the name and the way out have to stay reachable. The negative margins cancel the panel's padding so the background covers the full width. */ .who { position: sticky; top: -20px; z-index: 1; display: flex; gap: 14px; align-items: flex-start; background: var(--surface); margin: -20px -22px 18px; padding: 20px 22px 14px; border-bottom: 1px solid var(--line-soft); } .who .grow { flex: 1; min-width: 0; } .who h3 { margin-bottom: 2px; } .avatar { width: 64px; height: 64px; border-radius: 10px; flex: none; object-fit: cover; background: var(--ground); border: 1px solid var(--line); } .avatar.none { display: grid; place-items: center; color: var(--muted); font-size: 20px; font-weight: 600; letter-spacing: .02em; } .timeline { list-style: none; max-height: 220px; overflow-y: auto; } .timeline li { display: flex; gap: 10px; align-items: baseline; padding: 6px 0; border-bottom: 1px solid var(--line-soft); font-size: 12.5px; } .timeline li:last-child { border-bottom: 0; } .timeline .when { font-family: var(--mono); font-size: 11px; color: var(--muted); flex: none; min-width: 108px; } .timeline .where { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } /* Visually separated from Save: this is the one control in the sheet that cannot be undone, and it must not read as just another button in a row. */ .danger-zone { margin-top: 22px; border-color: #4a2823; } .danger-zone > h3 { color: var(--bad); } .danger-zone .note { margin-bottom: 10px; } .confirm h4 { font-size: 13.5px; font-weight: 620; margin-bottom: 10px; } .confirm .cols { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; margin-bottom: 12px; } @media (max-width: 560px) { .confirm .cols { grid-template-columns: 1fr; } } .confirm .lbl { font-size: 11px; text-transform: uppercase; letter-spacing: .07em; color: var(--muted); margin-bottom: 5px; } .confirm .lbl.bad { color: var(--bad); } .confirm ul { list-style: none; font-size: 12.5px; } .confirm li { padding: 3px 0 3px 12px; position: relative; color: var(--ink); } .confirm li::before { content: '·'; position: absolute; left: 2px; color: var(--muted); } .confirm .row { display: flex; gap: 8px; }