/* ---------------------------------------------------------------------------
   BBI-Inventory — the whole stylesheet.

   One file, plain CSS, no build step. It is meant to be read on a cheap laptop
   in a shop, so: high contrast, big enough targets, numbers that line up in
   columns, and a print layout that produces something you can hand a customer.
   --------------------------------------------------------------------------- */

:root {
    /* Brand. Three purples read off the logo, plus the grey of its tagline.
       Everything else in the file points at these, so the day the artwork
       changes there are three lines to edit and not two hundred. */
    --brand-deep: #5a11c4;
    --brand:      #7c2ae8;
    --brand-lit:  #9b5bf0;
    --brand-wash: #f2ebfe;
    --brand-edge: #ded0fb;

    --paper:      #ffffff;
    --wash:       #f6f5fb;
    --sunk:       #edebf6;
    --line:       #e2dff0;
    --ink:        #1b1726;
    --muted:      #5d5873;
    --faint:      #8b859f;

    --accent:     var(--brand);
    --accent-ink: #ffffff;
    --accent-soft: var(--brand-wash);

    /* Money and stock keep their own meanings. Green is takings, amber is
       owed, red is trouble — none of them borrow the brand colour, because a
       figure that is doing badly must not look like a heading. */
    --in:         #0f7a4a;
    --in-lit:     #17a066;
    --in-soft:    #e2f5ec;
    --out:        #b0541a;
    --out-soft:   #fdeee2;
    --warn:       #92640c;
    --warn-soft:  #fdf3da;
    --bad:        #c02a3c;
    --bad-soft:   #fce9ec;
    --info:       #0e6f9e;
    --info-soft:  #e3f1fa;

    --radius:     7px;
    --radius-lg:  11px;
    --shadow:     0 1px 2px rgba(38, 20, 70, .06), 0 2px 10px rgba(38, 20, 70, .05);
    --shadow-up:  0 2px 4px rgba(38, 20, 70, .07), 0 8px 24px rgba(38, 20, 70, .08);

    --sans: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
    --mono: ui-monospace, "Cascadia Mono", "Segoe UI Mono", Consolas, monospace;
}

@media (prefers-color-scheme: dark) {
    :root {
        /* The deep purple of the logo disappears against a dark screen, so on
           dark the mark is drawn in the light purple instead. Same brand, lit
           from the other side. */
        --brand-deep: #bb92ff;
        --brand:      #a878fb;
        --brand-lit:  #cdaeff;
        --brand-wash: #251b3c;
        --brand-edge: #3b2d60;

        --paper:      #191623;
        --wash:       #100e19;
        --sunk:       #221d31;
        --line:       #322b47;
        --ink:        #ece9f6;
        --muted:      #aaa3c0;
        --faint:      #847d9b;

        --accent:     var(--brand);
        --accent-ink: #1b0f33;
        --accent-soft: var(--brand-wash);

        --in:         #4fc98c;
        --in-lit:     #86e0b2;
        --in-soft:    #12301f;
        --out:        #e8946b;
        --out-soft:   #34211a;
        --warn:       #e0b354;
        --warn-soft:  #302716;
        --bad:        #f2818f;
        --bad-soft:   #351b21;
        --info:       #59b6e0;
        --info-soft:  #132b38;

        --shadow:     0 1px 2px rgba(0, 0, 0, .45);
        --shadow-up:  0 2px 4px rgba(0, 0, 0, .45), 0 8px 24px rgba(0, 0, 0, .35);
    }
}

* { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
    margin: 0;
    font-family: var(--sans);
    font-size: 14.5px;
    line-height: 1.5;
    color: var(--ink);
    background: var(--wash);
}

a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }

h1, h2, h3 { margin: 0; font-weight: 600; line-height: 1.25; text-wrap: balance; }
h1 { font-size: 1.4rem; }
h2 { font-size: 1.05rem; }
h3 { font-size: .95rem; }

:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}

/* --- Shell --------------------------------------------------------------- */

.shell { display: flex; min-height: 100vh; }

.sidebar {
    width: 220px;
    flex: 0 0 220px;
    background: var(--paper);
    border-right: 1px solid var(--line);
    display: flex;
    flex-direction: column;
    position: sticky;
    top: 0;
    height: 100vh;
    overflow-y: auto;
}

.brand {
    display: flex;
    align-items: center;
    gap: 11px;
    padding: 15px 16px 14px;
    border-bottom: 1px solid var(--line);
    background: linear-gradient(135deg, var(--brand-wash), transparent 72%);
}
.brand .who-we-are { min-width: 0; }
.brand strong { display: block; font-size: .98rem; letter-spacing: -.01em; }
.brand span { display: block; font-size: .76rem; color: var(--faint); }

/* The drawn mark and a real logo file share one slot, so either can sit
   there without the sidebar changing shape around it. */
.mark     { width: 36px; height: 36px; flex: 0 0 36px; display: block; }
.mark-img { width: 38px; height: 38px; flex: 0 0 38px; object-fit: contain; display: block; }

