/* The admin panel: the Master Cockpit and the payout desk.
   ============================================================================

   This page used to wear the vendor app's old chalkboard: a warm chalk-black
   ground, cream text, turmeric for money and tandoor teal for "done". It said
   it was the same palette as web/qr-page and apps/vendor_app/lib/theme.dart,
   and for a while it was. Then both of them moved. The QR page went first,
   because the person reading it is a customer about to open the customer app
   (its header tells that story). The vendor app followed on 18 September 2026,
   at the owner's request: one product, one set of colours. This page was the
   last surface still on the chalkboard, so it was the seam.

   So the tokens below are the counter palette, name for name and value for
   value with `apps/vendor_app/lib/theme.dart` and `web/qr-page/css/style.css`.
   Keep them in step with those files. The rules that come with the colours
   come too, because without them the palette is just paint:

     * `--lit` is live state and the one constructive control on a form. On
       the cockpit that means a stall that is open and people standing in a
       line. It is not decoration: a screen where everything is lit is a
       screen where nothing is.
     * `--attention` (the vendor app's lemon) is a question for the operator:
       money owed, something that went wrong, a refund nobody acknowledged.
       It never appears alone; the text always says why.
     * `--danger` is a refusal or a problem. The QR page's value, lifted for a
       dark web page, rather than the app's slightly deeper one.
     * Small print is the same white turned down, never a new grey.

   What is different from the QR page is the shape. That page is a phone held
   at a stall. This is a laptop on a desk with net banking open beside it, so
   it is wider and denser, and the cockpit is drawn as an instrument cluster:
   one strip per group, gauges as segments of it, a lamp on the ones that
   carry state. Figures are heavy and tabular in the system face, and upright:
   the italic the QR page borrows from the apps' Exo 2 was dropped here at the
   owner's request, 2 October 2026 - only the sign-in lockup, which is the
   wordmark in Exo 2's own italic face, still leans. Account numbers stay
   in the monospace stack because they are read a digit at a time and typed
   into a bank. */

:root {
  /* The board's unlit ground, and the raised surfaces on it. */
  --ground: #212121;
  --board: #2e2e2e;

  --text: #f8f8f8;
  --quiet: rgba(248, 248, 248, 0.55);
  --fainter: rgba(248, 248, 248, 0.45);
  --edge: rgba(248, 248, 248, 0.14);
  --rim: rgba(248, 248, 248, 0.24);

  /* Live state, lit and unlit: the same switch, on and off. */
  --lit: #5dd62c;
  --unlit: #337418;

  /* A question for the operator. Printed on, it takes the ground's ink. */
  --attention: #ffe135;

  --danger: #ff6b5a;

  --mono: ui-monospace, "SF Mono", "Roboto Mono", monospace;
  --radius: 6px;
}

/* Same guard as the QR page: the `hidden` attribute means display:none in the
   UA stylesheet and loses to any author rule setting `display`, so an element
   with both `hidden` and `display: flex` stays visible. This page toggles
   `hidden` on flex containers, so it is one rule away from the bug the QR page
   shipped — a fee row that stayed on screen for customers it did not apply to.
   Cheaper to state once than to remember at every call site. */
[hidden] {
  display: none !important;
}

* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

body {
  font-family: -apple-system, "Segoe UI", Roboto, sans-serif;
  color: var(--text);
  background: var(--ground);
  min-height: 100vh;
  line-height: 1.45;
}

/* The console takes the whole window. It is an operator's panel on a desk
   monitor, not an article, and a fixed reading width left a third of a wide
   screen empty while the gauges it exists to show were squeezed. */
#app {
  padding: 1.25rem clamp(1rem, 2.5vw, 2.5rem) 4rem;
}

a,
button,
input,
select,
[tabindex] {
  outline-offset: 2px;
}
a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible {
  outline: 2px solid var(--text);
}

/* Masthead ---------------------------------------------------------------- */

/* Three columns: the name, the clock, the menu. The outer two are equal
   fractions so the clock sits on the page's true centre line, not merely
   between its neighbours - with a flex row it would drift toward whichever
   side is narrower. */
.masthead {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 1.5rem;
  padding-bottom: 0.9rem;
  margin-bottom: 1.25rem;
  border-bottom: 1px solid var(--edge);
}

/* The masthead is the name and nothing else, in the lit green - the same
   green as the customer app's hero card and the Q on the sign-in lockup.
   An exception to --lit meaning live state, and the only one: this is the
   brand, which the palette's rules come from rather than answer to. */
h1 {
  font-size: 1.3rem;
  font-weight: 800;
  letter-spacing: -0.01em;
  color: var(--lit);
}

/* Menu -------------------------------------------------------------------

   The masthead carries one control. Behind it are the two desks and the way
   out: the things an operator reaches for between pieces of work, not during
   one, so they cost a click and buy back the width.

   It appears exactly when the sign-out button does. Signed-in state is
   already held in one place - main.js setting `hidden` on #sign-out - and a
   second place to hold it is a second place to get it wrong, so this reads
   that one rather than keeping its own. */
