/*
 * Sidobox shared portal styles (#17) — panels, tables and the analytics
 * component (period selector, KPI tiles, combo chart, heatmap, readouts,
 * sortable products table), consumed by BOTH the host portal and the admin
 * device pages.
 *
 * Theming: every colour/font/shadow goes through a --pl-* custom property.
 * The defaults below ARE the host portal's palette (extracted verbatim), so
 * the host page needs no overrides — pixel parity by construction. The admin
 * page overrides the tokens in its own stylesheet (dark panels, blue accent,
 * its font stack). Bump the ?v= query on the <link> tags when this changes.
 */
:root {
  --pl-panel: #FFFFFF;                    /* card / chip background            */
  --pl-panel-2: #FBF6EB;                  /* secondary surface (hover, inputs) */
  --pl-line: rgba(26, 42, 47, 0.12);      /* hairline borders                  */
  --pl-text: #1A2A2F;                     /* primary text                      */
  --pl-text-soft: #3A4F56;                /* secondary text                    */
  --pl-muted: #7A8B8F;                    /* captions / table headers          */
  --pl-accent: #0F4C5C;                   /* items line, focus, sort arrows    */
  --pl-accent-soft: #DDEDF0;              /* chart area fill                   */
  --pl-bar: #F2C24A;                      /* £ bars + money axis               */
  --pl-bar-hover: #E6573A;                /* bar hover                         */
  --pl-line-2: #E6573A;                   /* purchases line                    */
  --pl-line-3: #7B61C9;                   /* payers line                       */
  --pl-chip-active-bg: #1A2A2F;           /* active chip / primary button bg   */
  --pl-chip-active-fg: #FFD66B;           /* active chip / primary button fg   */
  --pl-pill-bg: #FCE4DC;                  /* refund pill                       */
  --pl-pill-fg: #C8462C;
  --pl-heat-rgb: 15, 76, 92;              /* heatmap tint (R,G,B)              */
  --pl-shadow: 0 1px 0 rgba(255,255,255,0.6) inset, 0 8px 22px -10px rgba(26,42,47,0.16);
  --pl-font-body: 'Outfit', sans-serif;
  --pl-font-mono: 'JetBrains Mono', monospace;
  --pl-font-display: 'Unbounded', sans-serif;
  --pl-ease: cubic-bezier(.2, .9, .25, 1);
}

/* ── Shared panels / tables / bits ── */
.panel{background:var(--pl-panel);border:1px solid var(--pl-line);border-radius:18px;overflow:hidden;box-shadow:var(--pl-shadow)}
table{width:100%;border-collapse:collapse;font-size:14.5px}
th,td{text-align:left;padding:13px 18px;border-bottom:1px solid var(--pl-line)}
th{font-family:var(--pl-font-mono);font-weight:700;font-size:10px;letter-spacing:.16em;text-transform:uppercase;color:var(--pl-muted)}
tr:last-child td{border-bottom:0}
td.num,th.num{text-align:right;font-variant-numeric:tabular-nums}
td.amount{font-weight:700}
.muted{color:var(--pl-muted)}
.empty{padding:22px 18px;color:var(--pl-muted);font-size:14px}

/* ── Wide tables on a narrow screen (maimava#47) ──────────────────────────────
   These tables are designed WIDE, not tall. With `width:100%` inside a panel
   that clips (`overflow:hidden`) a phone got the worst of both: the browser
   squeezed columns until every cell wrapped (rows 82-145px), and when squeezing
   bottomed out the table overflowed the panel and the remainder was CLIPPED —
   silently unreachable, e.g. Warehouse's Cost / If sold / Adjust and the whole
   outreach half of Leads. So below the breakpoint the panel SCROLLS instead:
   cells stay on one line, the identifying column is pinned so the numbers can be
   read against it, and any heading inside the panel is pinned with it. Measured
   on Warehouse: rows 103px -> 43px, 3 visible rows -> 9, nothing unreachable.
   Deliberately NOT stacked into cards: these tables exist to be sorted and
   scanned down a column, which a card layout makes impossible. */