.nav { padding: 10px 8px; flex: 1; }
.nav-group {
    padding: 14px 10px 4px;
    font-size: .68rem;
    letter-spacing: .09em;
    text-transform: uppercase;
    color: var(--faint);
}
.nav a {
    display: block;
    padding: 7px 10px;
    border-radius: var(--radius);
    color: var(--ink);
    font-size: .9rem;
}
.nav a:hover { background: var(--sunk); text-decoration: none; }
.nav a { position: relative; transition: background .12s ease; }
.nav a.on {
    background: var(--brand-wash);
    color: var(--brand-deep);
    font-weight: 600;
}
.nav a.on::before {
    content: "";
    position: absolute;
    left: 0;
    top: 6px;
    bottom: 6px;
    width: 3px;
    border-radius: 0 3px 3px 0;
    background: linear-gradient(180deg, var(--brand-lit), var(--brand-deep));
}

.main { flex: 1; min-width: 0; display: flex; flex-direction: column; }

.topbar {
    background: var(--paper);
    border-bottom: 1px solid var(--line);
    padding: 12px 22px;
    display: flex;
    align-items: center;
    gap: 14px;
    /* Sticky, because on a long list of stock the way back out should not be
       fourteen rows of scrolling away. */
    position: sticky;
    top: 0;
    z-index: 5;
}
.topbar::after {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    bottom: -1px;
    height: 2px;
    background: linear-gradient(90deg, var(--brand-deep), var(--brand-lit) 45%, transparent);
}
.topbar h1 { flex: 1; min-width: 0; }
.who { font-size: .82rem; color: var(--muted); text-align: right; }
.who strong { display: block; color: var(--ink); }

.page {
    padding: 20px 22px 60px;
    max-width: 1240px;
    width: 100%;
    background:
        radial-gradient(900px 380px at 100% -80px, var(--brand-wash), transparent 65%);
}

/* --- Messages ------------------------------------------------------------ */

.flash { margin: 0 0 14px; padding: 10px 14px; border-radius: var(--radius); border: 1px solid; font-size: .9rem; }
.flash-ok    { background: var(--in-soft);   border-color: var(--in);   color: var(--in); }
.flash-warn  { background: var(--warn-soft); border-color: var(--warn); color: var(--warn); }
.flash-error { background: var(--bad-soft);  border-color: var(--bad);  color: var(--bad); }

/* --- Cards --------------------------------------------------------------- */

.card {
    background: var(--paper);
    border: 1px solid var(--line);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow);
    margin-bottom: 16px;
}
.card-head {
    padding: 12px 16px;
    border-bottom: 1px solid var(--line);
    display: flex;
    align-items: center;
    gap: 12px;
    flex-wrap: wrap;
}
.card-head h2 {
    flex: 1;
    min-width: 0;
    display: flex;
    align-items: center;
    gap: 9px;
}
/* A short brand stroke against every heading. It is the one place the purple
   appears on an otherwise plain page, which is enough to tie the screens
   together without colouring anything that carries a number. */
.card-head h2::before {
    content: "";
    flex: 0 0 4px;
    width: 4px;
    height: 15px;
    border-radius: 2px;
    background: linear-gradient(180deg, var(--brand-lit), var(--brand-deep));
}
.card-body { padding: 16px; }

/* A card that folds away. The summary of goods sold sits above the sales list
   and is worth a glance every time the screen is opened, but it must never
   push the list it describes off the bottom of the screen — so the whole head
   is the handle, and the figures stay readable while it is shut. */
.card > details > summary { list-style: none; cursor: pointer; }
.card > details > summary::-webkit-details-marker { display: none; }
.card > details > summary .card-head { border-bottom: 0; }
.card > details[open] > summary .card-head { border-bottom: 1px solid var(--line); }
.card > details > summary:focus-visible .card-head { outline: 2px solid var(--brand-lit); outline-offset: -2px; }
.fold {
    flex: 0 0 auto;
    color: var(--faint);
    font-size: .95rem;
    line-height: 1;
    transition: transform .15s ease;
}
.card > details[open] > summary .fold { transform: rotate(180deg); }
@media (prefers-reduced-motion: reduce) { .fold { transition: none; } }

.card-foot {
    padding: 12px 16px;
    border-top: 1px solid var(--line);
    background: linear-gradient(180deg, var(--wash), var(--sunk));
    display: flex;
    gap: 10px;
    align-items: center;
    flex-wrap: wrap;
    border-radius: 0 0 var(--radius-lg) var(--radius-lg);
}

/* --- Stat tiles ---------------------------------------------------------- */

.stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(212px, 1fr)); gap: 13px; margin-bottom: 16px; }

/* Each tile carries one tone, set by a t- class. The tone drives the rail
   along the top, the icon chip and nothing else, so five tiles side by side
   are told apart at a glance while the figures themselves stay black. */