/* The middle of the masthead: the queue, a hairline, the clock. */
.masthead__centre {
  display: flex;
  align-items: center;
  gap: 1.25rem;
}
/* A hairline after every figure, so the clock - always last - closes the run
   without one. All the figures arrive in one read and show together, so no
   figure is ever left with a line beside nothing. */
.masthead__centre .stat {
  padding-right: 1.25rem;
  border-right: 1px solid var(--edge);
}

/* The right-hand end of the masthead: the menu. */
.masthead__end {
  justify-self: end;
  display: flex;
  align-items: center;
  gap: 1.25rem;
}

/* A live figure in the masthead: the count, heavy and tabular, then its
   label as small print. The queue's lamp sits before its count and is lit
   only while anybody is in a line - exactly the live state the palette
   reserves the colour for. */
.stat {
  display: flex;
  align-items: center;
  gap: 0.45rem;
  white-space: nowrap;
}
.stat__count {
  font-size: 1.1rem;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
}
.stat__label {
  font-size: 0.85rem;
  color: var(--quiet);
}
/* A figure that could not be refreshed stays, dimmed, with the reason in its
   title, rather than vanishing or pretending to be current. */
.stat--stale .stat__count {
  color: var(--quiet);
}

.menu {
  position: relative;
  display: none;
}

/* The clock. Time and date are set alike, at the owner's request: one
   reading, not a figure and its small print. Heavy and tabular, so the
   minutes do not shift the line when they change. */
.clock {
  display: flex;
  align-items: baseline;
  gap: 0.6rem;
  white-space: nowrap;
}
.clock__time,
.clock__date {
  font-size: 1.1rem;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
}
.masthead:has(#sign-out:not([hidden])) .menu {
  display: block;
}

/* Just the bars: no box around them. The hit area stays a full 2.25rem
   square so the target is no smaller for having no visible edge. */
.menu__button {
  display: grid;
  place-items: center;
  width: 2.25rem;
  height: 2.25rem;
  background: none;
  border: 0;
  cursor: pointer;
  opacity: 0.8;
}
.menu__button:hover,
.menu__button[aria-expanded="true"] {
  opacity: 1;
}

/* Three bars, drawn rather than fetched: this page has no icon font and its
   CSP would refuse one. They echo the app mark's three bars, which is why the
   middle one is the long one there and they are even here - the mark is the
   mark, and this is a control. */
.menu__bars,
.menu__bars::before,
.menu__bars::after {
  display: block;
  width: 1rem;
  height: 2px;
  border-radius: 2px;
  background: var(--text);
}
.menu__bars {
  position: relative;
}
.menu__bars::before,
.menu__bars::after {
  content: "";
  position: absolute;
  left: 0;
}
.menu__bars::before {
  top: -5px;
}
.menu__bars::after {
  top: 5px;
}

.menu__panel {
  position: absolute;
  top: calc(100% + 0.5rem);
  right: 0;
  z-index: 20;
  display: flex;
  flex-direction: column;
  min-width: 11rem;
  padding: 0.35rem;
  background: var(--board);
  border: 1px solid var(--rim);
  border-radius: var(--radius);
  /* The panel floats over the gauges, so it needs a shadow to sit above them
     rather than among them. */
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5);
}

/* The way out is last and divided off: it is not a third desk, and a stray
   click on it costs the operator their session. */
.menu__panel #sign-out {
  margin-top: 0.35rem;
  padding: 0.5rem 0.6rem;
  text-align: left;
  text-decoration: none;
  color: var(--quiet);
  border-top: 1px solid var(--edge);
  border-radius: 0;
  font-size: 0.85rem;
}
.menu__panel #sign-out:hover:not(:disabled) {
  color: var(--text);
}

/* Two desks, stacked in the panel. The one showing takes the text colour and
   a marker in the gutter, not a lit one: which desk you are on is not live
   state. */
.desk-nav {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
}
.desk-nav button {
  position: relative;
  padding: 0.5rem 0.6rem 0.5rem 1.1rem;
  text-align: left;
  color: var(--quiet);
  background: none;
  border: 0;
  border-radius: 4px;
  font-size: 0.9rem;
  cursor: pointer;
}
.desk-nav button:hover {
  color: var(--text);
  background: var(--ground);
}
.desk-nav button[aria-current="page"] {
  color: var(--text);
}
.desk-nav button[aria-current="page"]::before {
  content: "";
  position: absolute;
  left: 0.45rem;
  top: 50%;
  width: 2px;
  height: 0.9rem;
  margin-top: -0.45rem;
  border-radius: 2px;
  background: var(--text);
}

/* Said once, for anything whose label is for a screen reader and whose shape
   says it on screen. */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

h2 {
  font-size: 0.95rem;
  font-weight: 700;
  color: var(--quiet);
  margin-bottom: 0.6rem;
}

h3 {
  font-size: 1.05rem;
  font-weight: 700;
}

.lede {
  color: var(--quiet);
  margin-bottom: 1.5rem;
  max-width: 46ch;
}

.muted {
  color: var(--quiet);
  font-size: 0.875rem;
}

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

label {
  display: block;
  margin-bottom: 0.9rem;
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--quiet);
}