@media(max-width:760px){
  /* Long-hand, NOT the two-value `overflow:auto hidden` shorthand: a browser
     that can't parse the shorthand drops the whole declaration and inherits
     `overflow:hidden` from line 39 — while nowrap and width:auto still apply,
     leaving the table WIDER than before and still unscrollable. That is the
     original complaint, made worse, on exactly the old phones most likely to
     hit it. */
  .panel{overflow-x:auto;overflow-y:hidden;-webkit-overflow-scrolling:touch}
  .panel>table{width:auto;min-width:100%}
  .panel>table th,.panel>table td{white-space:nowrap}
  /* An empty/error row is one full-width cell. It must never be pinned, capped
     or clipped: "No machines mapped — map one with host-enroll.js --market"
     truncated at the panel edge loses the instruction, and because a capped
     sticky cell doesn't widen the table there is nothing to scroll to reveal
     it. It wraps, like it did before any of this. */
  .panel>table td[colspan]{white-space:normal;position:static;max-width:none}
  /* Two opt-outs from the nowrap, for the two ways a cell can lose by it.
     `.wrapcell` — the cell is a LIST, not a value (a basket's contents). One
     line would trade tall rows for a long horizontal scroll, which is worse. It
     keeps a floor so it can't collapse to a sliver once its neighbours stop
     wrapping; the floor is deliberately small, because at 13em the host
     portal's three-column purchases table stopped fitting at 390px and pushed
     the Amount — the host's own money — behind a scroll it had never needed.
     `.softwrap` — the cell is SHORT and wraps harmlessly (a timestamp). No
     floor: keeping it on one line only reserves width its neighbour needs more.
     Measured on that same table: nowrap everywhere gave 92px median / 201px
     max rows; letting the timestamp wrap gives 71px / 136px, i.e. exactly what
     it was before any of this. */
  .panel>table td.wrapcell{white-space:normal;min-width:9em}
  .panel>table td.softwrap{white-space:normal}
  /* Pin the column that says WHICH row this is: `.stickycol` where that isn't
     the first one (the Leads table is score-ranked, so its first column is a
     number), else the first. Two RULES, not one comma-separated selector: an
     unsupported `:has()` invalidates a whole selector list, which would drop
     the explicit .stickycol case with it. Split, the fallback degrades alone. */
  /* The pinned column WRAPS rather than ellipsing. Truncation here is not a
     cosmetic loss: the identifying column is the one cell that must stay
     unambiguous, and an ellipsis cuts the tail — which is exactly where the
     disambiguating size lands when two products would otherwise read alike
     ("Grenade Chocolate Salted Caramel 60 g" / "… 100 g" both truncate to
     "Grenade Chocolate Sa…"), and where a ⚠ or "(closed permanently)" marker
     sits. A capped sticky cell also doesn't widen the table, so there is
     nothing to scroll to recover it. Two lines cost ~20px; ordering against the
     wrong SKU costs a case of stock. The min-width is what makes wrapping
     affordable: without a floor the auto layout squeezes this column to its
     longest WORD while eight nowrap neighbours take what they like (measured:
     97px wide, 82px median rows); at 12em it is 168px and rows come back to
     43px median. `min()` keeps it from dominating a narrower phone. */
  .panel>table tr>.stickycol{
    position:sticky;left:0;z-index:1;background:var(--pl-panel);
    min-width:min(12em,45vw);max-width:46vw;white-space:normal;
    box-shadow:6px 0 6px -6px color-mix(in oklab, var(--pl-text) 22%, transparent);
  }
  /* The FALLBACK pins only — no floor, and no forced wrap. `.stickycol` marks
     the columns that hold a long name; the first column of a table that has
     none is as likely to be a date (Documents, Statements) or a timestamp, and
     neither treatment suits one: reserving 12em for "25 Jul 13:13" took the
     host portal's Amount off-screen, and wrapping with no floor collapsed its
     Month column to its longest word (49px rows -> 114px). Such a cell keeps
     the blanket nowrap and its natural width; where one genuinely reads better
     wrapped, `.softwrap` says so. */
  .panel>table:not(:has(.stickycol)) tr>:first-child{
    position:sticky;left:0;z-index:1;background:var(--pl-panel);
    box-shadow:6px 0 6px -6px color-mix(in oklab, var(--pl-text) 22%, transparent);
  }
  /* A supplier/section heading shares the scroller with its table (Buy list). */
  .panel>h3{position:sticky;left:0}
}
.pill{font-size:11px;font-weight:700;padding:2px 8px;border-radius:999px;background:var(--pl-pill-bg);color:var(--pl-pill-fg)}
.hide{display:none !important}
/* visually hidden but exposed to assistive tech (chart data table) */
.sr-only{position:absolute;width:1px;height:1px;margin:-1px;padding:0;border:0;clip:rect(0 0 0 0);clip-path:inset(50%);overflow:hidden;white-space:nowrap}