.stat {
    --tone:      var(--brand);
    --tone-2:    var(--brand-lit);
    --tone-soft: var(--brand-wash);

    position: relative;
    overflow: hidden;
    background: var(--paper);
    border: 1px solid var(--line);
    border-radius: var(--radius-lg);
    padding: 14px 15px 13px;
    box-shadow: var(--shadow);
}
.stat::before {
    content: "";
    position: absolute;
    inset: 0 0 auto 0;
    height: 3px;
    background: linear-gradient(90deg, var(--tone), var(--tone-2));
}
.stat .label {
    font-size: .72rem;
    text-transform: uppercase;
    letter-spacing: .08em;
    font-weight: 600;
    color: var(--faint);
}
.stat .value {
    font-size: 1.42rem;
    font-weight: 650;
    font-variant-numeric: tabular-nums;
    letter-spacing: -.015em;
    margin-top: 3px;
}
.stat .note  { font-size: .78rem; color: var(--muted); margin-top: 1px; }
.stat.good .value { color: var(--in); }
.stat.bad  .value { color: var(--bad); }

/* Label and icon sit on one line. The icon has no box around it and no
   colour of its own: the tile already says what kind of figure it is,
   through the coloured rule along its top edge, and a second coloured
   shape next to the number was one too many. It is a quiet marker in
   the corner, drawn in the same grey as the label above the figure. */
.stat .top { display: flex; align-items: center; gap: 8px; margin-bottom: 1px; }
.stat .top .label { flex: 1; min-width: 0; }
.stat .glyph {
    flex: 0 0 auto;
    display: grid;
    place-items: center;
    color: var(--faint);
}
.stat .glyph svg { width: 16px; height: 16px; display: block; }