input {
  display: block;
  width: 100%;
  margin-top: 0.4rem;
  padding: 0.65rem 0.8rem;
  font: inherit;
  color: var(--text);
  background: var(--ground);
  border: 1px solid var(--rim);
  border-radius: var(--radius);
}
input:focus {
  border-color: var(--text);
}
input::placeholder {
  color: var(--fainter);
}

/* Buttons are quiet by default: an outline in the text colour. The two that
   move the job forward (signing in, recording a payment) are lit, and the one
   that sends money out is outlined in danger. A desk of filled buttons is a
   desk where nothing says which one matters. */
button {
  font: inherit;
  font-weight: 700;
  color: var(--text);
  background: none;
  border: 1px solid var(--rim);
  border-radius: var(--radius);
  padding: 0.55rem 1rem;
  cursor: pointer;
}
button:hover:not(:disabled) {
  border-color: var(--text);
}
button:disabled {
  color: var(--fainter);
  border-color: var(--edge);
  background: none;
  cursor: not-allowed;
}

#sign-in-button,
.mark-paid button,
.pay-button {
  color: var(--ground);
  background: var(--lit);
  border-color: var(--lit);
}
#sign-in-button:disabled,
.mark-paid button:disabled {
  color: var(--fainter);
  background: var(--edge);
  border-color: transparent;
}

.button--refund {
  color: var(--danger);
  border-color: var(--danger);
}

#sign-in-button {
  width: 100%;
}

/* Sign in ------------------------------------------------------------------
   The look is the vendor website's login (apps/vendor_app/lib/screens/auth/:
   auth_ui.dart, phone_screen.dart), copied over as CSS and nothing else; this
   screen still signs in with email and password. Copied: the dark doodled
   ground (the website's own artwork, img/login-backdrop.webp) blurred behind
   the name and the card in frosted panels; the BoboQ lockup in Exo 2 900 with the Q lit,
   and a tracked label under it; a 22px-radius card on the board tone holding
   a 26/800 heading, a quiet 14.5 lede, 14px-radius fields on the ground tone,
   a danger line with an icon, and the full-width 52px white button with a
   12px radius and 14/800 tracked capitals. Exo 2 is the vendor app's bundled
   font (OFL, fonts/OFL.txt), served from here because the CSP allows font-src
   'self' and no CDN. Drawn only while the sign-in view is showing, via :has(),
   so the desks keep their own chrome. */

@font-face {
  font-family: "Exo 2";
  font-style: italic;
  font-weight: 100 900;
  font-display: swap;
  src: url("../fonts/Exo2-Italic.ttf") format("truetype");
}

body:has(#sign-in-view:not([hidden])) {
  background: #181818 url("../img/login-backdrop.webp") center / cover no-repeat fixed;
}
/* The artwork stays whole across the page and is blurred only behind the
   name and the card, each in its own frosted panel, so type is never read
   against line work. Rectangular on purpose: the panels follow what they
   hold rather than a spotlight in the middle of the screen. */
.brand,
#sign-in-form {
  -webkit-backdrop-filter: blur(14px);
  backdrop-filter: blur(14px);
}
#app:has(#sign-in-view:not([hidden])) {
  position: relative;
  max-width: none;
  padding: 0;
}
/* The lockup stands in for the masthead's name while signed out. */
#app:has(#sign-in-view:not([hidden])) .masthead {
  display: none;
}

#sign-in-view {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2.25rem;
  padding: 2rem 1rem;
}

.brand {
  text-align: center;
  padding: 22px 36px;
  border-radius: 22px;
  background: rgba(24, 24, 24, 0.55);
}
.brand__name {
  font-family: "Exo 2", -apple-system, "Segoe UI", Roboto, sans-serif;
  font-style: italic;
  font-weight: 900;
  font-size: 60px;
  line-height: 1.05;
  letter-spacing: -1.2px;
}
.brand__q {
  color: var(--lit);
}
.brand__desk {
  margin-top: 14px;
  font-family: "Exo 2", -apple-system, "Segoe UI", Roboto, sans-serif;
  font-style: italic;
  font-weight: 700;
  font-size: 18px;
  line-height: 1.06;
  letter-spacing: 5.4px;
  text-transform: uppercase;
  color: var(--quiet);
}

#sign-in-form {
  width: 100%;
  max-width: 440px;
  padding: 28px;
  /* The board tone, let through just enough for the blur to show. */
  background: rgba(46, 46, 46, 0.82);
  border-radius: 22px;
}
.auth-title {
  margin: 0;
  font-size: 26px;
  font-weight: 800;
  letter-spacing: -0.2px;
  color: var(--text);
}
.auth-detail {
  margin: 8px 0 20px;
  font-size: 14.5px;
  line-height: 1.45;
  color: var(--quiet);
}
#sign-in-form label {
  margin-bottom: 14px;
  font-size: 13px;
  font-weight: 600;
}
#sign-in-form input {
  margin-top: 6px;
  padding: 14px 16px;
  font-size: 17px;
  font-weight: 600;
  color: var(--text);
  background: var(--ground);
  border: 1px solid var(--edge);
  border-radius: 14px;
  caret-color: var(--text);
}
#sign-in-form input:focus {
  border-color: var(--rim);
  outline: none;
}
#sign-in-form input:focus-visible {
  outline: 2px solid var(--text);
  outline-offset: 2px;
}
#sign-in-form .error {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  margin: 2px 0 0;
  font-size: 13.5px;
  line-height: 1.4;
}
#sign-in-form .error::before {
  content: "";
  flex: none;
  width: 17px;
  height: 17px;
  margin-top: 1px;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23ff6b5a' stroke-width='2' stroke-linecap='round'%3E%3Ccircle cx='12' cy='12' r='9'/%3E%3Cpath d='M12 7v6M12 16.5v.5'/%3E%3C/svg%3E") center / contain no-repeat;
}
#sign-in-view #sign-in-button {
  height: 52px;
  margin-top: 20px;
  padding: 0 1rem;
  font-size: 14px;
  font-weight: 800;
  letter-spacing: 0.6px;
  text-transform: uppercase;
  color: var(--ground);
  background: var(--text);
  border: 0;
  border-radius: 12px;
}
#sign-in-view #sign-in-button:hover:not(:disabled) {
  background: #ffffff;
}
#sign-in-view #sign-in-button:disabled {
  color: var(--fainter);
  background: #141414;
}