/* Primary button (login / Apply range). width:100% matches the auth cards; the
   .mini variant used inside the analytics period bar shrinks it back. */
.btn{
  width:100%;display:inline-flex;align-items:center;justify-content:center;gap:9px;
  background:var(--pl-chip-active-bg);color:var(--pl-chip-active-fg);border:0;border-radius:13px;cursor:pointer;
  font-family:var(--pl-font-display);font-weight:700;font-size:14.5px;padding:14px 20px;
  box-shadow:var(--pl-shadow);transition:transform 140ms var(--pl-ease);
}
.btn:active{transform:translateY(2px)}
.btn:disabled{opacity:.6;cursor:default}
.mini{width:auto;padding:9px 16px;font-size:13px;border-radius:11px}

/* ── Analytics: period selector, KPIs, chart, sortable table ── */
.periodbar{display:flex;flex-wrap:wrap;gap:12px;align-items:center;justify-content:space-between;margin-bottom:16px}
.grantabs{display:flex;flex-wrap:wrap;gap:8px;align-items:center}
.chip{font-family:var(--pl-font-body);font-weight:600;font-size:13px;padding:8px 14px;border-radius:999px;border:1px solid var(--pl-line);background:var(--pl-panel);color:var(--pl-text-soft);cursor:pointer;transition:background 140ms var(--pl-ease),color 140ms var(--pl-ease)}
.chip:hover{background:var(--pl-panel-2)}
.chip.active{background:var(--pl-chip-active-bg);color:var(--pl-chip-active-fg);border-color:var(--pl-chip-active-bg)}
.chip.caltab{font-size:15px;padding:7px 12px;line-height:1}
.navbar{display:inline-flex;align-items:center;gap:6px}
.navarrow{width:34px;height:34px;padding:0;border-radius:999px;border:1px solid var(--pl-line);background:var(--pl-panel);color:var(--pl-text);line-height:1;cursor:pointer;display:grid;place-items:center;transition:background 140ms var(--pl-ease)}
.navarrow:hover:not(:disabled){background:var(--pl-panel-2)}
.navarrow:disabled{opacity:.35;cursor:default}
.navlabel{font-family:var(--pl-font-body);font-weight:600;font-size:14px;min-width:140px;text-align:center;color:var(--pl-text)}
/* On narrow screens the navigator drops to its own line: span full width so the
   arrows sit hard left/right with the label centred between them. */
@media(max-width:600px){
  .navbar{width:100%;justify-content:space-between}
  .navlabel{flex:1}
}
.customrange{display:flex;flex-wrap:wrap;align-items:center;gap:8px}
.customrange input[type=date]{font:inherit;font-weight:500;margin:0;width:auto;padding:8px 10px;font-size:13px;border-radius:10px;border:1px solid var(--pl-line);background:var(--pl-panel-2);color:var(--pl-text)}
.customrange input[type=date]:focus{outline:none;border-color:var(--pl-accent);background:var(--pl-panel)}
/* …but never leave a keyboard user with only a 1px border change to find the
   caret by (#55 item 8). :focus-visible comes AFTER the :focus rule above so it
   wins the cascade — the reverse order silently loses and looks identical in
   review. */
.customrange input[type=date]:focus-visible{outline:2px solid var(--pl-accent);outline-offset:2px}
.customrange .dash{color:var(--pl-muted)}

.kpis{display:grid;gap:10px;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));margin-bottom:16px}
.kpi{background:var(--pl-panel);border:1px solid var(--pl-line);border-radius:14px;padding:14px 16px;box-shadow:var(--pl-shadow)}
.kpi .k{font-family:var(--pl-font-mono);font-weight:700;font-size:9.5px;letter-spacing:.14em;text-transform:uppercase;color:var(--pl-muted);margin-bottom:6px}
.kpi .v{font-family:var(--pl-font-display);font-weight:700;font-size:21px;letter-spacing:-.02em;line-height:1.05}
.kpi .v small{font-family:var(--pl-font-body);font-weight:500;font-size:12px;color:var(--pl-muted);margin-left:5px}