.stat.t-brand { --tone: var(--brand);      --tone-2: var(--brand-lit); --tone-soft: var(--brand-wash); }
.stat.t-in    { --tone: var(--in);         --tone-2: #34a56f;          --tone-soft: var(--in-soft); }
.stat.t-info  { --tone: var(--info);       --tone-2: #3fa3cd;          --tone-soft: var(--info-soft); }
.stat.t-warn  { --tone: var(--warn);       --tone-2: #cb9622;          --tone-soft: var(--warn-soft); }
.stat.t-out   { --tone: var(--out);        --tone-2: #d8834a;          --tone-soft: var(--out-soft); }
.stat.t-deep  { --tone: var(--brand-deep); --tone-2: var(--brand);     --tone-soft: var(--brand-wash); }

/* A profit tile that has gone the wrong way changes its tone as well as its
   figure, so a bad month is not a green tile with a red number in it. */
.stat.bad     { --tone: var(--bad);        --tone-2: #de5f70;          --tone-soft: var(--bad-soft); }

/* One tile made of colour rather than outlined in it, for the figure that
   matters most on the screen. */
.stat.filled {
    background: linear-gradient(140deg, var(--brand-deep), var(--brand) 62%, var(--brand-lit));
    border-color: transparent;
    color: #fff;
    box-shadow: var(--shadow-up);
}
.stat.filled::before { display: none; }
.stat.filled .label,
.stat.filled .note  { color: rgba(255, 255, 255, .78); }
.stat.filled .value { color: #fff; }
.stat.filled .note a { color: #fff; text-decoration: underline; }
.stat.filled .glyph { color: rgba(255, 255, 255, .82); }

/* --- Document facts ------------------------------------------------------ */

.facts { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: 16px; }
.facts .label { font-size: .72rem; text-transform: uppercase; letter-spacing: .06em; color: var(--faint); margin-bottom: 2px; }
/* --- Tables -------------------------------------------------------------- */

.scroll { overflow-x: auto; }

table { width: 100%; border-collapse: collapse; font-size: .88rem; }
th, td { padding: 8px 12px; text-align: left; border-bottom: 1px solid var(--line); vertical-align: top; }
th {
    font-size: .72rem;
    text-transform: uppercase;
    letter-spacing: .06em;
    color: var(--faint);
    font-weight: 600;
    white-space: nowrap;
    background: var(--wash);
}
tbody tr:hover { background: var(--wash); }
tbody tr:last-child td { border-bottom: 0; }
td.num, th.num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
td.mono { font-family: var(--mono); font-size: .84rem; }
tfoot td { font-weight: 600; background: var(--wash); border-top: 2px solid var(--line); }

.empty { padding: 40px 16px; text-align: center; color: var(--faint); }

/* --- Forms --------------------------------------------------------------- */

.grid { display: grid; gap: 14px; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); }
.grid.two { grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); }

.field { display: flex; flex-direction: column; gap: 5px; }
.field label { font-size: .8rem; font-weight: 600; color: var(--muted); }
.field .hint { font-size: .76rem; color: var(--faint); }
.field.wide { grid-column: 1 / -1; }

input, select, textarea, button { font: inherit; color: inherit; }

input[type=text], input[type=email], input[type=password], input[type=date],
input[type=number], input[type=search], select, textarea {
    width: 100%;
    padding: 7px 10px;
    border: 1px solid var(--line);
    border-radius: var(--radius);
    background: var(--paper);
    color: var(--ink);
}
input:focus, select:focus, textarea:focus { border-color: var(--accent); outline: none; box-shadow: 0 0 0 3px var(--accent-soft); }
input[readonly] { background: var(--sunk); color: var(--muted); }
textarea { min-height: 68px; resize: vertical; }
input.num { text-align: right; font-variant-numeric: tabular-nums; }

.check { display: flex; align-items: center; gap: 8px; font-size: .88rem; }
.check input { width: auto; }

/* --- Buttons ------------------------------------------------------------- */

.btn {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 7px 14px;
    border: 1px solid var(--line);
    border-radius: var(--radius);
    background: var(--paper);
    color: var(--ink);
    cursor: pointer;
    font-size: .88rem;
    font-weight: 500;
    white-space: nowrap;
}
.btn:hover { background: var(--sunk); text-decoration: none; }
.btn { transition: background .12s ease, box-shadow .12s ease; }
.btn-main {
    background: linear-gradient(180deg, var(--brand-lit), var(--brand));
    border-color: var(--brand-deep);
    color: #fff;
    box-shadow: 0 1px 2px rgba(90, 17, 196, .28);
}
.btn-main:hover { filter: brightness(1.07); box-shadow: 0 2px 8px rgba(90, 17, 196, .3); }
.btn-bad { color: var(--bad); border-color: var(--bad); background: transparent; }
.btn-bad:hover { background: var(--bad-soft); }
.btn-small { padding: 4px 9px; font-size: .8rem; }
.btn-link { border: 0; background: none; color: var(--accent); padding: 0; }

.actions { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }
.actions .spacer { flex: 1; }

/* The clock at the end of the dashboard's action bar. It sits among buttons
   but is not one, so it is given the surface of a card rather than the face of
   a control — it is the one thing on that row you read instead of press. The
   digits are tabular so the bar does not twitch every second. */
.clock {
    display: flex;
    align-items: baseline;
    gap: 8px;
    padding: 6px 12px;
    border: 1px solid var(--line);
    border-radius: var(--radius-lg);
    background: var(--paper);
    box-shadow: var(--shadow);
    white-space: nowrap;
}

.clock-time {
    font-size: 1rem;
    font-weight: 650;
    font-variant-numeric: tabular-nums;
    color: var(--ink);
}

.clock-date { font-size: .76rem; color: var(--faint); }

/* --- Filters ------------------------------------------------------------- */

.filters {
    display: flex;
    gap: 10px;
    flex-wrap: wrap;
    align-items: flex-end;
}
.filters .field { min-width: 130px; }
.filters .field.grow { flex: 1; min-width: 200px; }

/* --- Line items ---------------------------------------------------------- */

.lines table { font-size: .88rem; }
.lines td { padding: 6px 8px; vertical-align: middle; }
.lines input, .lines select { padding: 6px 8px; }
.lines .line-total { font-variant-numeric: tabular-nums; text-align: right; white-space: nowrap; }
.lines .drop { width: 34px; }

.totals { display: flex; justify-content: flex-end; }
.totals table { width: auto; min-width: 280px; }
.totals td { border: 0; padding: 4px 10px; }
.totals td:last-child { text-align: right; font-variant-numeric: tabular-nums; min-width: 120px; }
.totals tr.grand td { font-weight: 700; font-size: 1.05rem; border-top: 1px solid var(--line); padding-top: 8px; }

/* --- Choice chips -------------------------------------------------------- */

/* What has been used before, under a box that still takes anything typed. */
.chips {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
    margin-top: 6px;
}

.chip {
    font: inherit;
    font-size: .74rem;
    line-height: 1;
    padding: 4px 8px;
    border: 1px solid var(--line);
    border-radius: 999px;
    background: var(--paper);
    color: var(--muted);
    cursor: pointer;
}

.chip:hover { border-color: var(--accent); color: var(--accent); }

.chip-on {
    background: var(--accent-soft);
    border-color: var(--accent);
    color: var(--accent);
    font-weight: 600;
}

.chip:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }

/* --- Pictures ------------------------------------------------------------ */

/* A thumbnail column in a list. Fixed width so the columns beside it do not
   shuffle sideways as pictures load, and reserved even on rows without one. */
th.shot, td.shot { width: 46px; padding-right: 0; }

td.shot img {
    display: block;
    width: 38px;
    height: 38px;
    object-fit: cover;
    border-radius: 4px;
    border: 1px solid var(--line);
    background: var(--sunk);
}

.lines td.shot { width: 40px; }
.lines td.shot img { width: 32px; height: 32px; }
.lines td.shot img[hidden] { display: none; }

/* The picture on the product page. Held to a readable size rather than
   stretched across the card, because most of these are phone photos. */
/* Small on purpose. The picture is here to confirm which item this is,
   not to be looked at — the numbers under it are what the page is for.
   Clicking opens the full size for anyone who does want a proper look. */
.photo-full { display: flex; justify-content: flex-start; padding: 12px 16px; }

.photo-full a { display: block; line-height: 0; }

.photo-full img {
    max-width: 100%;
    width: auto;
    max-height: 150px;
    border-radius: var(--radius);
    border: 1px solid var(--line);
}

/* Picking a picture on the product form. */
.photo-field {
    display: flex;
    gap: 16px;
    align-items: flex-start;
    margin-top: 20px;
    padding-top: 20px;
    border-top: 1px solid var(--line);
}

.photo-shot {
    flex: 0 0 auto;
    width: 116px;
    height: 116px;
    display: grid;
    place-items: center;
    border: 1px dashed var(--line);
    border-radius: var(--radius);
    background: var(--sunk);
    overflow: hidden;
}

.photo-shot img { width: 100%; height: 100%; object-fit: cover; }
.photo-shot img[hidden] { display: none; }

.photo-none { font-size: .78rem; color: var(--faint); }
.photo-none[hidden] { display: none; }

.photo-controls { flex: 1 1 auto; min-width: 0; }
.photo-controls label { display: block; font-size: .82rem; font-weight: 600; margin-bottom: 6px; }
.photo-controls input[type="file"] { max-width: 100%; font-size: .85rem; }
.photo-controls .hint { display: block; margin-top: 6px; max-width: 62ch; }
.photo-controls label.check { font-weight: 400; }

@media (max-width: 640px) {
    .photo-field { flex-direction: column; }
}

/* --- Badges -------------------------------------------------------------- */

.tag {
    display: inline-block;
    padding: 1px 8px;
    border-radius: 999px;
    font-size: .74rem;
    font-weight: 600;
    border: 1px solid transparent;
    white-space: nowrap;
}
.tag-in   { background: var(--in-soft);   color: var(--in); }
.tag-out  { background: var(--out-soft);  color: var(--out); }
.tag-warn { background: var(--warn-soft); color: var(--warn); }
.tag-bad  { background: var(--bad-soft);  color: var(--bad); }
.tag-off  { background: var(--sunk);      color: var(--faint); }
.tag-brand{ background: var(--brand-wash); color: var(--brand-deep); }

.pos { color: var(--in); }
.neg { color: var(--bad); }
.dim { color: var(--faint); }
.small { font-size: .8rem; }

/* --- Sparkline ----------------------------------------------------------- */

/* --- The fourteen day chart ---------------------------------------------
   Bars for what was sold, a thinner bar in front for what was kept. Four
   faint rules across the back so a bar can be read as an amount instead of
   only compared with its neighbours.
   ------------------------------------------------------------------------ */

.chart-top {
    display: flex;
    align-items: baseline;
    gap: 14px;
    flex-wrap: wrap;
    margin-bottom: 10px;
}
.chart-top .peak-note { flex: 1; min-width: 0; font-size: .78rem; color: var(--faint); }

.legend { display: flex; gap: 14px; font-size: .76rem; color: var(--muted); }
.legend span { display: inline-flex; align-items: center; gap: 6px; }
.legend i {
    width: 11px;
    height: 11px;
    border-radius: 3px;
    display: block;
}
.legend .sold  { background: linear-gradient(180deg, var(--brand-lit), var(--brand)); }
.legend .kept  { background: var(--in); }

.plot {
    display: flex;
    align-items: flex-end;
    gap: 5px;
    height: 148px;
    padding-top: 4px;
    border-bottom: 1px solid var(--line);
    background-image: repeating-linear-gradient(
        to top,
        var(--line) 0 1px,
        transparent 1px 25%
    );
    background-size: 100% 100%;
}
.plot .col {
    flex: 1;
    min-width: 0;
    height: 100%;
    display: flex;
    align-items: flex-end;
    justify-content: center;
    position: relative;
}
.plot .bar {
    width: 100%;
    max-width: 38px;
    min-height: 3px;
    border-radius: 5px 5px 0 0;
    background: linear-gradient(180deg, var(--brand-lit), var(--brand));
    position: relative;
    transition: filter .12s ease;
}
.plot .col:hover .bar { filter: brightness(1.1); }
.plot .col.peak .bar { background: linear-gradient(180deg, var(--brand), var(--brand-deep)); }
.plot .bar.empty { background: var(--sunk); }

/* What was kept out of what was sold, drawn inside the same bar. */
.plot .kept {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    border-radius: 0 0 0 0;
    background: var(--in);
    opacity: .85;
}
.plot .bar.short .kept { border-radius: 4px 4px 0 0; }
.plot .kept.loss { background: var(--bad); }

.plot-days { display: flex; gap: 5px; margin-top: 7px; }
.plot-days span {
    flex: 1;
    min-width: 0;
    text-align: center;
    font-size: .68rem;
    color: var(--faint);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
    overflow: hidden;
}
.plot-days span.peak { color: var(--brand-deep); font-weight: 600; }

@media (max-width: 700px) {
    .plot-days span { font-size: .6rem; }
}

/* --- Login --------------------------------------------------------------- */

.login-wrap {
    min-height: 100vh;
    display: grid;
    place-items: center;
    padding: 24px;
    background:
        radial-gradient(1100px 520px at 12% -12%, var(--brand-wash), transparent 62%),
        radial-gradient(760px 420px at 108% 112%, var(--brand-wash), transparent 60%),
        var(--wash);
}
.login-mark { display: flex; justify-content: center; margin-bottom: 14px; }
.login-mark .mark     { width: 62px; height: 62px; flex: none; }
.login-mark .mark-img { width: 66px; height: 66px; flex: none; }
.login {
    width: 100%;
    max-width: 380px;
    background: var(--paper);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    box-shadow: var(--shadow);
    padding: 26px;
}
.login h1 { margin-bottom: 4px; }
.login p.sub { margin: 0 0 20px; color: var(--muted); font-size: .88rem; }

/* --- Printable bill ------------------------------------------------------ */

.sheet { max-width: 860px; margin: 24px auto; padding: 0 16px; }
.bill {
    background: var(--paper);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    padding: 28px;
    box-shadow: var(--shadow);
}
.bill h1 { font-size: 1.35rem; margin: 0 0 2px; }
.bill-head { display: flex; justify-content: space-between; gap: 24px; align-items: flex-start; }
.bill-no { text-align: right; }
.bill-no .label,
.bill-to .label { font-size: .72rem; text-transform: uppercase; letter-spacing: .06em; color: var(--faint); }
.bill-to { margin: 24px 0 16px; }
.bill table { margin-top: 8px; }
.bill tfoot td { border-bottom: 0; }
.bill-foot { display: flex; justify-content: space-between; gap: 48px; margin-top: 56px; }
.bill-foot > div { flex: 1; }
.bill-foot .rule { border-top: 1px solid var(--line); margin-bottom: 4px; }

/* --- The sign-out warning -------------------------------------------------
   Shown for the last minute before an untouched screen signs itself out.
   Bottom centre and nothing else is up there, so it never lands on top of the
   row somebody is typing into — a warning that hides the work is worse than no
   warning. Amber, not red: nothing has gone wrong yet. */
.idle-warn {
    position: fixed;
    left: 50%;
    bottom: 22px;
    transform: translateX(-50%);
    z-index: 50;
    display: flex;
    align-items: center;
    gap: 12px;
    max-width: calc(100vw - 32px);
    padding: 11px 15px;
    border: 1px solid var(--warn);
    border-radius: var(--radius-lg);
    background: var(--warn-soft);
    color: var(--warn);
    font-size: .88rem;
    box-shadow: var(--shadow-up);
}
.idle-warn .btn { background: var(--paper); white-space: nowrap; }

@media print {
    .sheet { margin: 0; padding: 0; max-width: none; }
    .bill { border: 0; box-shadow: none; padding: 0; }
    .bill-foot .rule { border-top: 1px solid #000; }
}
/* --- Print --------------------------------------------------------------- */

.print-only { display: none; }

@media print {
    .sidebar, .topbar, .no-print, .card-foot { display: none !important; }
    th.shot, td.shot, .photo-field, .photo-full, .chips { display: none !important; }
    .stat::before, .card-head h2::before, .topbar::after, .stat .glyph,
    .owed-card::before { display: none !important; }
    .owed-card tr.stale td { background: none; }
    .owed-sum { color: #000; }
    .stat.filled { background: none !important; color: #000 !important; border: 1px solid #999 !important; }
    .stat.filled .label, .stat.filled .note, .stat.filled .value { color: #000 !important; }
    .print-only { display: block; }
    body { background: #fff; color: #000; font-size: 12px; }
    .page { padding: 0; max-width: none; }
    .card { border: 0; box-shadow: none; margin: 0; }
    .card-head { border-bottom: 1px solid #999; padding-left: 0; padding-right: 0; }
    .card-body { padding: 10px 0; }
    th { background: none; color: #000; border-bottom: 1px solid #000; }
    td, th { padding: 5px 8px; }
    a { color: #000; text-decoration: none; }
}

/* --- Where the money went ------------------------------------------------ */

/* A row of bars comparing categories. Deliberately not a pie: people read
   length far better than angle, and a pie with fifteen slices is unreadable
   at any size. */
.bars { display: flex; flex-direction: column; gap: 9px; }

.bar-row {
    display: grid;
    grid-template-columns: minmax(120px, 1.1fr) minmax(80px, 3fr) minmax(110px, auto);
    align-items: center;
    gap: 12px;
}

.bar-name { font-size: .85rem; display: flex; align-items: baseline; gap: 6px; min-width: 0; }
.bar-name a { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.bar-track {
    height: 9px;
    border-radius: 5px;
    background: var(--sunk);
    overflow: hidden;
}

.bar-track span {
    display: block;
    height: 100%;
    border-radius: 5px;
    background: linear-gradient(90deg, var(--brand), var(--brand-lit));
}

/* The biggest bar carries the strongest colour, which happens naturally
   because it is the widest — no extra class needed. */
.bar-value {
    text-align: right;
    font-size: .85rem;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.bar-value .small { margin-left: 5px; }

/* --- The profit ladder --------------------------------------------------- */

/* Sales down to what was kept, one subtraction per row. The point of it is
   that the two profit figures are visibly different things arrived at by
   visibly different arithmetic. */
.ladder td, .ladder th { border-bottom: 0; padding-top: 6px; padding-bottom: 6px; }
.ladder th { background: none; text-transform: none; letter-spacing: 0; font-size: .88rem; color: var(--ink); }
.ladder th.small, .ladder td.small { font-size: .78rem; }
.ladder tbody tr:hover { background: none; }
.ladder td.indent, .ladder th.indent { padding-left: 30px; font-size: .84rem; }

.ladder tr.rule td, .ladder tr.rule th {
    border-top: 1px solid var(--line);
    padding-top: 9px;
}

.ladder tr.total td, .ladder tr.total th {
    border-top: 2px solid var(--brand);
    font-weight: 700;
    font-size: .95rem;
}

.ladder tr.total th.num { font-size: 1.05rem; }

/* A tfoot built from th rather than td still needs to read as a total row. */
tfoot th { font-weight: 600; background: var(--wash); border-top: 2px solid var(--line); color: var(--ink); }

@media (max-width: 620px) {
    .bar-row { grid-template-columns: 1fr auto; }
    .bar-track { grid-column: 1 / -1; }
}
/* --- The dashboard, which has to fit one screen -------------------------- */

/* A quiet heading over a row of tiles. It is not a card head and must not
   look like one — the point is to group ten tiles into two readable halves
   without spending any vertical room on doing it. */
.row-label {
    font-size: .7rem;
    text-transform: uppercase;
    letter-spacing: .1em;
    font-weight: 650;
    color: var(--faint);
    margin: 2px 0 8px 2px;
}
.row-label + .stats { margin-bottom: 14px; }

/* Tiles on the dashboard run tighter than tiles on a report, because there
   are ten of them and the whole screen has to land above the fold. */
.stats.tight { gap: 11px; margin-bottom: 14px; }
.stats.tight .stat { padding: 11px 13px 10px; }
.stats.tight .stat .value { font-size: 1.3rem; margin-top: 2px; }
.stats.tight .stat .note { font-size: .74rem; }
.stats.tight .stat .glyph svg { width: 15px; height: 15px; }

/* One line that needs somebody to go and do something. Everything else on
   the dashboard is a figure to read; this is the only thing that asks. */
.strip {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 9px 14px;
    margin-bottom: 14px;
    border: 1px solid var(--line);
    border-radius: var(--radius-lg);
    background: var(--paper);
    box-shadow: var(--shadow);
    font-size: .85rem;
}
.strip-text { flex: 1; min-width: 0; }
.strip-icon { display: grid; place-items: center; flex: 0 0 18px; }
.strip-icon svg { width: 18px; height: 18px; display: block; }
.strip a { white-space: nowrap; font-weight: 600; }

.strip-warn {
    background: var(--warn-soft);
    border-color: var(--warn);
    border-color: color-mix(in srgb, var(--warn) 32%, transparent);
}
.strip-warn .strip-icon { color: var(--warn); }

/* The actions row above it all, pulled in so the two do not drift apart. */
/* The action bar is a row of controls; everything under it is information.
   They need a gap between them, or the warning reads as one more button. */
.actions + .strip, .actions + .row-label { margin-top: 14px; }

/* The two pictures under the tiles.

   They are ranked bars and not anything round, because the question they
   answer is "which of these is biggest", and a bar answers that at a glance
   while a slice of a circle has to be estimated. Everything here is sized
   down from the same components on the report pages: the dashboard has one
   screen to work with and these two cards share the bottom of it. */
.panels { margin-bottom: 0; }
.panels .card { margin-bottom: 0; display: flex; flex-direction: column; }
.panels .card-head { padding: 10px 14px; }
.panels .card-head h2 { font-size: .97rem; }
.panels .card-body { padding: 12px 14px; flex: 1; }
.panels .card-foot { padding: 8px 14px; font-size: .82rem; }
.panels .empty { padding: 24px 12px; }

.panels .bars { gap: 8px; }
.panels .bar-row {
    grid-template-columns: minmax(0, 1.4fr) minmax(46px, 1fr) minmax(76px, auto);
    gap: 10px;
}
.panels .bar-name { font-size: .82rem; flex-wrap: wrap; gap: 1px 6px; }
.panels .bar-name .small { font-size: .71rem; }
.panels .bar-value { font-size: .82rem; font-weight: 600; }

/* A label with nothing to link to still has to stay on one line. */
.ellipsis { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }

/* Two fills, two meanings. Purple is what the business owns, which is the
   brand colour it wears on every other screen; green is money taken, which
   is already what green means on the tiles above. Neither fill carries any
   text, and every bar has its figure written beside it in ordinary ink, so
   the colour decorates a number rather than being the only way to read it. */
.bars-sold .bar-track span { background: linear-gradient(90deg, var(--in), var(--in-lit)); }

@media (max-width: 620px) {
    /* The same collapse the report bars get. It has to be restated because
       .panels raises the specificity past the rule that does it there. */
    .panels .bar-row { grid-template-columns: 1fr auto; }
}
/* The list of what just sold, under the two pictures.

   Tighter than the same table on the sales screen: this one is being glanced
   at on the way past, not read. The picture column stays, because it is the
   fastest way to confirm which of two similarly named routers went out. */
.recent { margin-top: 14px; margin-bottom: 0; }
.recent table { font-size: .86rem; }
.recent td, .recent th { padding-top: 7px; padding-bottom: 7px; }
.recent td.shot img { width: 30px; height: 30px; }
.recent th.shot, .recent td.shot { width: 38px; }
.recent .small { font-size: .73rem; }

/* Where a sale stands. Three states, each with its word written next to it —
   the colour is a second reading of the same fact, never the only one. */
.tag-paid { background: var(--in-soft);   color: var(--in); }
.tag-part { background: var(--warn-soft); color: var(--warn); }
.tag-owed { background: var(--bad-soft);  color: var(--bad); }

/* The payment box on the sale form. Set apart from the fields above it with a
   rule and its own ground, because it is a different question from what was
   sold — and the one most likely to be got wrong in a hurry. */
.pay {
    margin-top: 16px;
    padding: 14px;
    border: 1px solid var(--line);
    border-radius: var(--radius-lg);
    background: var(--wash);
}

.pay-top { display: flex; align-items: baseline; gap: 8px; margin-bottom: 10px; }

.pay-states { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 12px; }

.pay-state {
    display: flex;
    align-items: center;
    gap: 7px;
    padding: 7px 12px;
    border: 1px solid var(--line);
    border-radius: var(--radius-lg);
    background: var(--paper);
    cursor: pointer;
    font-size: .88rem;
}

.pay-state:hover { border-color: var(--brand); }
.pay-state input { margin: 0; }
.pay-state:has(input:checked) {
    border-color: var(--brand);
    background: var(--brand-wash);
    color: var(--brand-deep);
    font-weight: 600;
}

.pay-detail { margin: 0; }
.pay-detail .field { margin-bottom: 0; }
.pay-detail[hidden], .pay-detail .field[hidden] { display: none; }

/* Somebody new, typed straight onto a sale instead of being added first. Given
   the same ground as the payment box below it, because it is the same kind of
   thing: a second question that only sometimes needs asking. */
.new-customer {
    margin-top: 12px;
    padding: 12px 14px;
    border: 1px solid var(--line);
    border-radius: var(--radius-lg);
    background: var(--wash);
}

.new-customer[hidden] { display: none; }
.new-customer .field { margin-bottom: 0; }

/* What is still owed on a document, under its total. */
.totals tr.owing td { color: var(--bad); font-weight: 600; }

/* The unpaid sales, high on the dashboard.
   Marked with the same 3px rule the figure tiles wear, in the colour used for
   anything that wants attention — enough to be found straight away, not so much
   that a dashboard with one late invoice looks like an emergency. The colour is
   never the only signal: the card is titled, the ages are written out, and rows
   past a month say so in words as well. */
.owed-card { position: relative; overflow: hidden; margin-bottom: 18px; }
.owed-card::before {
    content: "";
    position: absolute;
    inset: 0 0 auto 0;
    height: 3px;
    background: var(--bad);
}
.owed-card table { font-size: .88rem; }
.owed-card td, .owed-card th { padding-top: 8px; padding-bottom: 8px; }

/* The total, sitting at the end of the head where the eye lands last. */
.owed-sum {
    font-weight: 700;
    font-size: 1.02rem;
    color: var(--bad);
    font-variant-numeric: tabular-nums;
}

.owed-card .owed-figure { font-weight: 600; }

/* A month or more. Not shouted, just weighted. */
.owed-card tr.stale td { background: var(--bad-soft); }
.owed-card tr.stale .owed-figure { color: var(--bad); }

/* --- Narrow screens ------------------------------------------------------ */

@media (max-width: 860px) {
    .shell { flex-direction: column; }
    .sidebar {
        width: auto;
        flex: none;
        height: auto;
        position: static;
        border-right: 0;
        border-bottom: 1px solid var(--line);
    }
    .nav { display: flex; flex-wrap: wrap; gap: 4px; }
    .nav-group { display: none; }
    .page { padding: 14px; }

    /* On a phone the dashboard scrolls whatever we do, so stop squeezing. */
    .stats.tight .stat { padding: 13px 14px 12px; }
    .strip { flex-wrap: wrap; }
}

/* --- Print: the money screens -------------------------------------------- */

/* Appended after the components above so these win on order as well as on
   specificity. A printed report goes in a file or to an accountant, so the
   colour furniture comes off and the arithmetic stays. */
@media print {
    .bar-track { border: 1px solid #999; background: none; height: 7px; }
    .bar-track span { background: #555 !important; }
    .ladder th { color: #000; background: none; }
    .ladder tr.rule td, .ladder tr.rule th { border-top: 1px solid #999; }
    .ladder tr.total td, .ladder tr.total th { border-top: 2px solid #000; }
    .ladder td.indent, .ladder th.indent { padding-left: 24px; }
    tfoot th { background: none; color: #000; border-top: 2px solid #000; }
}