@media (max-width: 480px) {
  .brand__name {
    font-size: 44px;
  }
  .brand__desk {
    font-size: 13px;
    letter-spacing: 4px;
  }
  #sign-in-view {
    gap: 1.75rem;
    padding: 1.5rem 0.75rem;
  }
  #sign-in-form {
    padding: 22px 18px;
  }
}

/* A button that reads as a control, not a call to action — Show, Hide, Copy,
   Sign out. These sit inside dense rows and must not compete with the one
   button on the row that moves money's record forward. */
.link-button {
  padding: 0.15rem 0.3rem;
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--text);
  background: none;
  border: 0;
  border-radius: 4px;
  text-decoration: underline;
  text-decoration-color: var(--rim);
  text-underline-offset: 3px;
}
.link-button:hover:not(:disabled) {
  text-decoration-color: var(--text);
}

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

.error {
  color: var(--danger);
  font-size: 0.875rem;
  margin-top: 0.6rem;
}

.notice {
  padding: 0.7rem 0.9rem;
  margin-bottom: 1rem;
  font-size: 0.9rem;
  color: var(--text);
  background: var(--board);
  border-left: 3px solid var(--rim);
  border-radius: 0 var(--radius) var(--radius) 0;
}
.notice--error {
  color: var(--danger);
  border-left-color: var(--danger);
}

.panel {
  padding: 1rem;
  margin-bottom: 1.5rem;
  background: var(--board);
  border: 1px solid var(--edge);
  border-radius: var(--radius);
}
.panel ul {
  padding-left: 1.1rem;
}
.panel li {
  margin-bottom: 0.6rem;
}
.panel input[type="text"],
.panel input[type="search"] {
  width: auto;
  display: inline-block;
  min-width: 16rem;
  margin: 0.3rem 0.5rem 0.3rem 0;
}

/* Stragglers mean somebody is owed money the main list is not showing. That
   is the one thing on the payout desk that should look wrong. */
.panel--warn {
  border-left: 3px solid var(--danger);
}
.panel--warn h2 {
  color: var(--danger);
}
#straggler-list {
  margin-top: 0.7rem;
  font-size: 0.9rem;
}
#straggler-list li {
  margin-bottom: 0.3rem;
}

/* The cockpit ------------------------------------------------------------- */

/* A widget on the board: a titled panel, its controls in its own header. */
.widget {
  margin-bottom: 1.5rem;
  background: var(--board);
  border: 1px solid var(--edge);
  border-radius: var(--radius);
}
.widget__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.9rem 1rem;
  border-bottom: 1px solid var(--edge);
}
.widget__title {
  font-size: 1rem;
  font-weight: 800;
}
.widget__search {
  width: min(22rem, 100%);
  margin: 0;
  padding: 0.5rem 0.75rem;
}
.widget__empty {
  padding: 1.25rem 1rem;
}
.widget > .error {
  padding: 0.9rem 1rem;
}
.widget__foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.75rem 1rem;
  border-top: 1px solid var(--edge);
}
.pager {
  display: flex;
  gap: 0.5rem;
}
.pager button {
  padding: 0.35rem 0.8rem;
  font-size: 0.85rem;
}

/* The vendor table. Scrolls sideways inside its panel on a narrow screen
   rather than pushing the page wider than the window. */
.vendor-table__scroll {
  overflow-x: auto;
}
.vendor-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.9rem;
}
.vendor-table th {
  padding: 0.6rem 1rem;
  text-align: left;
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--quiet);
  white-space: nowrap;
}
.vendor-table td {
  padding: 0.65rem 1rem;
  border-top: 1px solid var(--edge);
  white-space: nowrap;
}
.vendor-table tbody tr:hover {
  background: var(--ground);
}
.vendor-table__number {
  color: var(--quiet);
  font-variant-numeric: tabular-nums;
}
.vendor-table__name {
  font-weight: 700;
  white-space: normal;
}
/* The stall name opens its details: it reads as the name, and underlines on
   hover and focus to say it can be pressed. */