.chartpanel{position:relative;padding:18px 18px 10px;margin-bottom:16px}
.charthead{display:flex;align-items:center;justify-content:space-between;gap:10px 14px;margin-bottom:8px;flex-wrap:wrap}
.charthead-left{display:flex;align-items:center;gap:10px;flex-wrap:wrap}
.charthead .ct{font-family:var(--pl-font-mono);font-weight:700;font-size:10px;letter-spacing:.16em;text-transform:uppercase;color:var(--pl-muted)}
.cumbtn{font-family:var(--pl-font-body);font-weight:600;font-size:11.5px;padding:5px 11px;border-radius:999px;border:1px solid var(--pl-line);background:var(--pl-panel);color:var(--pl-text-soft);cursor:pointer;transition:background 120ms var(--pl-ease),color 120ms var(--pl-ease)}
.cumbtn:hover{background:var(--pl-panel-2)}
.cumbtn[aria-pressed="true"]{background:var(--pl-chip-active-bg);color:var(--pl-chip-active-fg);border-color:var(--pl-chip-active-bg)}
#chart svg{width:100%;height:auto;display:block}
#chart .empty{text-align:center;padding:34px 0}
.bar-rect{fill:var(--pl-bar);transition:fill 120ms}
.bar-rect:hover{fill:var(--pl-bar-hover)}
.grid-line{stroke:var(--pl-line);stroke-width:1}
.axis-label{fill:var(--pl-muted);font-family:var(--pl-font-mono);font-size:10px}
.line-path{fill:none;stroke:var(--pl-accent);stroke-width:4;stroke-linejoin:round;stroke-linecap:round}
.line-path.purchases{stroke:var(--pl-line-2)}
.line-path.users{stroke:var(--pl-line-3)}
.area-path{fill:var(--pl-accent-soft);opacity:.5}
.dot{fill:var(--pl-accent);stroke:var(--pl-panel);stroke-width:1.5}
.dot.purchases{fill:var(--pl-line-2)}
.dot.users{fill:var(--pl-line-3)}
.hoverband{fill:transparent}
.hoverband:hover{fill:rgba(var(--pl-heat-rgb),.07)}
.axis-money{fill:var(--pl-bar)}
.chartlegend{display:flex;gap:8px;align-items:center;flex-wrap:wrap}
.leg{display:inline-flex;align-items:center;gap:6px;font-size:12px;font-weight:600;color:var(--pl-text-soft);font-family:inherit;background:none;border:1px solid transparent;border-radius:999px;padding:4px 9px;cursor:pointer;transition:background 120ms var(--pl-ease),opacity 120ms var(--pl-ease)}
.leg:hover{background:var(--pl-panel-2)}
.leg.off{opacity:.45;text-decoration:line-through;text-decoration-thickness:1.5px}
.leg .sw{display:inline-block}
.leg .sw.bar{width:13px;height:11px;border-radius:2px;background:var(--pl-bar)}
.leg .sw.line{width:16px;height:0;border-top:3px solid var(--pl-accent);border-radius:2px}
.leg .sw.line.purchases{border-top-color:var(--pl-line-2)}
.leg .sw.line.users{border-top-color:var(--pl-line-3)}

/* A figure we no longer hold (#55 item 6 Q4 — payer ids are removed at 25
   months). Deliberately NOT the `.off` look: `.off` means "you switched this
   off, switch it back on", and the same styling here would invite a click that
   can never work. Muted + a not-allowed cursor + the title on the element says
   the data is gone, not hidden. `.leg.unavailable` keeps its hover suppressed
   for the same reason. */
.unavailable{color:var(--pl-muted);font-weight:500}
.kpi .v .unavailable{font-size:15px;letter-spacing:0}
.leg.unavailable,.chip.unavailable{opacity:.5;cursor:not-allowed}
.leg.unavailable:hover,.chip.unavailable:hover{background:none}