.vendor-table__open {
  padding: 0;
  font-weight: 700;
  text-align: left;
  color: var(--text);
  background: none;
  border: 0;
  border-radius: 2px;
  cursor: pointer;
  text-decoration: underline;
  text-decoration-color: transparent;
  text-underline-offset: 3px;
}
.vendor-table__open:hover,
.vendor-table__open:focus-visible {
  text-decoration-color: var(--text);
}

/* The vendor details panel: a drawer down the right-hand side, over a dimmed
   board. The list stays visible beside it, so the operator keeps their place. */
.drawer {
  position: fixed;
  inset: 0 0 0 auto;
  width: min(28rem, 100vw);
  height: 100vh;
  max-height: none;
  margin: 0;
  padding: 1.25rem 1.5rem;
  color: var(--text);
  background: var(--board);
  border: 0;
  border-left: 1px solid var(--rim);
  box-shadow: -20px 0 40px rgba(0, 0, 0, 0.45);
}
.drawer::backdrop {
  background: rgba(0, 0, 0, 0.45);
}
.drawer__head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1rem;
  margin-bottom: 0.75rem;
}
.drawer__title {
  font-size: 1.3rem;
  font-weight: 800;
  line-height: 1.25;
}
.drawer__close {
  flex: none;
  width: 2rem;
  height: 2rem;
  padding: 0;
  font-size: 1.4rem;
  line-height: 1;
  color: var(--quiet);
  border: 0;
}
.drawer__close:hover:not(:disabled) {
  color: var(--text);
}
.drawer__status {
  display: flex;
  align-items: center;
  gap: 0.45rem;
  margin-bottom: 1rem;
  font-weight: 700;
}
.drawer__status .lamp {
  background: currentColor;
}
.drawer__deletion {
  margin-bottom: 1rem;
  font-size: 0.85rem;
  color: var(--quiet);
}
.drawer__deletion .tag {
  margin: 0 0.4rem 0 0;
}
/* The panel scrolls inside itself when a vendor has more than fits. */
.drawer[open] {
  overflow-y: auto;
}
.drawer__section {
  padding: 1rem 0;
  border-top: 1px solid var(--edge);
}
.drawer__section-title {
  margin-bottom: 0.75rem;
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--quiet);
}
.drawer__lines {
  display: grid;
  grid-template-columns: max-content 1fr;
  gap: 0.6rem 1.25rem;
}
.drawer__lines dd {
  overflow-wrap: anywhere;
}
.drawer__reveal {
  margin-left: 0.6rem;
  font-family: -apple-system, "Segoe UI", Roboto, sans-serif;
}
.drawer__map {
  padding-top: 1rem;
  border-top: 1px solid var(--edge);
  font-size: 0.9rem;
}
.drawer__map a {
  color: var(--text);
  text-underline-offset: 3px;
}
.drawer__lines dt {
  font-size: 0.85rem;
  color: var(--quiet);
}
.drawer__mono {
  font-family: var(--mono);
}
/* A phone is read a digit at a time and typed into a dialler: monospace, by
   the same rule as account numbers on the payout desk. */
.vendor-table__phone {
  font-family: var(--mono);
  font-size: 0.85rem;
}
.vendor-table__status {
  display: flex;
  align-items: center;
  gap: 0.45rem;
}
/* Status in three colours, the owner's call (2 October 2026): open green,
   paused yellow, closed red. The dot and the word both take the colour, and
   the word is always there, so the colour is never the only signal. */
.vendor-status--open {
  color: var(--lit);
}
.vendor-status--paused {
  color: var(--attention);
}
.vendor-status--closed {
  color: var(--danger);
}
.vendor-table__status .lamp {
  background: currentColor;
}

/* A short label beside a name. */
.tag {
  display: inline-block;
  margin-left: 0.4rem;
  padding: 0.05rem 0.4rem;
  font-size: 0.7rem;
  font-weight: 700;
  border-radius: 4px;
  vertical-align: 0.1em;
}
.tag--attention {
  color: var(--ground);
  background: var(--attention);
}

@media (max-width: 720px) {
  .widget__head {
    flex-wrap: wrap;
  }
}

/* One row per group: the group's name in a gutter on the left, its gauges in
   one board strip to the right. Every strip starts at the same edge and every
   gauge is the same width, so the figures line up in columns down the page
   the way dials do on a panel. */
.gauge-row {
  display: grid;
  grid-template-columns: 9.5rem minmax(0, 1fr);
  gap: 1.25rem;
  margin-bottom: 0.9rem;
}

.gauge-row__title {
  margin: 0;
  padding-top: 1rem;
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--quiet);
  text-align: right;
}

.gauge-row__strip {
  display: grid;
  /* Fills the row rather than stopping at its gauges' natural width. Every
     strip is now the same width, so auto-fit gives every row the same column
     count and the figures still line up in columns down the page — which is
     what the fixed 20rem columns were for. 20rem stays the floor, so a gauge
     is never narrower than it was. */
  grid-template-columns: repeat(auto-fit, minmax(min(20rem, 100%), 1fr));
  width: auto;
  background: var(--board);
  border: 1px solid var(--edge);
  border-radius: var(--radius);
  /* Clips the dividers below where they fall outside the strip, so only the
     ones between gauges show, however the row wraps. */
  overflow: hidden;
}

.gauge {
  position: relative;
  min-width: 0;
  padding: 0.95rem 1.2rem 1.05rem;
  box-shadow: -1px 0 0 var(--edge), 0 -1px 0 var(--edge);
}

/* A question for the operator: a lemon rule along the top of the segment, on
   top of the lamp. Two signals because it is the one thing the panel exists to
   surface, and the caption says why in words. */
.gauge--attention::before {
  content: "";
  position: absolute;
  inset: 0 0 auto;
  height: 3px;
  background: var(--attention);
}

.gauge__label {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--quiet);
}

.gauge__figure {
  margin: 0.3rem 0 0.45rem;
  font-size: 2.25rem;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.015em;
  line-height: 1.05;
  white-space: nowrap;
}

/* Paise on a rupee figure: kept, never rounded, and set small. */
.gauge__paise {
  font-size: 0.5em;
  font-weight: 700;
  color: var(--quiet);
}

.gauge__notes {
  list-style: none;
  font-size: 0.8rem;
  line-height: 1.4;
  color: var(--quiet);
}

.gauge__go {
  margin-top: 0.55rem;
  margin-left: -0.3rem;
}

[aria-busy="true"] .gauge__figure {
  color: var(--fainter);
}

/* The lamp. Off is a ring, unlit is the dim green, lit and attention glow. */
.lamp {
  flex: none;
  width: 0.55rem;
  height: 0.55rem;
  border-radius: 50%;
}
.lamp--clear {
  box-shadow: inset 0 0 0 1px var(--rim);
}
.lamp--unlit {
  background: var(--unlit);
}
.lamp--lit {
  background: var(--lit);
  box-shadow: 0 0 0 3px rgba(93, 214, 44, 0.16), 0 0 10px rgba(93, 214, 44, 0.55);
}
.lamp--attention {
  background: var(--attention);
  box-shadow: 0 0 0 3px rgba(255, 225, 53, 0.16), 0 0 10px rgba(255, 225, 53, 0.5);
}

/* Narrower than three fixed gauges and the gutter: the strip takes the full
   width and its gauges wrap, so nothing scrolls sideways. */
@media (max-width: 1180px) {
  .gauge-row__strip {
    grid-auto-flow: row;
    grid-template-columns: repeat(auto-fit, minmax(min(14rem, 100%), 1fr));
    width: auto;
  }
}

@media (max-width: 720px) {
  /* On a phone the date gives way: the time still fits between the name
     and the menu, and the date is the part that can be looked up. */
  .masthead {
    gap: 0.75rem;
  }
  .clock__date {
    display: none;
  }
  .gauge-row {
    grid-template-columns: minmax(0, 1fr);
    gap: 0.4rem;
  }
  .gauge-row__title {
    padding-top: 0;
    text-align: left;
  }
  .gauge__figure {
    font-size: 2rem;
  }
}

/* The payout day ----------------------------------------------------------- */

/* The day picker sits in the widget's header, label and field on one line. */
.widget__date {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin: 0;
  white-space: nowrap;
}
.widget__date input {
  width: auto;
  margin: 0;
  padding: 0.45rem 0.6rem;
  color-scheme: dark;
}
.widget__sub {
  margin-top: 0.2rem;
}
.widget > .error + .error,
#payout-day-truncated {
  padding: 0.9rem 1rem;
}

/* The number the operator is about to transfer, set as a figure: it is the
   one thing on the row that has to be read exactly right. */
.payout-table__amount {
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* Pay sits at the end of the row, compact enough not to crowd it. */
.payout-table__action {
  width: 1%;
  text-align: right;
}
.pay-button {
  padding: 0.3rem 0.9rem;
  font-size: 0.85rem;
}

/* Owed in yellow, paid in green - waiting on somebody, and done. */
.payout-status--owed {
  color: var(--attention);
}
.payout-status--paid {
  color: var(--lit);
}

#owed-elsewhere ul {
  list-style: none;
  padding: 0;
}

/* The payout panel holds a six-column history, so it is wider than the
   vendor details panel. */
#payout-detail {
  width: min(46rem, 100vw);
}
.payout-detail__line {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 0.4rem;
  margin-bottom: 0.75rem;
}
.payout-detail__line .payout-table__amount {
  font-size: 1.4rem;
}
.payout-detail__status {
  font-weight: 700;
}
.vendor-table--compact th,
.vendor-table--compact td {
  padding: 0.5rem 0.6rem;
}
.widget__foot--bare {
  padding: 0.75rem 0 0;
  border-top: 0;
}

.bank {
  margin: 0.9rem 0;
  padding: 0.7rem 0.85rem;
  background: var(--ground);
  border-radius: var(--radius);
}

.bank__row {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.25rem 0;
  flex-wrap: wrap;
}

.bank__label {
  min-width: 4.5rem;
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--quiet);
}

.bank__value {
  font-family: var(--mono);
  font-size: 0.95rem;
  letter-spacing: 0.04em;
  word-break: break-all;
}

.mark-paid {
  display: flex;
  gap: 0.6rem;
  align-items: flex-start;
  flex-wrap: wrap;
}
.mark-paid input {
  flex: 1 1 12rem;
  margin-top: 0;
  width: auto;
}
.mark-paid button {
  white-space: nowrap;
}
.mark-paid .error {
  flex-basis: 100%;
  margin-top: 0.2rem;
}