/* ── Heatmap (weekday rows × hour columns) ── */
.hmscalebar{display:flex;justify-content:flex-end;margin-top:9px}
.hmscale{display:inline-flex;align-items:center;gap:7px;font-family:var(--pl-font-mono);font-weight:700;font-size:9.5px;letter-spacing:.1em;text-transform:uppercase;color:var(--pl-muted)}
.hmscale .ramp{display:inline-block;width:90px;height:9px;border-radius:3px;border:1px solid var(--pl-line);background:linear-gradient(90deg,rgba(var(--pl-heat-rgb),.10),rgba(var(--pl-heat-rgb),.98))}
.hm{display:grid;gap:3px;grid-template-columns:auto repeat(24,1fr);align-items:center}
.hm .hm-corner{}
/* column headers = hours (across the top); row headers = weekdays (down the left) */
.hm .hm-colhead{font-family:var(--pl-font-mono);font-weight:700;font-size:9px;color:var(--pl-muted);text-align:center;padding-bottom:2px;white-space:nowrap}
.hm .hm-rowhead{font-family:var(--pl-font-mono);font-weight:700;font-size:10px;letter-spacing:.06em;text-transform:uppercase;color:var(--pl-muted);text-align:right;padding-right:9px;white-space:nowrap}
.hm .hm-cell{height:26px;border-radius:4px;border:1px solid var(--pl-line);cursor:default;transition:outline 100ms}
.hm .hm-cell:hover{outline:2px solid var(--pl-text);outline-offset:1px}
/* Keyboard focus must be at least as visible as hover, and MORE so — a mouse
   user knows where their pointer is, a keyboard user has only this (#58). The
   accent colour distinguishes 'I am here' from 'the mouse is passing over'. */
.hm .hm-cell:focus{outline:none}
.hm .hm-cell:focus-visible{outline:3px solid var(--pl-accent);outline-offset:1px;z-index:1;position:relative}
@media(max-width:560px){.hm{gap:2px}.hm .hm-cell{height:18px;border-radius:3px}.hm .hm-rowhead{font-size:8.5px;padding-right:5px}.hm .hm-colhead{font-size:7px}}
/* Heatmap readout: a fixed breakdown below the grid that tracks the hovered cell
   (replaces a floating tooltip that could fall off-screen). */
.hmreadout{display:flex;flex-wrap:wrap;align-items:baseline;gap:8px 18px;margin-top:14px;padding-top:13px;border-top:1px solid var(--pl-line);min-height:40px}
.hmreadout .ro-label{font-family:var(--pl-font-mono);font-weight:700;font-size:11px;letter-spacing:.08em;text-transform:uppercase;color:var(--pl-text);white-space:nowrap}
.hmreadout .ro-hint{color:var(--pl-muted);font-size:13px;font-weight:500}
.hmreadout .ro-stats{display:flex;flex-wrap:wrap;gap:8px 18px}
.hmreadout .ro-stat{display:inline-flex;align-items:baseline;gap:6px}
.hmreadout .ro-k{font-family:var(--pl-font-mono);font-weight:700;font-size:9.5px;letter-spacing:.12em;text-transform:uppercase;color:var(--pl-muted)}
/* Mono + tabular numerals so values keep a constant width as the cursor moves
   between cells — no horizontal jitter when the figures change. */
.hmreadout .ro-v{font-family:var(--pl-font-mono);font-weight:800;font-size:14px;font-variant-numeric:tabular-nums;color:var(--pl-text)}

.tablehead{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:11px 16px;border-bottom:1px solid var(--pl-line)}
.tablehead input{font:inherit;font-weight:500;margin:0;width:auto;flex:1;max-width:260px;padding:9px 12px;font-size:13.5px;border-radius:10px;border:1px solid var(--pl-line);background:var(--pl-panel-2);color:var(--pl-text)}
.tablehead input:focus{outline:none;border-color:var(--pl-accent);background:var(--pl-panel)}
.tablehead input:focus-visible{outline:2px solid var(--pl-accent);outline-offset:2px}
.tablehead .cnt{font-size:12.5px;color:var(--pl-muted);white-space:nowrap}
th.sortable{cursor:pointer;user-select:none;white-space:nowrap}
th.sortable:hover{color:var(--pl-text-soft)}
th.sortable .arw{font-size:9px;margin-left:3px;color:var(--pl-accent)}