@media (max-width: 480px) {
  .payout__head {
    flex-direction: column;
    gap: 0.2rem;
  }
}

/* The refresh control ------------------------------------------------------

   Sits above the list rather than beside the heading: it is the thing that
   makes the numbers below it true, and an operator should meet it before they
   read a figure they might otherwise assume is live. */
.refresh {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  flex-wrap: wrap;
  margin-bottom: 1.25rem;
}

/* Fee model ---------------------------------------------------------------

   Sits between the bank details and the mark-as-paid action: it is about this
   vendor rather than about this batch, and must not read as part of the
   payment being recorded. */
.fee-model {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  flex-wrap: wrap;
  margin: 0 0 0.9rem;
}
.fee-model__select {
  font: inherit;
  font-size: 0.9rem;
  color: var(--text);
  background: var(--ground);
  border: 1px solid var(--rim);
  border-radius: var(--radius);
  padding: 0.4rem 0.55rem;
}
.fee-model__select:disabled {
  color: var(--fainter);
}
.fee-model__note {
  font-size: 0.8rem;
  color: var(--quiet);
}

/* Platform settings --------------------------------------------------------

   Above the payout list because it changes what every vendor's customers are
   charged. Deliberately plain: a switch that decides who pays a fee should not
   look like a preference. */
.settings__row {
  display: flex;
  align-items: flex-start;
  gap: 0.7rem;
  cursor: pointer;
  color: var(--text);
}
.settings__row input {
  width: auto;
  margin: 0.15rem 0 0;
  accent-color: var(--lit);
}
.settings__row strong {
  display: block;
  font-size: 0.95rem;
  font-weight: 600;
}
.settings__note {
  display: block;
  margin-top: 0.2rem;
  font-size: 0.85rem;
  font-weight: 400;
  color: var(--quiet);
}

/* Platform fee --------------------------------------------------------------

   The owner's fee table: one row per band, read left to right as "From ₹50,
   Fee ₹5". Figures in the mono face so a column of rupees lines up. Save is
   lit, like the other controls that move a record forward; Add band and
   Remove stay quiet. */
.fee-bands h2 {
  margin-bottom: 0.2rem;
}
.fee-bands__rows {
  list-style: none;
  margin: 1rem 0 0;
  padding: 0;
  counter-reset: band;
}
.fee-band {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 0.4rem 1rem;
  padding: 0.55rem 0;
  margin: 0;
  border-top: 1px solid var(--edge);
  counter-increment: band;
}
.fee-band::before {
  content: counter(band);
  align-self: center;
  min-width: 1.4rem;
  font-family: var(--mono);
  font-size: 0.75rem;
  color: var(--fainter);
}
.fee-band__field {
  display: flex;
  align-items: center;
  gap: 0.45rem;
  margin: 0;
}
.fee-band__label {
  white-space: nowrap;
}
.fee-band__field input {
  width: 8.5rem;
  margin: 0;
  padding: 0.45rem 0.6rem;
  font-family: var(--mono);
  text-align: right;
}
.fee-band__field input[readonly] {
  color: var(--quiet);
  border-style: dashed;
}
.fee-band__remove {
  align-self: center;
  margin-left: auto;
}
.fee-bands__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem;
  padding-top: 0.8rem;
  border-top: 1px solid var(--edge);
}
.fee-bands__save {
  color: var(--ground);
  background: var(--lit);
  border-color: var(--lit);
}
.fee-bands__save:disabled {
  color: var(--fainter);
  background: var(--edge);
  border-color: transparent;
}
.fee-bands__changed {
  margin-top: 0.6rem;
  font-size: 0.8rem;
}

/* The confirm before a new fee table is saved: now on the left, after saving
   on the right, in the same lines, so a changed band is read across. */
.confirm {
  width: min(36rem, calc(100vw - 2rem));
  padding: 1.25rem 1.5rem;
  color: var(--text);
  background: var(--board);
  border: 1px solid var(--rim);
  border-radius: var(--radius);
  box-shadow: 0 20px 40px rgba(0, 0, 0, 0.45);
}
.confirm::backdrop {
  background: rgba(0, 0, 0, 0.55);
}
.confirm__title {
  margin: 0 0 1rem;
  font-size: 1.1rem;
}
.confirm__compare {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1.25rem;
}
.confirm__compare h3 {
  margin: 0 0 0.4rem;
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--quiet);
}
.confirm__list {
  margin: 0;
  padding-left: 1.2rem;
  font-family: var(--mono);
  font-size: 0.82rem;
  line-height: 1.6;
  color: var(--quiet);
}
.confirm__list--new {
  color: var(--text);
}
.confirm__actions {
  display: flex;
  justify-content: flex-end;
  gap: 0.6rem;
  margin-top: 1rem;
}
@media (max-width: 34rem) {
  .confirm__compare {
    grid-template-columns: 1fr;
  }
  .fee-band__field input {
    width: 7rem;
  }
}

/* Payment lookup ------------------------------------------------------------ */

.lookup {
  margin: 1rem 0 1.25rem;
}
.lookup label {
  margin-bottom: 0.2rem;
}
.lookup .panel {
  margin: 0.8rem 0 0;
  background: var(--ground);
}

/* The app gate --------------------------------------------------------------

   attestation_mode and attestation_enforced (specs/app-attestation-spec-v0.md,
   D13). The one control on this page that can refuse a paying customer, so the
   shape of the desk is an argument about which direction should be easy:

     * The state panel is the largest thing on the desk and reads at a glance
       — lamp, one word, one sentence. An operator opens this screen with one
       question.
     * The way back is `--lit`, filled, and the only filled button here. The
       palette's rule is that lit is the one constructive control on a form,
       and on this desk the constructive act is refusing nobody.
     * The way forward is outlined in `--danger` and sits behind a typed word.
       Same reasoning as the refund button on the payout desk: the control
       that takes something away from somebody does not get a filled button.
     * Function names are monospace, like account numbers, because they are
       compared character by character against a spec and a changelog. */

.gate-state {
  border-left: 3px solid var(--rim);
}
/* Reporting is the expected state and gets no colour. The other two are a
   refusal and a question, and the panel says which from across a desk. */
.gate-state--danger {
  border-left-color: var(--danger);
}
.gate-state--attention {
  border-left-color: var(--attention);
}
.gate-state__mode {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  font-size: 1.6rem;
  font-weight: 800;
  font-style: italic;
  letter-spacing: -0.01em;
}
.gate-state__mode .lamp {
  width: 0.7rem;
  height: 0.7rem;
}
.gate-state__headline {
  margin-top: 0.3rem;
  font-size: 1rem;
  font-weight: 600;
}
.gate-state__headline--danger {
  color: var(--danger);
}
.gate-state__enforced {
  margin-top: 0.7rem;
  font-family: var(--mono);
  font-size: 0.85rem;
  color: var(--quiet);
}

.gate-rollback {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.5rem 0.9rem;
  margin-top: 1rem;
  padding-top: 1rem;
  border-top: 1px solid var(--edge);
}
.gate-rollback .muted {
  flex: 1 1 18rem;
}

.button--rollback {
  color: var(--ground);
  background: var(--lit);
  border-color: var(--lit);
}
.button--rollback:disabled {
  color: var(--fainter);
  background: var(--edge);
  border-color: transparent;
}
/* The one that starts refusing people. Outlined, never filled. */
.button--enforce {
  color: var(--danger);
  border-color: var(--danger);
}

.gate-modes {
  display: grid;
  gap: 0.9rem;
  margin: 0.9rem 0 1rem;
}
.gate-modes .settings__row {
  margin: 0;
}

/* What enforcement would refuse, by name. Not a general caution — it is read
   immediately before the switch is thrown, so it is drawn as a refusal. */
.gate-warnings {
  margin: 0 0 1rem;
  padding: 0.7rem 0.9rem 0.7rem 1.9rem;
  font-size: 0.875rem;
  background: var(--ground);
  border-left: 3px solid var(--danger);
  border-radius: 0 var(--radius) var(--radius) 0;
}
.gate-warnings li {
  margin-bottom: 0.35rem;
}
.gate-warnings li:last-child {
  margin-bottom: 0;
}

#gate-confirm-row,
#gate-list-confirm-row {
  display: block;
  max-width: 34rem;
  margin: 0 0 1rem;
  color: var(--danger);
  font-weight: 700;
}
#gate-confirm,
#gate-list-confirm {
  max-width: 14rem;
  margin-top: 0.4rem;
  font-family: var(--mono);
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.gate-group {
  margin-bottom: 1.1rem;
}
.gate-group__title {
  margin-bottom: 0.5rem;
  font-size: 0.8rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--quiet);
}
.gate-function {
  margin-bottom: 0.65rem;
}
/* Specific enough to win against .settings__row strong without !important. */
.gate-function .gate-function__name {
  font-family: var(--mono);
  font-size: 0.9rem;
  font-weight: 700;
}
/* A row that cannot be ticked still has to be readable: it is here to say
   that the decision was made, not to look broken. */
.gate-function input:disabled + span .gate-function__name {
  color: var(--quiet);
}

/* D6a's classification, beside the name rather than buried in the note: what
   enforcing this function does to a caller depends on it. Drawn as a quiet tag
   and not a lamp — it is a property of the function, not live state. */
.gate-function__verdict {
  display: inline-block;
  margin-left: 0.5rem;
  padding: 0.05rem 0.4rem;
  font-family: var(--mono);
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.02em;
  color: var(--quiet);
  border: 1px solid var(--edge);
  border-radius: 4px;
  vertical-align: 0.1rem;
}
/* The one function a decode is ridden on is worth picking out of a list of
   twenty-two that are not. */
.gate-function__verdict--per-device {
  color: var(--text);
  border-color: var(--rim);
}

.gate-actions {
  display: flex;
  align-items: center;
  gap: 1rem;
}

.gate-trail {
  padding-left: 1.1rem;
  font-family: var(--mono);
  font-size: 0.8rem;
  color: var(--quiet);
}
.gate-trail li {
  margin-bottom: 0.4rem;
}
