/* ==========================================================================
   Tap-Pay Solutions — Agent Portal
   Design language: "the ledger line". Hairline rules over drop shadows,
   letterspaced eyebrows lifted from the SOLUTIONS lockup, tabular mono
   figures for every dollar amount.
   ========================================================================== */

/* ---- Tokens ------------------------------------------------------------ */
:root {
  /* Brand — sampled directly from TPS__LogoMark_FullColorRGB.png */
  --ink:        #101820;
  --ink-2:      #1B2530;
  --ink-3:      #2A3542;
  --crimson:    #BB2031;
  --crimson-dk: #94141F;
  --crimson-lt: #FDECEE;
  --steel:      #5C6871;
  --steel-lt:   #8A949B;
  --mist:       #C2C6C8;
  /* Hairlines and paper run a shade cooler than they did, so they sit on the
     slate field below rather than looking like warm grey cut out of it. */
  --hair:       #DDE3E9;
  --hair-soft:  #EAEEF2;
  --paper:      #F4F6F8;
  --card:       #FFFFFF;

  /* ---- Roles: what a colour MEANS, not what hue it is -------------------
     `--accent` ACTS and `--danger` WARNS. They were the same crimson until
     2026-08-12, which meant "Post statement" and "Delete statement" wore one
     colour and the only way to tell them apart was to read them.

     --accent derives from --crimson deliberately. A white-label ISO's brand
     overwrites --crimson at boot (see brand() in js/lib.js), and the acting
     colour has to follow them. --danger does NOT derive: red means danger in
     every brand, and an ISO whose colour happens to be green must not get a
     green Delete button. */
  --accent:      var(--crimson);
  --accent-dark: var(--crimson-dk);
  --accent-tint: var(--crimson-lt);
  --danger:      #8E1F27;
  --danger-dark: #741820;
  --danger-lt:   #FBEBEC;

  /* Status — kept desaturated so the accent always reads as the loudest thing */
  --green:      #1C7A56;
  --green-lt:   #E7F4EF;
  --amber:      #A8761B;
  --amber-lt:   #FBF2E2;
  --blue:       #2A5C8A;
  --blue-lt:    #EAF1F7;

  /* Type — the platform's own. Nothing is downloaded, so the first paint has
     the right letterforms instead of reflowing into them. */
  --f-display: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  --f-body:    -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  --f-mono:    ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;

  /* Geometry */
  --r-sm: 10px;
  --r:    14px;
  --r-lg: 20px;
  --rail: 244px;
  --topbar: 72px;

  /* ---- Glass, in one place so every panel agrees ------------------------
     WHERE THE GLASS STOPS. Frosted panels over a blurred ground are hard to
     read in daylight, and a residual statement gets read in a truck. So glass
     is for CHROME — the rail, stat strips, the drawer, overlays — and
     anywhere dense text lives (tables, forms, statements) is `--solid-bg`:
     94% white with a plain hairline. Every glass rule also sets a real
     background colour, so a browser without backdrop-filter gets an opaque
     panel rather than text floating on nothing. */
  --glass-bg:   rgba(255, 255, 255, .62);
  --glass-brd:  rgba(255, 255, 255, .75);
  --glass-blur: blur(18px) saturate(150%);
  --solid-bg:   rgba(255, 255, 255, .94);

  --shadow-sm:   0 1px 2px rgba(16, 24, 32, .05);
  --shadow-card: 0 1px 2px rgba(16, 24, 32, .05), 0 12px 34px -14px rgba(16, 24, 32, .26);
  --shadow-pop:  0 2px 4px rgba(16, 24, 32, .07), 0 20px 40px -18px rgba(16, 24, 32, .45);
}

/* ---- Reset ------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }
html, body { height: 100%; }
body {
  margin: 0;
  font-family: var(--f-body);
  font-size: 14px;
  line-height: 1.55;
  color: var(--ink);
  /* The field the glass sits on. Slate rather than blue — the accent is the
     only saturated thing on screen and a tinted ground would compete with it.
     Fixed, so panels blur against a still field rather than a smear that
     moves as the page scrolls. */
  background:
    radial-gradient(1100px 700px at 12% -10%, #DFE6ED 0%, rgba(223, 230, 237, 0) 60%),
    radial-gradient(900px 600px at 92% 8%, #D9E2EB 0%, rgba(217, 226, 235, 0) 55%),
    radial-gradient(1000px 800px at 60% 100%, #E6ECF2 0%, rgba(230, 236, 242, 0) 60%),
    linear-gradient(178deg, #EFF3F7 0%, #DFE6ED 100%);
  background-attachment: fixed;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

/* The two surface treatments, named so a view can ask for the right one. */
.glass {
  background: var(--glass-bg);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  border: 1px solid var(--glass-brd);
  border-radius: var(--r);
  box-shadow: var(--aura);
}
.solid {
  background: var(--solid-bg);
  border: 1px solid var(--hair);
  border-radius: var(--r);
  box-shadow: var(--shadow-card);
}
h1, h2, h3, h4, h5, p, figure, ul, ol { margin: 0; }
ul, ol { padding: 0; list-style: none; }
button, input, select, textarea { font: inherit; color: inherit; }
button { cursor: pointer; background: none; border: 0; padding: 0; }
a { color: inherit; text-decoration: none; }
img { max-width: 100%; display: block; }
table { border-collapse: collapse; width: 100%; }
:focus-visible {
  outline: 2px solid var(--crimson);
  outline-offset: 2px;
  border-radius: 3px;
}
::selection { background: var(--crimson); color: #fff; }

/* ---- Primitives -------------------------------------------------------- */

/* The eyebrow is the structural device of this design — a direct lift of the
   letterspacing in the SOLUTIONS half of the logo lockup. */
.eyebrow {
  font-family: var(--f-display);
  font-size: 10px;
  font-weight: 600;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--steel-lt);
  display: block;
}
.eyebrow--ink { color: var(--steel); }

.mono { font-family: var(--f-mono); font-variant-numeric: tabular-nums; }
.num  { font-family: var(--f-mono); font-variant-numeric: tabular-nums; letter-spacing: -.01em; }
/* No spinner arrows on a number field. They are useless for money — nobody
   nudges a rate to 2.35% a click at a time — and they hijack the scroll
   wheel when the pointer is over the box. Typing is the only sane input. */
input[type=number] { -moz-appearance: textfield; appearance: textfield; }
input[type=number]::-webkit-outer-spin-button,
input[type=number]::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
/* A figure that has turned into words — "2 Years" in the In-stage column.
   The column keeps its tabular alignment for the numbers; the word itself
   should not be set in the mono face, where the letters read pushed apart. */
.num .word, .mono .word { font-family: var(--f-body); letter-spacing: normal; }

.h1 { font-family: var(--f-display); font-size: 25px; font-weight: 700; letter-spacing: -.02em; line-height: 1.15; }
.h2 { font-family: var(--f-display); font-size: 17px; font-weight: 700; letter-spacing: -.015em; }
.h3 { font-family: var(--f-display); font-size: 14px; font-weight: 700; letter-spacing: -.01em; }
.muted   { color: var(--steel); }
.muted-2 { color: var(--steel-lt); }
.small   { font-size: 12.5px; }
.tiny    { font-size: 11.5px; }
.right   { text-align: right; }
.center  { text-align: center; }
.nowrap  { white-space: nowrap; }
.truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.hidden  { display: none !important; }
.grow    { flex: 1 1 auto; min-width: 0; }
.row     { display: flex; align-items: center; gap: 10px; }
.row-t   { display: flex; align-items: flex-start; gap: 10px; }
.col     { display: flex; flex-direction: column; }
.wrap    { flex-wrap: wrap; }
.gap-4 { gap: 4px; } .gap-6 { gap: 6px; } .gap-8 { gap: 8px; }
.gap-12 { gap: 12px; } .gap-16 { gap: 16px; } .gap-24 { gap: 24px; }
/* ⚠ FOUR CLASSES THAT WERE BEING USED WITH NOTHING BEHIND THEM. gap-2, gap-9,
   gap-14 and mb-4 appear on the account record and the settings screens and had
   no rule anywhere, so every one of those gaps was silently zero — the exact
   fault Greg has now reported three times, and invisible until somebody looks.
   Found by the class audit on 2026-09-17 while adding the Application Record.
   Written here rather than patched on the screens, because a margin added in a
   view is a bug moved rather than removed. */
.gap-2 { gap: 2px; } .gap-9 { gap: 9px; } .gap-14 { gap: 14px; }
.mb-4 { margin-bottom: 4px; }
.mt-4{margin-top:4px}.mt-8{margin-top:8px}.mt-12{margin-top:12px}
.mt-16{margin-top:16px}.mt-24{margin-top:24px}.mt-32{margin-top:32px}
.mb-8{margin-bottom:8px}.mb-12{margin-bottom:12px}.mb-16{margin-bottom:16px}.mb-24{margin-bottom:24px}

/* ---- Buttons ----------------------------------------------------------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  height: 40px; padding: 0 17px;
  border-radius: 11px;
  font-family: var(--f-display);
  font-size: 13px; font-weight: 600; letter-spacing: -.005em;
  border: 1px solid transparent;
  white-space: nowrap;
  transition: background-color .14s ease, border-color .14s ease, color .14s ease, transform .08s ease;
}
.btn:active { transform: translateY(.5px); }
.btn svg { width: 15px; height: 15px; flex: none; }

/* The lift under a primary is tinted with its own colour rather than grey, so
   the button reads as sitting above the field instead of stamped onto it. */
.btn--primary {
  background: var(--accent); color: #fff;
  box-shadow: var(--shadow-sm), 0 6px 16px -8px rgba(187, 32, 49, .5);
}
.btn--primary:hover { background: var(--accent-dark); }

.btn--ink {
  background: var(--ink); color: #fff;
  box-shadow: var(--shadow-sm), 0 6px 16px -8px rgba(16, 24, 32, .45);
}
.btn--ink:hover { background: var(--ink-3); }

/* Ghost is glass, so it belongs on the field rather than fighting it — with a
   real background behind the blur for browsers without one. */
.btn--ghost {
  background: rgba(255, 255, 255, .72); color: var(--ink);
  border-color: rgba(16, 24, 32, .14);
  backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
}
.btn--ghost:hover { background: rgba(255, 255, 255, .96); border-color: var(--mist); }

.btn--quiet { background: transparent; color: var(--steel); }
.btn--quiet:hover { background: var(--hair-soft); color: var(--ink); }

/* Destructive. Deliberately NOT the accent — see the role tokens. */
.btn--danger { background: var(--card); color: var(--danger); border-color: #EBC9CC; }
.btn--danger:hover { background: var(--danger-lt); border-color: var(--danger); }
.btn--danger-solid {
  background: var(--danger); color: #fff;
  box-shadow: var(--shadow-sm), 0 6px 16px -8px rgba(142, 31, 39, .5);
}
.btn--danger-solid:hover { background: var(--danger-dark); }

.btn--sm { height: 30px; padding: 0 11px; font-size: 12.5px; }
.btn--sm svg { width: 13px; height: 13px; }
.btn--icon { width: 34px; padding: 0; }
.btn--icon.btn--sm { width: 28px; }
.btn--block { width: 100%; }
.btn:disabled { opacity: .45; pointer-events: none; }

/* ---- Form controls ----------------------------------------------------- */
.field { display: flex; flex-direction: column; gap: 6px; }
.field > label,
.label {
  font-family: var(--f-display);
  font-size: 11px; font-weight: 600; letter-spacing: .09em;
  text-transform: uppercase; color: var(--steel);
}
.input, .select, .textarea {
  width: 100%;
  min-height: 38px;
  padding: 8px 11px;
  background: var(--card);
  border: 1px solid var(--hair);
  border-radius: var(--r);
  font-size: 14px;
  color: var(--ink);
  transition: border-color .14s ease, box-shadow .14s ease;
}
.input::placeholder, .textarea::placeholder { color: var(--steel-lt); }
.input:hover, .select:hover, .textarea:hover { border-color: var(--mist); }
.input:focus, .select:focus, .textarea:focus {
  outline: none;
  border-color: var(--ink);
  box-shadow: 0 0 0 3px rgba(16, 24, 32, .07);
}
.textarea { min-height: 88px; resize: vertical; line-height: 1.55; }
.select {
  appearance: none;
  padding-right: 32px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%235C6871' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 6.5 8 10.5 12 6.5'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 10px center;
  background-size: 15px;
}
.input--err, .select--err, .textarea--err { border-color: var(--crimson); }
.err-msg { color: var(--crimson); font-size: 12px; }
.hint { font-size: 12px; color: var(--steel-lt); }

.check { display: flex; align-items: flex-start; gap: 9px; cursor: pointer; }
.check input { width: 16px; height: 16px; margin: 2px 0 0; accent-color: var(--crimson); flex: none; }

.search {
  position: relative; display: flex; align-items: center;
}
.search svg { position: absolute; left: 11px; width: 15px; height: 15px; color: var(--steel-lt); pointer-events: none; }
.search .input { padding-left: 33px; }

.grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
.grid-3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px; }
/* Was referenced by the Cost analysis basis row long before it existed here,
   so those four fields stacked one per line. */
.grid-4 { display: grid; grid-template-columns: repeat(4, 1fr); gap: 14px; }
@media (max-width: 760px) { .grid-4 { grid-template-columns: 1fr 1fr; } }
.span-2 { grid-column: 1 / -1; }

/* Page-level two-column layouts. These live in CSS rather than inline styles
   so the mobile media query can collapse them — an inline
   grid-template-columns would win over any stylesheet rule and leave phones
   with an unreadable sliver of a column. */
.split { display: grid; gap: 16px; align-items: start; }
.split--main-left  { grid-template-columns: minmax(0, 1.4fr)  minmax(0, 1fr); }
.split--main-right { grid-template-columns: minmax(0, .85fr)  minmax(0, 1.15fr); }
.split--form       { grid-template-columns: minmax(0, 1.55fr) minmax(0, 1fr); }
.split--table      { grid-template-columns: minmax(0, 1.6fr)  minmax(0, 1fr); }
.split--profile    { grid-template-columns: minmax(0, 1.25fr) minmax(0, 1fr); }
.split--even       { grid-template-columns: minmax(0, 1fr)    minmax(0, 1fr); }

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

.rail {
  width: var(--rail); flex: none;
  /* A gradient rather than a flat slab: at full height a single ink fill goes
     dead about two thirds down, and the portal's tallest element is the one
     the eye rests against all day. */
  background: linear-gradient(172deg, var(--ink-2) 0%, var(--ink) 100%);
  color: #fff;
  display: flex; flex-direction: column;
  position: sticky; top: 0; height: 100vh;
  z-index: 40;
}
.rail__brand {
  padding: 22px 20px 18px;
  border-bottom: 1px solid rgba(255,255,255,.09);
}
.rail__logo-full { width: 152px; }
/* The chip logomark only appears when the rail is collapsed (desktop). */
.rail__logo-mark { display: none; width: 30px; }
.rail__role {
  margin-top: 11px;
  display: inline-flex; align-items: center; gap: 6px;
  font-family: var(--f-display);
  font-size: 9.5px; font-weight: 600; letter-spacing: .16em; text-transform: uppercase;
  color: rgba(255,255,255,.55);
}
.rail__role::before {
  content: ""; width: 5px; height: 5px; border-radius: 50%;
  background: var(--crimson);
}
.rail__nav { flex: 1 1 auto; overflow-y: auto; padding: 14px 12px 20px; }
.rail__nav::-webkit-scrollbar { width: 8px; }
.rail__nav::-webkit-scrollbar-thumb { background: rgba(255,255,255,.13); border-radius: 4px; }

.navgroup + .navgroup { margin-top: 20px; }
.navgroup__label {
  padding: 0 10px 8px;
  font-family: var(--f-display);
  font-size: 9.5px; font-weight: 600; letter-spacing: .18em; text-transform: uppercase;
  color: rgba(255,255,255,.36);
}
.navitem {
  position: relative;
  display: flex; align-items: center; gap: 11px;
  width: 100%;
  padding: 10px 12px;
  border-radius: 10px;
  font-size: 13.5px; font-weight: 500;
  color: rgba(255,255,255,.74);
  transition: background-color .14s ease, color .14s ease;
}
.navitem svg { width: 16px; height: 16px; flex: none; opacity: .82; }
.navitem:hover { background: rgba(255,255,255,.08); color: #fff; }
/* A tint of the accent with an inset hairline, not a solid slab: at full
   strength on ink it reads as a button somebody forgot to remove. */
.navitem.is-active {
  background: rgba(187, 32, 49, .26); color: #fff; font-weight: 600;
  box-shadow: inset 0 0 0 1px rgba(187, 32, 49, .42);
}
.navitem.is-active::before {
  content: ""; position: absolute; left: -12px; top: 50%; transform: translateY(-50%);
  width: 3px; height: 19px; background: var(--crimson); border-radius: 0 2px 2px 0;
}
.navitem__badge {
  margin-left: auto;
  min-width: 19px; height: 18px; padding: 0 5px;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--crimson); color: #fff;
  border-radius: 9px;
  font-family: var(--f-mono); font-size: 10.5px; font-weight: 500;
}

.rail__foot { padding: 14px 12px; border-top: 1px solid rgba(255,255,255,.09); }
.railuser { display: flex; align-items: center; gap: 10px; width: 100%; padding: 7px 8px; border-radius: var(--r); transition: background-color .14s ease; }
.railuser:hover { background: rgba(255,255,255,.07); }
.railuser__meta { min-width: 0; text-align: left; }
/* Both are spans, so they need to be blocks to stack instead of running on. */
.railuser__name,
.railuser__sub { display: block; }
.railuser__name { font-size: 13px; font-weight: 600; color: #fff; }
.railuser__sub { font-size: 11px; color: rgba(255,255,255,.5); }

/* ---- Mail thread (an account's Email tab) ------------------------------- */

/* A transcript, not an inbox. Oldest at the top and the newest at the bottom,
   so reading downwards ends where the conversation actually is. The merchant's
   messages sit left and the agent's sit right, the way every messaging app has
   taught everybody to read a conversation — but wider than a chat bubble,
   because these are emails and a paragraph in a 300px column is unreadable. */

.thread {
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.mail {
  align-self: flex-start;
  max-width: min(78%, 760px);
  background: var(--card);
  border: 1px solid var(--hair);
  border-radius: 12px 12px 12px 4px;
  padding: 12px 14px;
}

/* The agent's own, mirrored. Tinted rather than crimson: a wall of brand
   colour behind body text is unreadable, and the side already says whose it
   is. */
.mail--out {
  align-self: flex-end;
  /* --paper, not a brand tint. A wall of crimson behind body text is
     unreadable, and the side of the column already says whose message it is.
     This also survives white-labelling: an ISO's palette overwrites --crimson
     at boot, and a thread should not change legibility with it. */
  background: var(--paper);
  border-radius: 12px 12px 4px 12px;
}

.mail__head {
  display: flex;
  align-items: baseline;
  gap: 10px;
  font-size: 12.5px;
  color: var(--steel);
}
.mail__who { font-weight: 600; color: var(--ink); }
.mail__when { flex: none; white-space: nowrap; }
.mail__clip { flex: none; display: inline-flex; color: var(--steel); }

.mail__subject {
  margin-top: 4px;
  font-size: 13.5px;
  font-weight: 600;
  color: var(--ink);
}

/* white-space: pre-wrap is what makes a plain-text mail body keep the shape
   its author gave it. The bodies arrive as text on purpose (Graph is asked for
   text, see api/ms-mail.js), so there is no markup here to render and none is
   rendered — this element is filled with textContent and nothing else. */
.mail__text {
  margin-top: 7px;
  font-size: 14px;
  line-height: 1.55;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  color: var(--ink);
}

.mail__open {
  display: inline-block;
  margin-top: 9px;
  font-size: 12.5px;
  color: var(--crimson);
}

@media (max-width: 720px) {
  .mail { max-width: 92%; }
}

/* ---- Collapsed rail (desktop only — the mobile drawer stays full width) -- */
.rail__collapse { display: none; }

/* Floating label for collapsed icons. Fixed and on <body>: .rail__nav scrolls,
   so anything positioned inside it would be clipped at the rail edge. */
.railtip {
  position: fixed; z-index: 90;
  transform: translateY(-50%);
  padding: 5px 10px;
  background: var(--ink); color: #fff;
  border-radius: var(--r);
  font-size: 12px; font-weight: 500; white-space: nowrap;
  box-shadow: 0 4px 14px rgba(16,24,32,.25);
  pointer-events: none;
  opacity: 0; transition: opacity .1s ease;
}
.railtip.is-on { opacity: 1; }

@media (min-width: 901px) {
  .rail { transition: width .22s cubic-bezier(.22,.7,.3,1); }

  .rail__collapse {
    position: absolute; right: -12px; top: 26px; z-index: 41;
    width: 24px; height: 24px;
    display: inline-flex; align-items: center; justify-content: center;
    background: var(--ink); color: rgba(255,255,255,.75);
    border: 1px solid rgba(255,255,255,.18);
    border-radius: 50%;
    box-shadow: 0 2px 8px rgba(16,24,32,.3);
    transition: color .14s ease, background-color .14s ease;
  }
  .rail__collapse:hover { color: #fff; background: var(--ink-3); }
  .rail__collapse svg { transition: transform .22s ease; }
  .rail.is-collapsed .rail__collapse svg { transform: rotate(180deg); }

  .rail.is-collapsed { width: 68px; }

  .rail.is-collapsed .rail__brand { padding: 20px 0 16px; text-align: center; }
  .rail.is-collapsed .rail__logo-full,
  .rail.is-collapsed .rail__role { display: none; }
  .rail.is-collapsed .rail__logo-mark { display: inline-block; }

  /* Group names have nowhere to go at 68px; a hairline keeps the grouping. */
  .rail.is-collapsed .navgroup__label { display: none; }
  .rail.is-collapsed .navgroup + .navgroup {
    margin-top: 12px; padding-top: 12px;
    border-top: 1px solid rgba(255,255,255,.09);
  }

  .rail.is-collapsed .navitem { justify-content: center; gap: 0; padding: 10px 0; }
  .rail.is-collapsed .navitem > .grow { display: none; }
  /* The overdue count has no room for a number; it becomes a dot on the icon. */
  .rail.is-collapsed .navitem__badge {
    position: absolute; top: 5px; right: 14px;
    min-width: 7px; width: 7px; height: 7px; padding: 0;
    border-radius: 50%;
    font-size: 0; margin-left: 0;
  }

  .rail.is-collapsed .rail__foot { padding: 14px 8px; }
  .rail.is-collapsed .railuser { justify-content: center; gap: 0; padding: 7px 0; }
  .rail.is-collapsed .railuser__meta,
  .rail.is-collapsed .railuser > svg { display: none; }
}

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

.topbar {
  height: var(--topbar);
  flex: none;
  display: flex; align-items: center; gap: 16px;
  padding: 0 28px;
  /* Chrome, and sticky over scrolling content — the one place glass earns its
     keep most obviously, because there is always something moving under it. */
  background: var(--glass-bg);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  border-bottom: 1px solid rgba(16, 24, 32, .07);
  position: sticky; top: 0; z-index: 30;
}
/* The title must clip rather than run underneath the action buttons when the
   bar gets tight — min-width alone doesn't stop text from painting over. */
.topbar__title { min-width: 0; overflow: hidden; }
.topbar__title .h1,
.topbar__title .eyebrow { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.topbar > .row { flex: none; }
.view { padding: 26px 28px 64px; max-width: 1400px; width: 100%; }

/* ---- Avatars ----------------------------------------------------------- */
.avatar {
  flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  width: 32px; height: 32px;
  border-radius: var(--r);
  background: var(--ink-3); color: #fff;
  font-family: var(--f-display); font-size: 12px; font-weight: 700; letter-spacing: .01em;
}
.avatar--sm { width: 24px; height: 24px; font-size: 10px; border-radius: var(--r-sm); }
.avatar--lg { width: 44px; height: 44px; font-size: 15px; }

/* ---- Panels ------------------------------------------------------------ */
/* Panels hold forms, tables and paragraphs — dense text — so they are solid,
   not glass. See the note on the glass tokens. */
/* The aura rather than the flat card shadow: two grey layers for lift and a
   third tinted with the accent. On a pale field a flat shadow reads as a
   rectangle cut out of the page; this reads as an object on it. Changed here
   rather than per screen, so all 99 panels in the admin views and every other
   panel in the portal pick it up at once. */
.panel {
  background: var(--solid-bg);
  border: 1px solid var(--hair);
  border-radius: var(--r);
  box-shadow: var(--aura);
}
.panel__head {
  display: flex; align-items: center; gap: 12px;
  padding: 14px 18px;
  border-bottom: 1px solid var(--hair-soft);
}
.panel__body { padding: 18px; }
.panel__body--flush { padding: 0; }
.panel__foot { padding: 12px 18px; border-top: 1px solid var(--hair-soft); }

/* Stat strip — chrome rather than content: four numbers and their labels, no
   dense text. So this one is glass, and it is the clearest place on a
   dashboard to see the field showing through. */
.stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  background: var(--glass-bg);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  border: 1px solid var(--glass-brd);
  border-radius: var(--r);
  overflow: hidden;
  box-shadow: var(--shadow-card);
}
.stat { padding: 15px 18px 16px; border-right: 1px solid rgba(16, 24, 32, .07); }
.stat:last-child { border-right: 0; }
.stat__val {
  font-variant-numeric: tabular-nums;
  font-size: 26px; font-weight: 600; letter-spacing: -.02em;
  margin-top: 6px;
  line-height: 1.1;
}
.stat__val--crimson { color: var(--accent); }
.stat__sub { margin-top: 5px; font-size: 12px; color: var(--steel-lt); }

/* ---- Tables ------------------------------------------------------------ */
.tbl { font-size: 13.5px; }
/* Columns that share the width evenly instead of sizing to their widest
   cell. Added 2026-09-22 for the statement history on Residuals, where the
   auto-sized columns bunched to the left once the Statement column went. */
.tbl--even { width: 100%; table-layout: fixed; }
/* An ink header band rather than a hairline under grey capitals: on a long
   residual statement it is what tells you where the figures start when the
   page is scrolled halfway down. */
.tbl th {
  text-align: left;
  padding: 11px 14px;
  font-family: var(--f-display);
  font-size: 10px; font-weight: 700; letter-spacing: .09em; text-transform: uppercase;
  color: #fff;
  border-bottom: 0;
  background: var(--ink);
  white-space: nowrap;
}
.tbl th:first-child { border-top-left-radius: var(--r-sm); }
.tbl th:last-child { border-top-right-radius: var(--r-sm); }
/* `.tbl th` is more specific than the .right/.center utilities, so without
   these a numeric column's heading sits left while its figures sit right. */
.tbl th.right  { text-align: right; }
.tbl th.center { text-align: center; }
/* Uppercase headings carry a .12em tracking space after their last letter.
   Right-aligned, that trailing space is what meets the column edge and the
   heading reads a hair left of the numbers under it — take it back. */
.tbl th.right { padding-right: calc(14px - .12em); }
.tbl th.is-sortable { cursor: pointer; user-select: none; }
.tbl th.is-sortable:hover { color: rgba(255, 255, 255, .78); }
.tbl th .sortmark { display: inline-block; margin-left: 4px; opacity: .7; }
.tbl td { padding: 12px 14px; border-bottom: 1px solid var(--hair-soft); vertical-align: middle; }
/* Banding does the work hairlines used to: at statement length the eye keeps
   its row across twelve columns without a rule under every one of them. */
.tbl tbody tr:nth-child(even) { background: var(--paper); }
.tbl tbody tr:last-child td { border-bottom: 0; }
.tbl tbody tr.is-clickable { cursor: pointer; }
.tbl tbody tr.is-clickable:hover { background: var(--accent-tint); }
/* A row that is itself the filter the page is showing — the month picked on
   Ticket reports. Beats the :nth-child banding on specificity, which is the
   whole point: on an even row the tint alone was invisible. The bar on the
   left is what carries it at a glance; the tint on its own reads as hover. */
.tbl tbody tr.is-selected,
.tbl tbody tr.is-selected:nth-child(even) { background: var(--accent-tint); }
.tbl tbody tr.is-selected td:first-child { box-shadow: inset 3px 0 0 var(--crimson); }
/* The same state on a bar row (.funnel-row), which is not a table. */
.funnel-row.is-selected .funnel-row__name { font-weight: 700; }

/* ---- Heat grid — Ticket reports ---------------------------------------
   Months across, people down. One object answers two of the three questions
   the report exists for, and the ground answers the third.

   THE COLOUR IS TIME OPEN, NOT VOLUME. That is the whole design and it is the
   easy thing to get backwards: shaded by count, the person who closed the most
   work is the reddest cell on the screen, and a report that paints your best
   month as the problem is worse than no report. Volume is the FIGURE; speed is
   the ground it sits on. A busy month that moved fast stays green.

   Buckets are absolute rather than relative to the desk's own median, so the
   grid means the same thing in January as in June — a service desk improving
   over a year should be able to watch the red drain out of it. */
.heat { display: grid; gap: 4px; min-width: 700px; }
.heat__h {
  padding: 0 10px 5px;
  text-align: right;
  font-size: 11.5px; font-weight: 600;
  color: var(--steel-lt);
  white-space: nowrap;
}
/* The month in progress. It is the one column still being written, and the
   Tickets board is still holding its closures — worth marking. */
.heat__h--now { color: var(--accent); }
.heat__h:hover { color: var(--ink); }
.heat__h.is-on { color: var(--ink); text-decoration: underline; text-underline-offset: 3px; }
/* The person's name, when the whole row is the filter. */
.heat__name--on { text-decoration: underline; text-underline-offset: 3px; }
.heat__rowhead { display: flex; align-items: center; gap: 8px; padding-right: 10px; min-width: 0; }

/* Every cell is a filter, which is why these are buttons and not divs: the
   grid is a control surface, and a control surface has to be reachable from
   the keyboard. */
.heat__cell {
  display: block; width: 100%;
  border: 0; border-radius: 9px;
  padding: 9px 11px 10px;
  text-align: left;
  font-family: var(--f-mono); font-variant-numeric: tabular-nums;
  transition: transform .12s ease, box-shadow .12s ease;
}
.heat__cell:hover { transform: translateY(-1px); box-shadow: var(--shadow-sm); }
.heat__cell:disabled { cursor: default; }
.heat__cell:disabled:hover { transform: none; box-shadow: none; }
.heat__cell.is-on { box-shadow: 0 0 0 2px var(--ink); }
.heat__n { display: block; font-size: 18px; font-weight: 600; letter-spacing: -.02em; line-height: 1.15; }
.heat__k {
  display: block; margin-top: 2px;
  font-family: var(--f-mono); font-variant-numeric: tabular-nums;
  font-size: 10px; font-weight: 500; letter-spacing: -.01em;
  opacity: .8;
}

/* The four speeds and the two totals. Crimson is reserved for the slowest
   bucket the same way it is everywhere else in the portal — the loudest thing
   on screen, spent once. */
.heat--fast  { background: var(--green-lt);   color: var(--green); }
.heat--ok    { background: var(--blue-lt);    color: var(--blue); }
.heat--slow  { background: var(--amber-lt);   color: var(--amber); }
.heat--worst { background: var(--danger-lt);  color: var(--danger); }
.heat--none  { background: var(--hair-soft);  color: var(--steel-lt); }
.heat--tot   { background: var(--ink-3);      color: #fff; }
.heat--tot .heat__k, .heat--grand .heat__k { opacity: .6; }
.heat--grand { background: var(--ink);        color: #fff; }

.heat__scale {
  width: 72px; height: 9px; border-radius: 5px;
  border: 1px solid var(--hair);
  background: linear-gradient(90deg, var(--green-lt), var(--blue-lt), var(--amber-lt), var(--danger-lt));
}
.tbl__scroll { overflow-x: auto; }
.tbl tfoot td {
  background: var(--paper);
  border-top: 1px solid var(--hair); border-bottom: 0;
  font-family: var(--f-display); color: var(--ink);
}

/* ---- Badges & pills ---------------------------------------------------- */
.badge {
  display: inline-flex; align-items: center; gap: 5px;
  height: 22px; padding: 0 10px;
  border-radius: 999px;
  font-family: var(--f-display);
  font-size: 10.5px; font-weight: 700; letter-spacing: .02em;
  white-space: nowrap;
}
.badge::before { content: ""; width: 5px; height: 5px; border-radius: 50%; background: currentColor; flex: none; }
.badge--no-dot::before { display: none; }
.badge--gray  { background: var(--hair-soft); color: var(--steel); }
.badge--green { background: var(--green-lt); color: var(--green); }
.badge--amber { background: var(--amber-lt); color: var(--amber); }

/* A caution inside a form or a preview: something has been guessed, or the
   inputs disagree, and the person is about to commit to it. Amber rather than
   crimson — crimson in this design means an error or money, and this is
   neither. Deliberately not `.note`, which carries no styling of its own and
   is used for neutral asides. */
.note-warn {
  padding: 9px 11px;
  border: 1px solid #EBDCB6;
  border-left: 3px solid var(--amber);
  border-radius: var(--r-sm);
  background: var(--amber-lt);
  color: #6E4E11;
  line-height: 1.5;
}
.badge--blue  { background: var(--blue-lt);  color: var(--blue); }
.badge--red   { background: var(--crimson-lt); color: var(--crimson); }
.badge--ink   { background: var(--ink); color: #fff; }

.chip {
  display: inline-flex; align-items: center; gap: 6px;
  height: 28px; padding: 0 11px;
  border: 1px solid var(--hair);
  border-radius: 14px;
  background: var(--card);
  font-size: 12.5px; font-weight: 500; color: var(--steel);
  transition: border-color .14s ease, color .14s ease, background-color .14s ease;
}
.chip:hover { border-color: var(--mist); color: var(--ink); }
.chip.is-on { background: var(--ink); border-color: var(--ink); color: #fff; }

/* A SECOND RANK OF CHIPS, for navigation that only exists inside a tab. Smaller
   and lighter when chosen, so a nested choice never competes with the tab it
   sits under — two rows of identical chips read as one confusing row of six. */
.chip--sm { height: 24px; padding: 0 9px; font-size: 11.5px; border-radius: 12px; }
.chip--sm.is-on {
  background: var(--paper); border-color: var(--mist);
  color: var(--ink); font-weight: 600;
}

/* ---- Tabs -------------------------------------------------------------- */
/* Pills on the field rather than an underlined strip: the underline needed a
   hairline rule to sit on, and there are no hairline rules left to sit on. */
.tabs { display: flex; gap: 6px; flex-wrap: wrap; }
.tab {
  position: relative;
  padding: 7px 14px;
  border-radius: 999px;
  background: rgba(255, 255, 255, .72);
  border: 1px solid var(--hair);
  font-family: var(--f-display);
  font-size: 12.5px; font-weight: 600;
  color: var(--steel);
  transition: color .14s ease, background-color .14s ease, border-color .14s ease;
}
.tab:hover { color: var(--ink); background: #fff; }
.tab.is-on { color: #fff; background: var(--ink); border-color: var(--ink); }
.tab.is-on .tab__count { color: rgba(255, 255, 255, .7); }
.tab__count { margin-left: 6px; color: var(--steel-lt); font-family: var(--f-mono); font-size: 11.5px; }

/* ---- Dotted leader — the receipt detail -------------------------------- */
.leader { display: flex; align-items: baseline; gap: 8px; }
.leader__label { color: var(--steel); flex: none; }
.leader__dots {
  flex: 1 1 auto;
  border-bottom: 1px dotted var(--mist);
  transform: translateY(-3px);
  min-width: 16px;
}
.leader__val { flex: none; font-family: var(--f-mono); font-variant-numeric: tabular-nums; }

/* ---- Statement stub — the signature element ---------------------------- */
.stub {
  position: relative;
  background: var(--card);
  border: 1px solid var(--hair);
  border-top: 0;
  border-radius: 0 0 var(--r-lg) var(--r-lg);
  padding: 30px 30px 26px;
  box-shadow: var(--aura);
}
/* Perforated tear edge along the top */
.stub__perf {
  height: 9px;
  background:
    radial-gradient(circle at 5px 0, transparent 4.5px, var(--hair) 4.5px, var(--hair) 5.4px, var(--card) 5.4px) 0 0 / 10px 9px repeat-x;
  border: 1px solid var(--hair);
  border-bottom: 0;
  border-radius: var(--r-lg) var(--r-lg) 0 0;
  position: relative;
}
.stub__rule { height: 3px; background: var(--crimson); }
.stub__amount {
  font-family: var(--f-mono);
  font-variant-numeric: tabular-nums;
  font-size: clamp(38px, 6vw, 56px);
  font-weight: 500;
  letter-spacing: -.045em;
  line-height: 1;
  color: var(--ink);
}
.stub__lines { display: flex; flex-direction: column; gap: 9px; font-size: 13.5px; }
.stub__total {
  margin-top: 14px; padding-top: 14px;
  border-top: 1px solid var(--ink);
  font-weight: 700;
}
.stub__total .leader__label { color: var(--ink); font-weight: 700; }
.stub__watermark {
  position: absolute; right: 26px; bottom: 20px;
  width: 92px; opacity: .05; pointer-events: none;
}

/* ---- Pipeline (kanban) ------------------------------------------------- */
.board {
  display: grid;
  grid-auto-flow: column;
  /* 210px keeps all five stages on screen at laptop width — seeing the whole
     cycle at once is the point of the board. */
  grid-auto-columns: minmax(210px, 1fr);
  gap: 12px;
  overflow-x: auto;
  padding-bottom: 12px;
  align-items: start;
}
.lane {
  background: #EFF1F2;
  border: 1px solid var(--hair);
  border-radius: var(--r-lg);
  display: flex; flex-direction: column;
  min-height: 180px;
  transition: background-color .16s ease, border-color .16s ease;
}
.lane.is-over { background: var(--crimson-lt); border-color: #EBB9BF; }
.lane__head { padding: 12px 13px 10px; }
.lane__topline { display: flex; align-items: center; gap: 8px; }
.lane__seq {
  font-family: var(--f-mono); font-size: 11px; color: var(--steel-lt);
  font-variant-numeric: tabular-nums;
}
.lane__name { font-family: var(--f-display); font-size: 12.5px; font-weight: 700; letter-spacing: -.005em; }
.lane__count { margin-left: auto; font-family: var(--f-mono); font-size: 11.5px; color: var(--steel); }
.lane__bar { height: 2px; margin-top: 9px; background: var(--mist); border-radius: 1px; overflow: hidden; }
/* Ink by default — crimson is held back for the boarded lane, so the eye lands
   on the stage that actually pays. */
.lane__bar span { display: block; height: 100%; background: var(--ink-3); }
.lane--won .lane__bar span { background: var(--crimson); }
.lane--won .lane__name { color: var(--crimson); }

/* Closed / Lost sits outside the cycle, so it reads as an archive rather than
   a step: muted, dashed, and visually separated from the five live stages. */
.lane--lost {
  background: transparent;
  border-style: dashed;
  border-color: var(--mist);
}
.lane--lost .lane__name { color: var(--steel); }
.lane--lost .lane__bar span { background: var(--steel-lt); }
.lane--lost .dealcard { background: #FCFCFC; border-style: dashed; }
.lane--lost .dealcard__biz { color: var(--steel); }

/* Banner shown in the account drawer in place of the stage stepper. */
.loststrip {
  display: flex; align-items: center; gap: 12px;
  padding: 12px 14px;
  border: 1px dashed var(--mist);
  border-left: 3px solid var(--steel);
  border-radius: var(--r);
  background: var(--hair-soft);
  color: var(--steel);
}
.loststrip svg { color: var(--steel); flex: none; }
.lane__sum { margin-top: 8px; font-family: var(--f-mono); font-size: 11.5px; color: var(--steel); font-variant-numeric: tabular-nums; }
.lane__cards { padding: 0 9px 9px; display: flex; flex-direction: column; gap: 8px; }
.lane__empty {
  margin: 0 9px 9px; padding: 18px 10px;
  border: 1px dashed var(--mist); border-radius: var(--r);
  text-align: center; font-size: 12px; color: var(--steel-lt);
}

.dealcard {
  background: var(--card);
  border: 1px solid var(--hair);
  border-radius: var(--r);
  padding: 11px 12px;
  cursor: grab;
  transition: box-shadow .14s ease, border-color .14s ease, transform .14s ease;
}
.dealcard:hover { border-color: var(--mist); box-shadow: var(--shadow-card); }
.dealcard:active { cursor: grabbing; }
.dealcard.is-dragging { opacity: .4; }
.dealcard__biz { font-family: var(--f-display); font-size: 13.5px; font-weight: 700; letter-spacing: -.01em; }
.dealcard__contact { margin-top: 2px; font-size: 12px; color: var(--steel); }
.dealcard__foot {
  margin-top: 10px; padding-top: 9px;
  border-top: 1px solid var(--hair-soft);
  display: flex; align-items: center; gap: 8px;
}
.dealcard__vol { font-family: var(--f-mono); font-size: 12px; font-weight: 500; font-variant-numeric: tabular-nums; }
.dealcard__age { margin-left: auto; font-size: 11px; color: var(--steel-lt); }
.dealcard__flag { color: var(--crimson); }

/* ---- Pipeline: the aurora field and the flight deck --------------------
   The board stops being six grey boxes on the page and becomes glass lanes
   floating on a soft field of their own.

   WHY THE FIELD EXISTS. Glass needs something behind it or it is just a pale
   panel — the whole point of a frosted surface is what shows through. The page
   background is a still slate wash and the lanes sat directly on it, so the
   blur had nothing to do. This gives them a ground with colour in it: cool at
   the top of the funnel, warm at the close, which is also the direction of
   travel.

   The card stays near-opaque white. It is the one thing on this screen anybody
   reads closely, and the stylesheet's rule about where glass stops applies to
   it exactly as it applies everywhere else. */
.aurora {
  position: relative;
  border-radius: var(--r-lg);
  padding: 16px;
  overflow: hidden;
  background:
    radial-gradient(420px 220px at 8% 30%,  rgba(94, 150, 214, .30), rgba(94, 150, 214, 0) 70%),
    radial-gradient(420px 240px at 42% 70%, rgba(120, 196, 168, .28), rgba(120, 196, 168, 0) 70%),
    radial-gradient(460px 240px at 78% 24%, rgba(214, 120, 140, .30), rgba(214, 120, 140, 0) 70%),
    linear-gradient(180deg, #F2F5F9, #E4EBF2);
  border: 1px solid var(--glass-brd);
}
/* The board inside the field scrolls on its own, so the field does not have to
   grow a scrollbar of its own. */
.aurora > .board { overflow-x: auto; padding-bottom: 4px; }

.board--aurora .lane {
  background: rgba(255, 255, 255, .42);
  backdrop-filter: blur(22px) saturate(170%);
  -webkit-backdrop-filter: blur(22px) saturate(170%);
  border-color: rgba(255, 255, 255, .78);
  box-shadow: 0 1px 2px rgba(16, 24, 32, .05), 0 18px 46px -24px rgba(16, 24, 32, .45);
}
/* The drop target has to survive the blur — at 42% white a crimson tint alone
   was almost invisible, so this one leans on the border and a lift. */
.board--aurora .lane.is-over {
  background: rgba(253, 236, 238, .72);
  border-color: #EBB9BF;
  box-shadow: 0 1px 2px rgba(16, 24, 32, .05), 0 20px 50px -22px rgba(187, 32, 49, .55);
}
.board--aurora .lane--lost {
  background: rgba(255, 255, 255, .2);
  border-color: rgba(255, 255, 255, .6);
}
.board--aurora .dealcard {
  background: rgba(255, 255, 255, .88);
  border-color: rgba(255, 255, 255, .92);
}
.board--aurora .lane--lost .dealcard { background: rgba(255, 255, 255, .6); }
.board--aurora .lane__empty { border-color: rgba(255, 255, 255, .75); color: var(--steel); }

/* ---- The flight deck: one glass bar for everything that is not the board -
   The orbit anchors the left, the pills fill the right. Both are chrome, so
   both are glass; they sit in ONE surface rather than two so the top of the
   page reads as a single instrument rather than a row of widgets. */
.deck {
  display: flex; align-items: center; gap: 18px;
  padding: 12px 16px;
  border-radius: var(--r-lg);
  background: rgba(255, 255, 255, .55);
  backdrop-filter: blur(16px) saturate(160%);
  -webkit-backdrop-filter: blur(16px) saturate(160%);
  border: 1px solid rgba(255, 255, 255, .8);
  box-shadow: var(--shadow-card);
}
.deck__orbit { flex: none; width: 96px; height: 96px; display: block; }
.deck__read {
  flex: none; max-width: 132px;
  padding-right: 16px;
  border-right: 1px solid rgba(16, 24, 32, .1);
}

/* Info pills. A label and a figure, and a dot that carries state so the row
   can be read without being read. */
.pills { display: flex; flex-wrap: wrap; gap: 8px; align-items: stretch; }
.pill {
  display: flex; align-items: center; gap: 9px;
  padding: 7px 14px 8px;
  border-radius: 999px;
  background: rgba(255, 255, 255, .55);
  border: 1px solid rgba(255, 255, 255, .7);
  white-space: nowrap;
}
.pill__dot { width: 7px; height: 7px; border-radius: 50%; flex: none; background: var(--steel-lt); }
.pill__dot--good { background: var(--green); }
.pill__dot--warn { background: var(--amber); }
.pill__dot--hot  { background: var(--accent); }
.pill__label {
  display: block; line-height: 1.3;
  font-family: var(--f-display);
  font-size: 9.5px; font-weight: 600; letter-spacing: .14em; text-transform: uppercase;
  color: var(--steel-lt);
}
.pill__value {
  display: block; line-height: 1.15;
  font-family: var(--f-mono); font-variant-numeric: tabular-nums;
  font-size: 16px; font-weight: 600; letter-spacing: -.02em;
  color: var(--ink);
}
/* Only drawn when something is actually stalling, so the colour always means
   something. */
.pill--alert { background: rgba(253, 236, 238, .72); border-color: rgba(235, 185, 191, .9); }
.pill--alert .pill__value { color: var(--crimson-dk); }
.pill--alert .pill__label { color: var(--accent); }

@media (max-width: 900px) {
  .deck { flex-wrap: wrap; gap: 12px; }
  .deck__read { border-right: 0; padding-right: 0; max-width: none; }
  .aurora { padding: 10px; }
}

/* ---- Dashboard: the aura and the under-glow ----------------------------
   Adapted from the white-ground model used on the OnSight side, kept on this
   portal's aurora field rather than on white so the Dashboard, Pipeline and
   Accounts read as one product.

   THE AURA is a three-layer shadow whose third layer is tinted with the
   accent. Two grey layers give a card its lift; the tinted one is what stops
   it looking like flat paper cut out of the page. It is the whole reason a
   white card on a pale field still reads as an object.

   One restraint carried over from the rest of this file: in the source system
   the accent is the everyday hue and glows under half the tiles. Crimson is
   not that here — it is the loudest thing on screen, spent once — so crimson
   lights the money and the single thing needing a decision, and the state
   tiles glow in their own semantic colours instead. */
:root {
  --aura:
    0 1px 2px rgba(16, 24, 32, .06),
    0 10px 26px -12px rgba(16, 24, 32, .40),
    0 2px 8px -4px rgba(187, 32, 49, .16);
  --aura-o: .15;
}

.dashrow { display: grid; grid-template-columns: minmax(0, 1.35fr) minmax(0, .65fr); gap: 16px; }
.dashcard {
  background: var(--card);
  border: 1px solid var(--hair);
  border-radius: var(--r);
  box-shadow: var(--aura);
  padding: 18px 20px;
}
.dashcard--flush { padding: 0; }
.dash__n {
  font-family: var(--f-mono); font-variant-numeric: tabular-nums;
  font-size: 40px; font-weight: 600; letter-spacing: -.035em; line-height: 1.02;
  margin-top: 6px; color: var(--accent);
}
.dash__sub { margin-top: 8px; font-size: 13px; color: var(--steel); }
.dash__sparkwrap { margin-top: 14px; }
.dash__spark { display: block; width: 100%; height: 40px; }
/* The bars carried no label at all — eight grey rectangles under a dollar
   figure. This says what they measure and over what span; the key below says
   why one of them is crimson. */
.dash__sparkcap {
  display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap;
  margin-top: 7px; padding-top: 7px;
  border-top: 1px solid var(--hair-soft);
  font-size: 11.5px; color: var(--steel);
}
.dash__sparkcap .mono { font-variant-numeric: tabular-nums; color: var(--steel-lt); }
.dash__sparkkey {
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
  margin-top: 5px; font-size: 11px; color: var(--steel-lt);
}
.dash__sparkkey span { margin-right: 6px; }
.dash__dot {
  flex: none; width: 7px; height: 7px; border-radius: 2px;
  background: var(--mist); display: inline-block;
}
.dash__dot--now { background: var(--accent); }

/* The one thing that needs a decision, in ink. The ghosted numeral behind it
   is the same device the Pipeline lane heads use. */
.callout {
  background: var(--ink); color: #fff;
  border-radius: var(--r); border-left: 5px solid var(--accent);
  padding: 18px 20px; position: relative; overflow: hidden;
  display: flex; flex-direction: column; justify-content: center;
  box-shadow: var(--aura);
}
.callout > * { position: relative; z-index: 1; }
/* The Dashboard stacks its callout; the ticket board puts the action beside
   the sentence, because there the callout sits above a board rather than
   beside a number. */
.callout--row { flex-direction: row; align-items: center; gap: 16px; }
@media (max-width: 720px) { .callout--row { flex-direction: column; align-items: flex-start; } }
.callout__q { font-size: 16.5px; font-weight: 600; line-height: 1.3; letter-spacing: -.015em; }
.callout__n {
  font-family: var(--f-mono); font-variant-numeric: tabular-nums;
  font-size: 26px; font-weight: 600; letter-spacing: -.03em;
  color: #F0A8B0; margin-top: 10px;
}
.callout__by {
  margin-top: 8px; font-family: var(--f-display);
  font-size: 10px; font-weight: 600; letter-spacing: .14em; text-transform: uppercase;
  color: rgba(255, 255, 255, .5);
}
.callout__ghost {
  position: absolute; right: -20px; bottom: -46px; z-index: 0;
  font-family: var(--f-mono); font-size: 104px; font-weight: 700; letter-spacing: -.06em;
  color: rgba(187, 32, 49, .24); line-height: 1; pointer-events: none;
}

/* State tiles, lit from beneath in their own hue. `--h` is set per tile. */
/* The Admin home page (views/adminhome.js, 2026-09-22): a grid of the
   administration screens, grouped. Same footprint as a figure tile so the
   page reads like the rest of the portal; the whole tile is the link. */
.launch__group + .launch__group { margin-top: 20px; }
.launch__group .eyebrow { margin-bottom: 10px; }
.launch { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 14px; }
.launch__tile {
  display: flex; align-items: flex-start; gap: 12px;
  padding: 14px 16px;
  background: #fff; border: 1px solid var(--hair); border-radius: 12px;
  color: var(--ink); text-decoration: none;
  transition: border-color .14s ease, box-shadow .14s ease;
}
.launch__tile:hover { border-color: var(--mist); box-shadow: var(--shadow-card); }
.launch__icon {
  flex: none; width: 34px; height: 34px; border-radius: 9px;
  display: grid; place-items: center;
  background: var(--paper); border: 1px solid var(--hair); color: var(--steel);
}
.launch__text { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.launch__name { font-family: var(--f-display); font-size: 13.5px; font-weight: 700; letter-spacing: -.01em; display: flex; align-items: center; gap: 8px; }
.launch__hint { font-size: 12px; color: var(--steel); }
.launch__count {
  display: inline-block; min-width: 18px; padding: 0 6px; border-radius: 99px;
  background: var(--accent); color: #fff; font-size: 11px; font-weight: 600; line-height: 18px; text-align: center;
}
.tiles { display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); gap: 16px; }
.tile {
  --h: var(--blue);
  position: relative; isolation: isolate;
  background: var(--card); border-radius: var(--r);
  padding: 16px 18px;
  border: 1px solid color-mix(in srgb, var(--h) 30%, var(--hair));
  box-shadow: var(--aura);
}
/* The glow sits BELOW the card, not behind the text — which is what keeps this
   readable where a tinted background would not be. */
.tile::after {
  content: ""; position: absolute; z-index: -1;
  left: 14%; right: 14%; bottom: -11px; height: 20px;
  border-radius: 50%;
  background: var(--h); opacity: calc(var(--aura-o) * 2); filter: blur(13px);
}
.tile--good { --h: #1C7A56; } .tile--warn { --h: #A8761B; }
.tile--bad  { --h: #BB2031; } .tile--flat { --h: #8A949B; }
.tile--acct { --h: #2A5C8A; }
/* The default a plain stat strip gets: a grey glow and the figure in ink.
   Neutral counts must not all arrive blue — four blue tiles in a row is a
   colour saying nothing, and this file spends colour only where it means
   something. */
.tile--plain { --h: #8A949B; }
.tile__n {
  display: block; margin-top: 6px;
  font-family: var(--f-mono); font-variant-numeric: tabular-nums;
  font-size: 26px; font-weight: 600; letter-spacing: -.03em;
}
.tile--good  .tile__n { color: var(--green); }
.tile--warn  .tile__n { color: var(--amber); }
.tile--bad   .tile__n { color: var(--accent); }
.tile--flat  .tile__n { color: var(--steel); }
.tile--acct  .tile__n { color: var(--blue); }
.tile--plain .tile__n { color: var(--ink); }
.tile__s { display: block; margin-top: 4px; font-size: 12.5px; color: var(--steel); }
a.tile, button.tile { display: block; width: 100%; text-align: left; cursor: pointer;
  transition: transform .12s ease; }
a.tile:hover, button.tile:hover { transform: translateY(-1px); }

/* The Today list: a count, what it is, and the way to it. */
.todo { display: flex; align-items: baseline; gap: 12px; padding: 9px 10px; border-radius: 9px;
  width: 100%; text-align: left; }
.todo:hover { background: var(--paper); }
.todo__n {
  font-family: var(--f-mono); font-variant-numeric: tabular-nums;
  font-size: 22px; font-weight: 600; letter-spacing: -.03em;
  color: var(--accent); min-width: 1.6em; flex: none;
}
.todo__n--calm { color: var(--ink-3); }
.todo__t { font-weight: 600; }
.todo__d { font-family: var(--f-mono); font-size: 12px; color: var(--steel-lt); margin-left: 6px; }
.todo__go { margin-left: auto; font-size: 12.5px; font-weight: 600; color: var(--accent); flex: none; }

.morebar {
  display: flex; gap: 16px; align-items: center; flex-wrap: wrap;
  margin-top: 16px; padding-top: 13px; border-top: 1px solid var(--hair-soft);
  font-size: 14px;
}
.morebar > span {
  font-family: var(--f-display);
  font-size: 10px; font-weight: 600; letter-spacing: .15em; text-transform: uppercase;
  color: var(--steel-lt);
}
.morebar a { color: var(--accent); font-weight: 600; }
.morebar a:hover { text-decoration: underline; }

@media (max-width: 900px) { .dashrow { grid-template-columns: 1fr; } }
/* The glow is the first thing to go when somebody has asked for less. */
@media (prefers-reduced-motion: reduce) { .tile::after { filter: none; } }
@media (prefers-reduced-transparency: reduce), (prefers-contrast: more) {
  .tile::after { display: none; }
  .tile { border-color: var(--hair); }
}

/* A late ticket, read from across the board rather than only at its date.
   The crimson edge and its shadow are the same pair the drop target uses, so
   "this one is wrong" looks the same wherever it appears. */
.board--aurora .dealcard.tkt--late {
  border-color: #EBB9BF;
  box-shadow: 0 1px 2px rgba(16, 24, 32, .06), 0 12px 30px -14px rgba(187, 32, 49, .55);
}

/* ---- Accounts: the frosted ledger --------------------------------------
   The Accounts table becomes one frosted slab sitting on the aurora field, so
   the colour drifts through underneath the figures rather than around them.

   THIS IS THE ONE PLACE THE PORTAL PUTS GLASS UNDER DENSE TEXT, and it is a
   deliberate exception to the rule at the top of this file, not an oversight.
   Three things pay for it:

     the ink header band stays fully opaque, so the sheet is always anchored;
     the surface sits at 55% white over a pale field, which measures about 8:1
       on the body figures — well past the 4.5:1 floor;
     and the reduced-transparency fallback below turns all of it solid for
       anyone whose system has asked for that.

   Lower the 55% and the exception stops being payable. */
.frostpanel {
  border-radius: var(--r-lg);
  overflow: hidden;
  border: 1px solid rgba(255, 255, 255, .85);
  background: rgba(255, 255, 255, .55);
  backdrop-filter: blur(26px) saturate(175%);
  -webkit-backdrop-filter: blur(26px) saturate(175%);
  box-shadow: 0 2px 6px rgba(16, 24, 32, .07), 0 26px 60px -26px rgba(16, 24, 32, .55);
}
/* Hairlines and banding both go up in contrast: over a moving ground the
   hairline the solid table uses disappears, and the row you are reading has to
   stay findable across seven columns. */
.frostpanel .tbl td { border-bottom: 1px solid rgba(16, 24, 32, .09); }
.frostpanel .tbl tbody tr:nth-child(even) { background: rgba(255, 255, 255, .34); }
.frostpanel .tbl tbody tr.is-clickable:hover { background: rgba(255, 255, 255, .7); }
.frostpanel .tbl th { background: rgba(16, 24, 32, .92); }
.frostpanel .pager, .frostpanel .panel__foot { border-top-color: rgba(16, 24, 32, .12); }
/* Analytics gives its sheet a head; Accounts does not. The rule under it has
   to be the frost's hairline rather than the panel's, or it reads as a seam. */
.frostpanel .panel__head { border-bottom-color: rgba(16, 24, 32, .12); }
/* A merchant that has stopped processing, or was never on a statement, reads
   back rather than shouting — the crimson badge is what carries the alarm. */
.frostpanel .tbl tr.is-quiet td:not(:first-child) { opacity: .72; }

.spark { display: inline-flex; align-items: flex-end; gap: 2px; height: 15px; }
.spark i { display: block; width: 5px; border-radius: 1px; background: var(--ink-3); }
.spark i.is-gone { background: var(--danger); }
.delta { font-family: var(--f-mono); font-size: 11px; font-weight: 600; }
.delta--up { color: var(--green); }
.delta--down { color: var(--danger); }

/* ---- The fallback -----------------------------------------------------
   Someone who has asked their operating system for less transparency, or for
   more contrast, has asked for exactly the thing this screen trades away. One
   media query is the whole accommodation: the blur goes, every surface goes
   solid, and not a single figure moves. */
@media (prefers-reduced-transparency: reduce), (prefers-contrast: more) {
  .frostpanel {
    background: var(--solid-bg);
    backdrop-filter: none; -webkit-backdrop-filter: none;
    border-color: var(--hair);
  }
  .frostpanel .tbl tbody tr:nth-child(even) { background: var(--paper); }
  .frostpanel .tbl th { background: var(--ink); }
  .aurora, .livefield { background: var(--paper); }
  .deck, .pill { backdrop-filter: none; -webkit-backdrop-filter: none; }
  .deck { background: var(--card); border-color: var(--hair); }
  .pill { background: var(--paper); border-color: var(--hair); }
  .board--aurora .lane {
    background: var(--card); border-color: var(--hair);
    backdrop-filter: none; -webkit-backdrop-filter: none;
  }
}

/* ---- The field, turned down -------------------------------------------
   Same devices, less of them. A sales board is glanced at; a service queue is
   sat in front of all afternoon, and at that dwell time the full field reads
   as noise behind the one thing being read. `.quietaura` on a page root keeps
   the ground and the lift and spends about half the colour. */
.quietaura .aurora {
  background:
    radial-gradient(560px 280px at 14% 26%, rgba(94, 150, 214, .13), rgba(94, 150, 214, 0) 72%),
    radial-gradient(560px 300px at 84% 74%, rgba(214, 120, 140, .11), rgba(214, 120, 140, 0) 72%),
    linear-gradient(180deg, #F6F8FA, #EDF1F6);
}
.quietaura .board--aurora .lane {
  background: rgba(255, 255, 255, .62);
  box-shadow: 0 1px 2px rgba(16, 24, 32, .05), 0 14px 34px -22px rgba(16, 24, 32, .34);
}
/* The under-glow halves rather than goes: it is what tells the four counts
   apart at a glance, and the tone is still doing work. */
.quietaura .tile::after { opacity: var(--aura-o); filter: blur(16px); }

@media (prefers-reduced-transparency: reduce), (prefers-contrast: more) {
  .quietaura .aurora { background: var(--paper); }
  .quietaura .board--aurora .lane { background: var(--card); box-shadow: none; }
}

/* ---- Tickets ----------------------------------------------------------- */
/* Three wide lanes rather than five narrow ones — a ticket card carries more
   text than a deal card, so it needs the room. */
.board--tickets { grid-auto-columns: minmax(268px, 1fr); }
.lane--open .lane__name { color: var(--crimson); }
.lane--closed { background: transparent; border-style: dashed; }
.lane--closed .dealcard { background: #FCFCFC; }

/* Unassigned-queue call to action above the ticket board. */
.triage {
  display: flex; align-items: center; gap: 12px;
  padding: 13px 16px;
  background: var(--crimson-lt); border: 1px solid #EBB9BF;
  border-radius: var(--r); color: var(--ink);
}
.triage > svg { color: var(--crimson); flex: none; }
.triage .tiny { color: var(--steel); }
@media (max-width: 640px) {
  .triage { align-items: flex-start; flex-wrap: wrap; }
}

.tkt--high { border-left: 3px solid var(--crimson); }
.tkt__flag { color: var(--crimson); flex: none; display: inline-flex; }
.tkt .dealcard__foot { gap: 8px; }

/* ---- Calendar ---------------------------------------------------------- */
.cal-chip {
  display: flex; align-items: flex-start; gap: 6px;
  width: 100%; padding: 4px 6px;
  border-radius: var(--r-sm);
  background: var(--card);
  border: 1px solid var(--hair);
  font-size: 11.5px; text-align: left;
  transition: border-color .14s ease, background-color .14s ease;
}
.cal-chip:hover { border-color: var(--chip, var(--mist)); background: var(--paper); }
.cal-chip + .cal-chip { margin-top: 4px; }
.cal-chip[draggable=true] { cursor: grab; }
.cal-chip.is-dragging { opacity: .4; cursor: grabbing; }
.cal-chip__dot {
  width: 6px; height: 6px; flex: none;
  border-radius: 50%; background: var(--chip, var(--steel));
}
.cal-chip__time {
  flex: none; font-family: var(--f-mono); font-size: 10px;
  color: var(--steel); font-variant-numeric: tabular-nums;
}
/* Week columns are narrow; two lines beats an ellipsis after three words. */
.cal-chip__title {
  min-width: 0; line-height: 1.35;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden;
}
.cal-chip__dot { margin-top: 4px; }
.cal-chip__time { margin-top: 1px; }
/* Month cells are short — keep those to a single line. */
.cal-cell .cal-chip__title { -webkit-line-clamp: 1; }

/* Week — seven day columns */
.cal-week {
  display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 8px;
  align-items: start;
}
.cal-col {
  background: var(--card); border: 1px solid var(--hair);
  border-radius: var(--r); overflow: hidden; min-height: 190px;
}
.cal-col.is-today { border-color: var(--crimson); }
/* Drop landing zone, shared by the week column and the month cell. */
.cal-col.is-drop, .cal-cell.is-drop {
  border-color: var(--crimson);
  background: var(--crimson-lt);
  box-shadow: inset 0 0 0 1px var(--crimson);
}
.cal-col.is-drop * , .cal-cell.is-drop * { pointer-events: none; }
.cal-col__head {
  width: 100%; padding: 9px 10px;
  border-bottom: 1px solid var(--hair-soft);
  display: flex; align-items: baseline; gap: 7px;
  background: var(--paper);
}
.cal-col.is-today .cal-col__head { background: var(--crimson-lt); }
.cal-col__dow {
  font-family: var(--f-display); font-size: 10px; font-weight: 600;
  letter-spacing: .12em; text-transform: uppercase; color: var(--steel-lt);
}
.cal-col.is-today .cal-col__dow { color: var(--crimson); }
.cal-col__num {
  font-family: var(--f-mono); font-size: 15px; font-weight: 500;
  font-variant-numeric: tabular-nums; margin-left: auto;
}
.cal-col.is-today .cal-col__num { color: var(--crimson); }
.cal-col__body { padding: 7px; }
.cal-col__empty { text-align: center; color: var(--mist); font-size: 12px; padding: 10px 0; }

/* Month */
.cal-dow {
  display: grid; grid-template-columns: repeat(7, minmax(0, 1fr));
  gap: 8px; margin-bottom: 6px;
}
.cal-dow span {
  font-family: var(--f-display); font-size: 10px; font-weight: 600;
  letter-spacing: .14em; text-transform: uppercase; color: var(--steel-lt);
  padding-left: 2px;
}
.cal-month { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 8px; }
.cal-cell {
  background: var(--card); border: 1px solid var(--hair);
  border-radius: var(--r); padding: 7px; min-height: 108px;
  cursor: pointer; transition: border-color .14s ease;
}
.cal-cell:hover { border-color: var(--mist); }
.cal-cell.is-outside { background: var(--paper); opacity: .6; }
.cal-cell.is-today { border-color: var(--crimson); }
.cal-cell__num {
  display: block; font-family: var(--f-mono); font-size: 12.5px;
  font-variant-numeric: tabular-nums; color: var(--steel); margin-bottom: 5px;
}
.cal-cell.is-today .cal-cell__num { color: var(--crimson); font-weight: 600; }
.cal-cell__more { display: block; margin-top: 4px; font-size: 10.5px; color: var(--steel-lt); }

/* Day */
.cal-row {
  display: flex; align-items: center; gap: 12px;
  width: 100%; padding: 12px 18px; text-align: left;
  border-bottom: 1px solid var(--hair-soft);
  transition: background-color .12s ease;
}
.cal-row:last-child { border-bottom: 0; }
.cal-row:hover { background: #FAFBFB; }
.cal-row__time {
  flex: none; width: 78px; font-size: 12px; color: var(--steel);
  font-variant-numeric: tabular-nums;
}
.cal-row__bar { flex: none; width: 3px; align-self: stretch; border-radius: 2px; background: var(--chip, var(--steel)); }

/* ---- Calendar: the rail and the day ------------------------------------
   The little month is the overview AND the drop target; the day gets the
   room. See the note above drawDay() in views/calendar.js for why this is
   the default rather than a grid. */
.cal-rd { display: grid; grid-template-columns: 236px minmax(0, 1fr); gap: 14px; align-items: start; }
.cal-rail {
  background: rgba(255, 255, 255, .62);
  backdrop-filter: blur(20px) saturate(160%);
  -webkit-backdrop-filter: blur(20px) saturate(160%);
  border: 1px solid rgba(255, 255, 255, .85);
  border-radius: var(--r); padding: 13px; box-shadow: var(--aura);
}
.cal-rail__grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; margin-top: 9px; }
.cal-rail__dow {
  font-size: 9px; font-weight: 600; color: var(--steel-lt);
  text-align: center; padding-bottom: 3px;
}
.rday {
  position: relative; border: 0; background: transparent; cursor: pointer;
  text-align: center; padding: 6px 0 11px; border-radius: 7px;
  font-family: var(--f-mono); font-size: 11.5px; font-variant-numeric: tabular-nums;
  color: var(--ink-3);
}
.rday:hover { background: rgba(255, 255, 255, .85); }
.rday.is-outside { color: var(--mist); }
.rday.is-today { box-shadow: inset 0 0 0 1px #EBB9BF; }
/* A dot says the day holds something; crimson says something on it is late.
   That is the whole overview, and it is why the grid is not needed. */
.rday.has::after {
  content: ""; position: absolute; left: 50%; bottom: 4px; transform: translateX(-50%);
  width: 4px; height: 4px; border-radius: 50%; background: var(--steel);
}
.rday.is-late::after { background: var(--accent); }
.rday.is-sel { background: var(--ink); color: #fff; }
.rday.is-sel::after { background: #F0A8B0; }
.rday.is-drop { background: var(--crimson-lt); box-shadow: inset 0 0 0 1px var(--crimson); }
.rday.is-drop::after { background: var(--crimson); }

.daysheet {
  background: var(--card); border: 1px solid var(--hair);
  border-radius: var(--r); box-shadow: var(--aura); overflow: hidden;
}
.daysheet.is-drop { border-color: var(--crimson); box-shadow: inset 0 0 0 1px var(--crimson); }
.daysheet__head {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 13px 16px; border-bottom: 1px solid var(--hair);
}
/* Untimed work sits ABOVE the clock. A ticket due date has no hour on it, and
   putting it on the spine would be inventing one. */
.daysheet__all {
  padding: 10px 16px 12px; background: var(--paper);
  border-bottom: 1px solid var(--hair);
}
.daysheet__spine { padding: 8px 16px 16px; }
.cal-row--flat { padding: 8px 0; border-bottom: 0; }
.cal-row--flat:hover { background: transparent; }

.calhr { display: grid; grid-template-columns: 52px minmax(0, 1fr); align-items: start; min-height: 34px; }
.calhr__t { font-family: var(--f-mono); font-size: 11px; color: var(--steel-lt); padding-top: 1px; }
.calhr__l { border-top: 1px dashed var(--hair-soft); min-height: 100%; padding: 6px 0 0; }
.calhr.is-now .calhr__l { border-top: 1px solid var(--accent); }
.calhr.is-now .calhr__t { color: var(--accent); font-weight: 600; }
.calblk {
  display: block; width: 100%; text-align: left; cursor: pointer;
  background: var(--card); border: 1px solid var(--hair);
  border-left: 3px solid var(--chip, var(--accent));
  border-radius: 9px; padding: 8px 11px; margin-bottom: 6px;
  box-shadow: 0 1px 2px rgba(16, 24, 32, .05), 0 10px 24px -16px rgba(16, 24, 32, .5);
}
.calblk:hover { border-color: var(--mist); border-left-color: var(--chip, var(--accent)); }
.calblk__n { display: block; font-weight: 600; font-size: 13px; }
.calblk__s { display: block; font-family: var(--f-mono); font-size: 11.5px; color: var(--steel); margin-top: 2px; }

/* ---- Calendar: the week and the month, on the field --------------------
   The same glass the Pipeline lanes and the Tickets board use, so all three
   boards read as one product. The page root carries `quietaura`, which is
   what turns the field down for a screen somebody sits in front of. */
.deck--cal { margin-bottom: 12px; }
.deck__t { font-size: 17px; font-weight: 600; letter-spacing: -.02em; margin-top: 2px; }

.aurora .cal-col, .aurora .cal-cell {
  background: rgba(255, 255, 255, .55);
  backdrop-filter: blur(20px) saturate(165%);
  -webkit-backdrop-filter: blur(20px) saturate(165%);
  border-color: rgba(255, 255, 255, .8);
  box-shadow: 0 1px 2px rgba(16, 24, 32, .05), 0 16px 40px -24px rgba(16, 24, 32, .42);
}
.aurora .cal-col__head { background: rgba(255, 255, 255, .38); border-bottom-color: rgba(16, 24, 32, .1); }
.aurora .cal-col.is-today {
  background: rgba(255, 255, 255, .82);
  border-color: #EBB9BF; border-top: 3px solid var(--accent);
  box-shadow: 0 1px 2px rgba(16, 24, 32, .06), 0 22px 52px -22px rgba(187, 32, 49, .5);
}
.aurora .cal-col.is-today .cal-col__head { background: transparent; }
.cal-col--past { opacity: .62; }
.aurora .cal-cell.is-outside { background: rgba(255, 255, 255, .24); opacity: 1; }
.aurora .cal-cell.is-today { border-color: #EBB9BF; }
.aurora .cal-chip { background: rgba(255, 255, 255, .9); border-color: rgba(255, 255, 255, .95); }
.aurora .cal-col__empty { color: rgba(16, 24, 32, .26); }
.aurora .cal-dow span { color: var(--steel); }

/* The pointer at the foot of every view. Undated follow-ups cannot appear on
   a calendar at all, so this names the number and sends it somewhere it can
   be cleared rather than hosting a list of it. */
.undated {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 10px 14px; border-radius: var(--r);
  background: var(--card); border: 1px solid var(--hair);
  font-size: 12.5px; color: var(--steel);
}
.undated .mono { color: var(--ink); }

/* ---- Inventory: the stockroom -------------------------------------------
   Opens on what is on the shelf, because "can we fill this order" is the
   question asked of it most often. One bin per model: the count left is the
   big figure, and the bar beneath it is where the rest of that model went. */
.shelf { display: grid; grid-template-columns: repeat(auto-fill, minmax(236px, 1fr)); gap: 14px; }
.bin {
  background: var(--card); border: 1px solid var(--hair);
  border-radius: var(--r); padding: 14px; box-shadow: var(--aura);
}
.bin__n { font-weight: 600; font-size: 14px; letter-spacing: -.01em; }
.bin__p { font-size: 11.5px; color: var(--steel-lt); margin-top: 1px; }
.bin__big {
  font-family: var(--f-mono); font-variant-numeric: tabular-nums;
  font-size: 34px; font-weight: 600; letter-spacing: -.035em;
  line-height: 1; margin: 12px 0 2px;
}
/* The one colour on this card, and it means "order more". */
.bin--low { border-color: #EBB9BF; }
.bin--low .bin__big { color: var(--accent); }
.bin__bar {
  display: flex; height: 6px; border-radius: 3px; overflow: hidden;
  margin: 10px 0 8px; background: var(--hair-soft);
}
.bin__bar i { display: block; height: 100%; }
.bin__k { display: flex; gap: 10px; flex-wrap: wrap; font-size: 11px; color: var(--steel); }
.bin__k i {
  width: 7px; height: 7px; border-radius: 2px;
  display: inline-block; margin-right: 4px; vertical-align: middle;
}
.sw-stock { background: var(--blue); }
.sw-sold  { background: var(--green); }
.sw-rent  { background: var(--amber); }
.sw-loan  { background: var(--accent); }

/* The commission, shown before it is committed rather than after. A split
   applied silently is a split nobody checks. */
.placepreview {
  padding: 12px 14px; border-radius: var(--r);
  background: var(--paper); border: 1px solid var(--hair);
  display: flex; flex-direction: column; gap: 8px;
}
.placepreview .pos { color: var(--green); }
.placepreview .neg { color: var(--accent); }
/* Stock, said while a promise is being made. Nothing is reserved — the note
   under buildPanel() in views/tickets.js says why — so this is a warning and
   never a refusal: a merchant who wants five gets five, and the shortfall
   becomes a back-order on the order. */
.rowstock { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; padding: 0 2px 4px; }
.stockpill {
  font-family: var(--f-mono); font-size: 11px; padding: 2px 8px; border-radius: 999px;
  display: inline-block;
}
.stockpill--ok { background: var(--green-lt); color: var(--green); }
.stockpill--short { background: var(--crimson-lt); color: var(--accent); }

/* Two ways to take a unit back, and the difference is money, so it is a
   choice with its consequence written under it rather than a dropdown. */
.pickrow {
  display: flex; align-items: flex-start; gap: 10px; width: 100%;
  text-align: left; padding: 11px 13px; border-radius: var(--r);
  border: 1px solid var(--hair); background: var(--card); cursor: pointer;
}
.pickrow:hover { border-color: var(--mist); }
.pickrow.is-on { border-color: var(--accent); background: var(--crimson-lt); }
.pickrow__dot {
  flex: none; width: 14px; height: 14px; border-radius: 50%;
  border: 2px solid var(--mist); margin-top: 2px;
}
.pickrow.is-on .pickrow__dot { border-color: var(--accent); background: var(--accent); box-shadow: inset 0 0 0 2px #fff; }

.tbl .pos, td.pos { color: var(--green); }
.tbl .neg, td.neg { color: var(--accent); }

/* ---- Cost analysis: the bar, the two bills, the stamp -------------------
   This screen is not a form, it is two bills. What a merchant compares is the
   cost of acceptance this month against next month, so it is set like one:
   the perforated edge, the dotted leaders and the mono figures the residual
   statement already uses — the other place in this portal where somebody
   reads what they were charged.

   The sheets are a read-out. Every figure is still entered in the panels
   underneath; a typeset statement with inputs buried in it would be neither
   one thing nor the other, and the sheet is what gets turned around to face
   the merchant. */

/* The four figures used to sit halfway down the page and scroll away exactly
   while they were being changed. Now they ride the top of the window. */
.costbar {
  position: sticky; top: 8px; z-index: 6;
  display: flex; align-items: center; gap: 18px; flex-wrap: wrap;
  padding: 12px 18px; border-radius: var(--r);
  background: rgba(255, 255, 255, .74);
  backdrop-filter: blur(20px) saturate(170%);
  -webkit-backdrop-filter: blur(20px) saturate(170%);
  border: 1px solid var(--glass-brd); box-shadow: var(--aura);
}
.costbar__arrow { color: var(--mist); font-size: 18px; }
.pin { display: flex; flex-direction: column; min-width: 0; }
.pin__n {
  font-family: var(--f-mono); font-variant-numeric: tabular-nums;
  font-size: 19px; font-weight: 600; letter-spacing: -.03em; margin-top: 2px;
}
.pin--win { padding-left: 18px; border-left: 1px solid rgba(16, 24, 32, .13); }
.pin--win .pin__n { font-size: 26px; }
.pin--good .pin__n { color: var(--green); }
.pin--bad .pin__n { color: var(--accent); }

.sheets { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; align-items: start; }
.sheet {
  position: relative; overflow: hidden;
  background: var(--card); border: 1px solid var(--hair);
  border-radius: var(--r); box-shadow: var(--aura);
}
/* The torn edge off the residual statement. Ours tears crimson. */
.sheet::before {
  content: ""; position: absolute; left: 0; right: 0; top: 0; height: 5px;
  background: repeating-linear-gradient(90deg, var(--hair) 0 5px, transparent 5px 10px);
}
.sheet--ours::before {
  background: repeating-linear-gradient(90deg, #EBB9BF 0 5px, transparent 5px 10px);
}
.sheet__h { padding: 15px 16px 12px; border-bottom: 1px solid var(--hair); }
.sheet__who { font-weight: 600; font-size: 15px; letter-spacing: -.01em; margin-top: 3px; }
.sheet__b { padding: 13px 16px 4px; display: flex; flex-direction: column; gap: 9px; }
.sl { display: flex; align-items: baseline; gap: 10px; font-size: 12.5px; }
.sl .lbl { color: var(--ink-3); }
.sl .dots { flex: 1 1 auto; border-bottom: 1px dotted var(--mist); transform: translateY(-3px); }
/* The qualifier that tells the two sheets' same-named rows apart. */
.sl__d { display: block; font-size: 11px; color: var(--steel-lt); font-family: var(--f-mono); margin-top: 1px; }
.sl--new .sl__d { color: #C9757F; }
.sl .v { font-family: var(--f-mono); font-variant-numeric: tabular-nums; }
/* A line our quote drops is struck at what they pay for it today; a line we
   add is crimson. That is the comparison, without a chart. */
.sl--gone .lbl, .sl--gone .v { color: var(--mist); text-decoration: line-through; }
.sl--new .lbl { color: var(--accent); font-weight: 600; }
.sl--new .v { color: var(--accent); }
.sheet__f {
  margin-top: 6px; padding: 12px 16px 14px; border-top: 2px solid var(--ink);
  display: flex; align-items: baseline; justify-content: space-between; gap: 10px;
}
.sheet__k {
  font-size: 10px; font-weight: 600; letter-spacing: .15em;
  text-transform: uppercase; color: var(--steel-lt);
}
.sheet__v {
  font-family: var(--f-mono); font-variant-numeric: tabular-nums;
  font-size: 22px; font-weight: 600; letter-spacing: -.03em;
}
.sheet__v--ours { color: var(--accent); }
.sheet__once {
  padding: 0 16px 13px; font-family: var(--f-mono); font-size: 11.5px; color: var(--steel);
  text-align: right;
}

/* The saving, set as a total under the pair rather than as another tile. */
.stamp {
  display: flex; align-items: center; gap: 16px; flex-wrap: wrap;
  margin-top: 14px; padding: 14px 18px; border-radius: var(--r);
}
.stamp--good { background: var(--green-lt); border: 1px solid #BFE0D2; }
.stamp--bad  { background: var(--crimson-lt); border: 1px solid #EBB9BF; }
.stamp__k { font-size: 10px; font-weight: 600; letter-spacing: .15em; text-transform: uppercase; }
.stamp--good .stamp__k, .stamp--good .stamp__t { color: var(--green); }
.stamp--bad  .stamp__k, .stamp--bad  .stamp__t { color: var(--accent); }
.stamp__n {
  font-family: var(--f-mono); font-variant-numeric: tabular-nums;
  font-size: 30px; font-weight: 700; letter-spacing: -.035em; margin-top: 2px;
}
.stamp--good .stamp__n { color: var(--green); }
.stamp--bad  .stamp__n { color: var(--accent); }
.stamp__n--sm { font-size: 22px; }
.stamp__sep { padding-left: 16px; }
.stamp--good .stamp__sep { border-left: 1px solid #BFE0D2; }
.stamp--bad  .stamp__sep { border-left: 1px solid #EBB9BF; }
.stamp__t { font-size: 11.5px; }

/* Who picks up the difference. A saving made by moving to a surcharge is paid
   by the merchant's customers, and it is stated on its own rather than netted
   against the saving — it is not the same person's money. */
.whopays {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  margin-top: 12px; padding: 12px 16px; border-radius: var(--r);
  background: var(--card); border: 1px solid var(--hair);
  font-size: 12.5px; color: var(--ink-3); line-height: 1.6;
}

/* ---- The account passport ----------------------------------------------
   ONE PAGE PER TAB, AND THE ROW IS THE NAVIGATION. Greg, 2026-09-17: "Push
   the different tabs in the column on the left to their own row where we can
   navigate from page to page for each tab. Not one large flowing page where
   you have to keep scrolling down."

   So the 176px rail is gone (his q7, `gone`) and the record is a single
   column: the tab row, then the one section it selected. The 16px gap is the
   grid's, not a margin on either child — a margin here would travel with the
   row to the next screen that used it. */
.passport { display: grid; grid-template-columns: minmax(0, 1fr); gap: 16px; }

/* The row itself is the house `.tabs`/`.tab` pill strip — see line 808. Only
   the greyed state is new, because no other screen in the portal shows a tab
   for something that is not there yet. */

/* AN EMPTY TAB STAYS IN THE ROW, GREYED. Greg's q2, 2026-09-17: `grey`. Six of
   the eleven are empty on almost every account, so hiding them would make the
   row a different shape on every merchant, which is exactly what q1 ruled out.
   It must read as available-but-empty and never as disabled: full contrast on
   hover, and it opens on the section's own empty state. */
/* ⚠ NOT --steel-lt, THOUGH IT LOOKS LIKE THE ONE TO REACH FOR. Measured on
   the sandbox build: --steel-lt on this background is 2.89:1, under the 3:1 at
   which a control reads as disabled — and this control is one Greg said must
   still be pressed. #646F78 measures 4.81:1, still plainly lighter than the
   5.51:1 of a tab with something in it. Measure before changing it. */
.tab--empty { color: #646f78; border-color: rgba(16, 24, 32, .09); background: rgba(255, 255, 255, .5); }
.tab--empty:hover { color: var(--ink); background: #fff; border-color: var(--hair); }
/* Selected wins over empty — an empty tab you are reading is still where you
   are, and the ink pill is the only thing that says so. */
.tab--empty.is-on { color: #fff; background: var(--ink); border-color: var(--ink); }

/* THE ROW ON A WIDE SCREEN, THE SAME ELEVEN AS A MENU ON A PHONE — Greg's q6,
   2026-09-17, `menu`. Both are in the markup and this chooses; see tabRow() in
   views/crm.js for why it is not a resize listener. 640px is the house phone
   breakpoint, and at 390px eleven pills wrap to four lines. */
/* The wrapper holds the row and the menu and carries NO spacing of its own:
   the 16px between it and the section below is the .passport grid's gap, and a
   margin here would double it. It needs a rule even so — a class with nothing
   behind it is how a layout row silently ends up at gap zero. */
.rectabs { display: block; min-width: 0; }
.rectabs__pick { display: none; }
@media (max-width: 640px) {
  .rectabs > .tabs { display: none; }
  .rectabs__pick { display: block; width: 100%; }
}

/* ---- Equipment on an account -------------------------------------------
   One block per make and model. The acquisition tag is the thing worth
   reading from across the room — whether the hardware is theirs or ours is
   the question that gets asked when an account leaves. */
.kit {
  border: 1px solid var(--hair); border-radius: var(--r);
  padding: 12px 14px; background: var(--card);
}
.kit__name { font-weight: 600; font-size: 14px; letter-spacing: -.01em; }
.kit__q {
  margin-left: 7px; font-family: var(--f-mono); font-size: 12px;
  font-weight: 500; color: var(--steel);
}
.kit__meta {
  display: flex; flex-wrap: wrap; align-items: center; gap: 10px;
  margin-top: 5px; font-size: 12px; color: var(--steel);
}
.kit__tag {
  padding: 2px 8px; border-radius: 999px; font-size: 10.5px; font-weight: 600;
  letter-spacing: .04em; text-transform: uppercase;
  background: var(--paper); color: var(--steel); border: 1px solid var(--hair);
}
/* Bought is settled and needs no colour. Rent, lease and a payment plan are
   money still moving. A loan is ours, and that is the one to notice. */
.kit__tag--bought { background: var(--green-lt); color: var(--green); border-color: #BFE0D2; }
.kit__tag--rented, .kit__tag--leased, .kit__tag--plan {
  background: var(--blue-lt); color: var(--blue); border-color: #C3D6E6;
}
.kit__tag--loaned { background: var(--crimson-lt); color: var(--crimson); border-color: #EBB9BF; }
.kit__sn { margin-top: 9px; padding-top: 9px; border-top: 1px solid var(--hair-soft); }
.kit__sn .eyebrow { margin-bottom: 5px; }
.sn {
  font-family: var(--f-mono); font-size: 11.5px; letter-spacing: .01em;
  padding: 3px 8px; border-radius: 6px;
  background: var(--paper); border: 1px solid var(--hair); color: var(--ink-3);
}
/* Said, never enforced: hardware gets recorded before the boxes are opened,
   and a row refused for a missing serial is a row nobody ever creates. */
.kit__gap { margin-top: 8px; font-size: 11.5px; color: var(--amber); }
.kit__note {
  margin-top: 8px; font-size: 12.5px; color: var(--steel); line-height: 1.6;
}
@media (max-width: 700px) {
  /* .grid-3 itself is defined once, near the top with the other layout
     helpers; this only collapses it. */
  .grid-3 { grid-template-columns: 1fr; }
  .kit__meta { gap: 7px; }
}

.sect { margin-bottom: 16px; scroll-margin-top: 14px; }
.sect:last-child { margin-bottom: 0; }
.sect__h { display: flex; align-items: baseline; gap: 10px; margin: 0 0 8px 2px; flex-wrap: wrap; }

/* The identity band: everything that was spread across a heading, a meta row
   and the first tab, said once at the top. */
.idhead {
  background: var(--ink); color: #fff; border-radius: var(--r);
  padding: 18px 20px; box-shadow: var(--aura);
}
.idhead .eyebrow { color: #8A949B; }
.idhead__who { font-size: 24px; font-weight: 600; letter-spacing: -.025em; margin-top: 3px; }
.idhead__meta {
  display: flex; flex-wrap: wrap; gap: 14px; margin-top: 10px;
  font-size: 12.5px; color: #C6CCD2;
}
.idhead__meta a { color: #C6CCD2; }
.idhead__meta a:hover { color: #fff; text-decoration: underline; }
.idhead__meta .mono { color: #fff; }
.btn--ink-ghost {
  background: rgba(255, 255, 255, .1); border-color: rgba(255, 255, 255, .22); color: #fff;
}
.btn--ink-ghost:hover { background: rgba(255, 255, 255, .18); border-color: rgba(255, 255, 255, .35); }


@media (max-width: 860px) {
  .sheets { grid-template-columns: 1fr; }
  .costbar { position: static; gap: 14px; }
  .pin--win { padding-left: 0; border-left: 0; }
}
@media (prefers-reduced-transparency: reduce), (prefers-contrast: more) {
  .costbar {
    background: var(--card); border-color: var(--hair);
    backdrop-filter: none; -webkit-backdrop-filter: none;
  }
}

@media (max-width: 900px) {
  .cal-rd { grid-template-columns: 1fr; }
  .calhr { grid-template-columns: 44px minmax(0, 1fr); }
}
@media (prefers-reduced-transparency: reduce), (prefers-contrast: more) {
  .cal-rail { background: var(--card); backdrop-filter: none; -webkit-backdrop-filter: none; border-color: var(--hair); }
  .aurora .cal-col, .aurora .cal-cell {
    background: var(--card); border-color: var(--hair);
    backdrop-filter: none; -webkit-backdrop-filter: none;
  }
  .aurora .cal-cell.is-outside { background: var(--paper); }
  .aurora .cal-chip { background: var(--card); border-color: var(--hair); }
  .deck--cal { background: var(--card); border-color: var(--hair); }
}

@media (max-width: 900px) {
  /* A seven-column week is unreadable on a phone; stack the days instead. */
  .cal-week { grid-template-columns: 1fr; }
  .cal-col { min-height: 0; }
  .cal-dow { display: none; }
  .cal-month { grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 3px; }
  .cal-cell { min-height: 74px; padding: 4px; }
  .cal-cell .cal-chip__title, .cal-cell .cal-chip__time { display: none; }
  .cal-chip { justify-content: center; padding: 3px; }
  .cal-row__time { width: 62px; }
}

/* ---- Stage stepper ----------------------------------------------------- */
.stepper { display: flex; align-items: stretch; gap: 3px; }
.step {
  flex: 1 1 0; min-width: 0;
  padding: 8px 10px 9px;
  background: var(--hair-soft);
  border: 0;
  text-align: left;
  transition: background-color .14s ease, color .14s ease;
}
.step:first-child { border-radius: var(--r) 0 0 var(--r); }
.step:last-child  { border-radius: 0 var(--r) var(--r) 0; }
.step:hover { background: var(--mist); }
.step__seq { font-family: var(--f-mono); font-size: 10px; color: var(--steel-lt); }
.step__name { font-family: var(--f-display); font-size: 11.5px; font-weight: 600; color: var(--steel); margin-top: 2px; }
.step.is-done { background: var(--ink-3); }
.step.is-done .step__seq { color: rgba(255,255,255,.5); }
.step.is-done .step__name { color: rgba(255,255,255,.9); }
.step.is-current { background: var(--crimson); }
.step.is-current .step__seq { color: rgba(255,255,255,.65); }
.step.is-current .step__name { color: #fff; }

/* ---- Drawer ------------------------------------------------------------ */
.scrim {
  position: fixed; inset: 0; z-index: 60;
  background: rgba(16, 24, 32, .38);
  animation: fade .16s ease;
}
.drawer {
  position: fixed; top: 0; right: 0; bottom: 0; z-index: 61;
  width: min(680px, 100vw);
  background: var(--paper);
  border-left: 1px solid var(--hair);
  display: flex; flex-direction: column;
  animation: slide-in .22s cubic-bezier(.22,.7,.3,1);
  box-shadow: -18px 0 44px -18px rgba(16,24,32,.28);
}
.drawer__head {
  flex: none;
  padding: 18px 22px;
  background: var(--card);
  border-bottom: 1px solid var(--hair);
}
.drawer__body { flex: 1 1 auto; overflow-y: auto; padding: 20px 22px 44px; }
.drawer__foot { flex: none; padding: 13px 22px; background: var(--card); border-top: 1px solid var(--hair); display: flex; gap: 9px; }

@keyframes slide-in { from { transform: translateX(22px); opacity: .4; } to { transform: none; opacity: 1; } }
@keyframes fade { from { opacity: 0; } to { opacity: 1; } }
@keyframes pop { from { transform: translateY(6px) scale(.99); opacity: 0; } to { transform: none; opacity: 1; } }

/* ---- Modal ------------------------------------------------------------- */
.modal {
  position: fixed; z-index: 61;
  top: 50%; left: 50%; transform: translate(-50%, -50%);
  width: min(560px, calc(100vw - 32px));
  max-height: calc(100vh - 60px);
  background: var(--card);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-pop);
  display: flex; flex-direction: column;
  animation: pop .18s cubic-bezier(.22,.7,.3,1);
}
.modal--wide { width: min(760px, calc(100vw - 32px)); }
/* A dialog carrying a whole table rather than a form. The posting review is a
   merchant breakdown — seven columns of it — and at 760px the split and the
   cut fall off the right-hand edge, which is exactly what the page exists to
   let somebody read. */
.modal--sheet { width: min(1180px, calc(100vw - 48px)); }
.modal__head { padding: 18px 22px 14px; border-bottom: 1px solid var(--hair-soft); }
.modal__body { padding: 20px 22px; overflow-y: auto; }
.modal__foot { padding: 14px 22px; border-top: 1px solid var(--hair-soft); display: flex; justify-content: flex-end; gap: 9px; }

/* ---- Menu -------------------------------------------------------------- */
.menu {
  position: fixed; z-index: 70;
  min-width: 190px;
  background: var(--card);
  border: 1px solid var(--hair);
  border-radius: var(--r);
  box-shadow: var(--shadow-pop);
  padding: 5px;
  animation: pop .13s ease;
}
.menu__item {
  display: flex; align-items: center; gap: 9px;
  width: 100%; padding: 8px 10px;
  border-radius: var(--r-sm);
  font-size: 13.5px; text-align: left;
  transition: background-color .12s ease;
}
.menu__item svg { width: 15px; height: 15px; color: var(--steel); flex: none; }
.menu__item:hover { background: var(--hair-soft); }
.menu__item--danger { color: var(--crimson); }
.menu__item--danger svg { color: var(--crimson); }
.menu__sep { height: 1px; background: var(--hair-soft); margin: 5px 0; }

/* Typeahead under a text field. Absolute rather than fixed like .menu, because
   it belongs to the input it hangs from and must move with it when the panel
   scrolls. Same card, border and shadow so it reads as the same family. */
.suggest {
  position: absolute; z-index: 60; left: 0; right: 0; top: calc(100% + 4px);
  background: var(--card);
  border: 1px solid var(--hair);
  border-radius: var(--r);
  box-shadow: var(--shadow-pop);
  padding: 5px;
  max-height: 240px; overflow-y: auto;
  animation: pop .13s ease;
}
.suggest__item {
  display: block; width: 100%; text-align: left;
  padding: 8px 10px; border: 0; background: none; cursor: pointer;
  border-radius: 6px; font: inherit; color: var(--ink);
}
.suggest__item:hover,
.suggest__item.is-on { background: var(--hair-soft); }
.suggest__name { font-weight: 600; font-size: 13px; }
.suggest__meta { font-size: 11.5px; color: var(--mute); margin-top: 2px; }
.suggest__none { padding: 10px; font-size: 12.5px; color: var(--mute); }

/* ---- Toast ------------------------------------------------------------- */
.toasts {
  position: fixed; z-index: 90; bottom: 22px; right: 22px;
  display: flex; flex-direction: column-reverse; gap: 9px;
  pointer-events: none;
}
.toast {
  pointer-events: auto;
  display: flex; align-items: flex-start; gap: 10px;
  min-width: 268px; max-width: 384px;
  padding: 12px 14px;
  background: var(--ink);
  color: #fff;
  border-radius: var(--r);
  box-shadow: var(--shadow-pop);
  font-size: 13.5px;
  animation: slide-in .2s cubic-bezier(.22,.7,.3,1);
}
.toast svg { width: 16px; height: 16px; flex: none; margin-top: 1px; }
.toast--ok svg { color: #57D6A4; }
.toast--err svg { color: #FF8A97; }
.toast__sub { color: rgba(255,255,255,.65); font-size: 12px; margin-top: 2px; }

/* ---- Timeline (notes / activity) --------------------------------------- */
.timeline { position: relative; padding-left: 26px; }
.timeline::before {
  content: ""; position: absolute; left: 9px; top: 6px; bottom: 6px;
  width: 1px; background: var(--hair);
}
.tl-item { position: relative; padding-bottom: 18px; }
.tl-item:last-child { padding-bottom: 0; }
.tl-item::before {
  content: ""; position: absolute; left: -21px; top: 5px;
  width: 7px; height: 7px; border-radius: 50%;
  background: var(--card); border: 2px solid var(--mist);
}
.tl-item--note::before { border-color: var(--crimson); }
.tl-item__meta { font-size: 11.5px; color: var(--steel-lt); }
.tl-item__body {
  margin-top: 5px; padding: 11px 13px;
  background: var(--card); border: 1px solid var(--hair); border-radius: var(--r);
  font-size: 13.5px; line-height: 1.55; white-space: pre-wrap;
}

/* ---- Task / follow-up rows --------------------------------------------- */
.taskrow {
  display: flex; align-items: flex-start; gap: 11px;
  padding: 11px 14px;
  border-bottom: 1px solid var(--hair-soft);
}
.taskrow:last-child { border-bottom: 0; }
.taskrow.is-done .taskrow__title { text-decoration: line-through; color: var(--steel-lt); }
.taskrow__title { font-size: 13.5px; font-weight: 500; }
.taskrow input[type=checkbox] { width: 16px; height: 16px; margin-top: 2px; accent-color: var(--crimson); flex: none; }

/* Rows that open something on click — follow-ups and account tickets. */
.taskrow--edit { cursor: pointer; align-items: center; transition: background-color .12s ease; }
.taskrow--edit:hover { background: #FAFBFB; }
.taskrow__edit {
  flex: none; display: inline-flex; color: var(--mist);
  opacity: 0; transition: opacity .12s ease;
}
.taskrow--edit:hover .taskrow__edit { opacity: 1; }
/* Touch devices have no hover, so the affordance stays put. */
@media (hover: none) { .taskrow__edit { opacity: 1; } }

/* ---- Accordion (FAQ) --------------------------------------------------- */
.acc { border-bottom: 1px solid var(--hair-soft); }
.acc:last-child { border-bottom: 0; }
.acc__q {
  display: flex; align-items: center; gap: 12px;
  width: 100%; padding: 15px 18px;
  text-align: left;
  font-family: var(--f-display); font-size: 14px; font-weight: 600;
}
.acc__q svg { width: 16px; height: 16px; margin-left: auto; color: var(--steel-lt); transition: transform .2s ease; flex: none; }
.acc.is-open .acc__q svg { transform: rotate(180deg); }
.acc__a { padding: 0 18px 17px; font-size: 13.5px; line-height: 1.65; color: var(--steel); max-width: 76ch; }

/* ---- Knowledge base cards ---------------------------------------------- */
.kb-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(268px, 1fr)); gap: 14px; }
.kb-card {
  display: flex; flex-direction: column;
  background: var(--card); border: 1px solid var(--hair); border-radius: var(--r-lg);
  overflow: hidden; text-align: left;
  transition: border-color .14s ease, box-shadow .14s ease, transform .14s ease;
}
.kb-card:hover { border-color: var(--mist); box-shadow: var(--shadow-card); transform: translateY(-1px); }
.kb-card__thumb {
  position: relative; aspect-ratio: 16 / 9;
  background: var(--ink); display: flex; align-items: center; justify-content: center;
  overflow: hidden;
}
.kb-card__thumb img { width: 100%; height: 100%; object-fit: cover; opacity: .78; }
.kb-card__play {
  position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
}
.kb-card__play span {
  width: 44px; height: 44px; border-radius: 50%;
  background: rgba(187, 32, 49, .95);
  display: flex; align-items: center; justify-content: center;
  box-shadow: 0 4px 14px rgba(0,0,0,.3);
  transition: transform .16s ease;
}
.kb-card:hover .kb-card__play span { transform: scale(1.08); }
.kb-card__play svg { width: 17px; height: 17px; color: #fff; margin-left: 2px; }
.kb-card__dur {
  position: absolute; right: 8px; bottom: 8px;
  padding: 2px 6px; border-radius: 3px;
  background: rgba(16,24,32,.82); color: #fff;
  font-family: var(--f-mono); font-size: 11px;
}
.kb-card__body { padding: 14px 15px 15px; flex: 1 1 auto; display: flex; flex-direction: column; }
.kb-card__title { font-family: var(--f-display); font-size: 14px; font-weight: 700; letter-spacing: -.01em; }
.kb-card__sum { margin-top: 6px; font-size: 12.5px; color: var(--steel); line-height: 1.55; flex: 1 1 auto; }

/* Written material gets no thumbnail — a hairline rule and the title do the
   work, which keeps the grid dense and spends no crimson on decoration. */
.kb-card--doc { border-top: 2px solid var(--ink); }
.kb-card--doc:hover { border-top-color: var(--crimson); }
.kb-card--doc .kb-card__body { padding: 15px 16px 16px; }
.kb-card__cat {
  display: inline-flex; align-items: center;
  font-family: var(--f-display);
  font-size: 10px; font-weight: 600; letter-spacing: .14em; text-transform: uppercase;
  color: var(--steel-lt);
  margin-bottom: 9px;
}
.kb-card__meta {
  display: flex; align-items: center; gap: 8px;
  margin-top: 13px; padding-top: 11px;
  border-top: 1px solid var(--hair-soft);
}

/* Marketing material carries its own buttons instead of opening a reader, so
   the card is a div rather than a button — it loses the pointer cursor a
   button gave it, and gains a hover it has to declare for itself. */
.kb-card--asset { cursor: default; }
.kb-card--asset .kb-card__meta { margin-top: auto; }
.kb-card--asset .btn { flex: 0 0 auto; }

/* ---- Progress ---------------------------------------------------------- */
.bar { height: 6px; background: var(--hair); border-radius: 3px; overflow: hidden; }
.bar span { display: block; height: 100%; background: var(--crimson); border-radius: 3px; transition: width .5s cubic-bezier(.3,.8,.3,1); }
.bar--green span { background: var(--green); }
.bar--ink span { background: var(--ink); }

/* ---- Empty state ------------------------------------------------------- */
.empty { padding: 52px 24px; text-align: center; }
.empty svg { width: 30px; height: 30px; color: var(--mist); margin: 0 auto 12px; }
.empty__title { font-family: var(--f-display); font-size: 15px; font-weight: 700; }
.empty__body { margin-top: 5px; font-size: 13px; color: var(--steel); max-width: 44ch; margin-inline: auto; }

/* ---- Dropzone ---------------------------------------------------------- */
.drop {
  border: 1.5px dashed var(--mist);
  border-radius: var(--r);
  padding: 24px 18px;
  text-align: center;
  background: var(--paper);
  cursor: pointer;
  transition: border-color .14s ease, background-color .14s ease;
}
.drop:hover, .drop.is-over { border-color: var(--crimson); background: var(--crimson-lt); }
.drop svg { width: 22px; height: 22px; color: var(--steel-lt); margin: 0 auto 9px; }
.drop__name { font-weight: 600; }
/* A document that has been read says so. The panel is rebuilt the instant a
   file is parsed, so this state is derived from what is loaded, not set. */
.drop.is-loaded { border-style: solid; border-color: var(--green); background: var(--green-lt); }
.drop.is-loaded:hover, .drop.is-loaded.is-over { border-color: var(--green); background: var(--green-lt); }
.drop.is-loaded svg { color: var(--green); }

.filerow {
  display: flex; align-items: center; gap: 11px;
  padding: 10px 12px;
  border: 1px solid var(--hair); border-radius: var(--r);
  background: var(--card);
}
.filerow__ico {
  width: 32px; height: 32px; flex: none;
  border-radius: var(--r-sm);
  background: var(--crimson-lt); color: var(--crimson);
  display: flex; align-items: center; justify-content: center;
}
.filerow__ico svg { width: 16px; height: 16px; }

/* ---- Announcements ----------------------------------------------------- */
.ann { padding: 15px 18px; border-bottom: 1px solid var(--hair-soft); }
.ann:last-child { border-bottom: 0; }
.ann__title { font-family: var(--f-display); font-size: 14px; font-weight: 700; letter-spacing: -.01em; }
.ann__body { margin-top: 6px; font-size: 13px; line-height: 1.6; color: var(--steel); white-space: pre-wrap; }

/* ---- Login ------------------------------------------------------------- */
.login {
  min-height: 100vh;
  display: grid;
  grid-template-columns: 1.05fr .95fr;
}
.login__aside {
  background: var(--ink);
  color: #fff;
  padding: 46px 52px;
  display: flex; flex-direction: column;
  position: relative; overflow: hidden;
}
/* Ledger rule field — the receipt bars of the logomark, blown up as texture */
.login__rules {
  position: absolute; inset: 0;
  background-image: repeating-linear-gradient(
    180deg,
    rgba(255,255,255,.045) 0px,
    rgba(255,255,255,.045) 13px,
    transparent 13px,
    transparent 30px
  );
  mask-image: linear-gradient(105deg, #000 8%, transparent 62%);
  -webkit-mask-image: linear-gradient(105deg, #000 8%, transparent 62%);
  pointer-events: none;
}
.login__mark {
  position: absolute; right: -110px; bottom: -90px;
  width: 460px; opacity: .05; pointer-events: none;
}
/* Lift only the in-flow children above the two decorative layers. Scoping this
   by class matters: a `.login__aside > *` rule would out-specify the
   `position: absolute` above and drop the watermark back into the flow. */
.login__logo,
.login__pitch,
.login__sub,
.login__list,
.login__facts { position: relative; z-index: 1; }
.login__logo { width: 208px; }
.login__pitch {
  margin-top: auto;
  font-family: var(--f-display);
  font-size: clamp(30px, 3.6vw, 46px);
  font-weight: 700;
  letter-spacing: -.035em;
  line-height: 1.06;
  max-width: 14ch;
}
.login__pitch em { font-style: normal; color: var(--crimson); }
.login__sub { margin-top: 16px; font-size: 14.5px; line-height: 1.6; color: rgba(255,255,255,.62); max-width: 44ch; }

/* What the portal actually gives them, scannable in a couple of seconds.
   Same crimson eyebrow + hairline rules as the rest of the product, so the
   sign-in screen reads as the same thing they are about to log into. */
.login__list { margin-top: 22px; max-width: 50ch; }
.login__row { display: flex; gap: 16px; align-items: baseline; padding: 9px 0; }
.login__row + .login__row { border-top: 1px solid rgba(255, 255, 255, .1); }
.login__row-key {
  flex: none; width: 108px;
  font-family: var(--f-display);
  font-size: 10px; font-weight: 600; letter-spacing: .16em; text-transform: uppercase;
  color: var(--crimson);
}
.login__row-val { font-size: 13.5px; line-height: 1.5; color: rgba(255, 255, 255, .72); }

.login__facts { margin-top: 26px; display: flex; gap: 34px; flex-wrap: wrap; }

/* Short laptop screens: tighten so the live counters stay above the fold
   rather than being pushed off the bottom of the panel. */
@media (max-height: 820px) {
  .login__aside { padding-top: 34px; padding-bottom: 34px; }
  .login__pitch { font-size: clamp(28px, 3vw, 38px); }
  .login__sub { margin-top: 13px; font-size: 13.5px; }
  .login__list { margin-top: 16px; }
  .login__row { padding: 7px 0; }
  .login__facts { margin-top: 20px; }
}
.login__fact .eyebrow { color: rgba(255,255,255,.42); }
.login__fact strong {
  display: block; margin-top: 7px;
  font-family: var(--f-mono); font-variant-numeric: tabular-nums;
  font-size: 21px; font-weight: 500; letter-spacing: -.03em;
}

.login__form {
  display: flex; align-items: center; justify-content: center;
  padding: 46px 40px;
  background: var(--card);
}
.login__card { width: 100%; max-width: 372px; }
/* .demo-key styled the sign-in screen's account picker, deleted from auth.js
   on 2026-08-11 along with the credentials it printed. */

/* ---- Charts ------------------------------------------------------------ */
.chart { width: 100%; display: block; overflow: visible; }
.chart text { font-family: var(--f-mono); font-size: 10px; fill: var(--steel-lt); }
.chart .grid { stroke: var(--hair-soft); stroke-width: 1; }
.chart .axis { stroke: var(--hair); stroke-width: 1; }

.funnel-row { display: flex; align-items: center; gap: 12px; padding: 9px 0; }
.funnel-row__name { width: 116px; flex: none; font-size: 12.5px; font-weight: 500; }
.funnel-row__track { flex: 1 1 auto; height: 24px; background: var(--hair-soft); border-radius: var(--r-sm); overflow: hidden; }
.funnel-row__fill { height: 100%; background: var(--ink); border-radius: var(--r-sm); transition: width .5s cubic-bezier(.3,.8,.3,1); }
.funnel-row__fill--crimson { background: var(--crimson); }
.funnel-row__val { width: 74px; flex: none; text-align: right; font-family: var(--f-mono); font-size: 12.5px; font-variant-numeric: tabular-nums; }

/* ---- Utility ----------------------------------------------------------- */
.divider { height: 1px; background: var(--hair); }
.stack { display: flex; flex-direction: column; }
.stack > * + * { border-top: 1px solid var(--hair-soft); }
.link { color: var(--crimson); font-weight: 600; }
.link:hover { text-decoration: underline; }
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; border: 0;
}
.copyline {
  display: flex; align-items: center; gap: 8px;
  padding: 9px 11px;
  background: var(--paper); border: 1px solid var(--hair); border-radius: var(--r);
  font-family: var(--f-mono); font-size: 12.5px;
}

/* Entrance stagger — subtle, only on view swap */
.view > * { animation: pop .26s cubic-bezier(.22,.7,.3,1) backwards; }
.view > *:nth-child(1) { animation-delay: 0ms; }
.view > *:nth-child(2) { animation-delay: 35ms; }
.view > *:nth-child(3) { animation-delay: 70ms; }
.view > *:nth-child(4) { animation-delay: 100ms; }
.view > *:nth-child(n+5) { animation-delay: 125ms; }

/* ---- Mobile ------------------------------------------------------------ */
.rail__scrim { display: none; }
.menu-btn { display: none; }

@media (max-width: 1080px) {
  .login { grid-template-columns: 1fr; }
  .login__aside { padding: 30px 26px 34px; }
  .login__pitch { margin-top: 30px; font-size: 30px; }
  .login__facts { margin-top: 22px; gap: 22px; }
  .login__mark { display: none; }
}

@media (max-width: 900px) {
  .rail {
    position: fixed; left: 0; top: 0; bottom: 0;
    transform: translateX(-100%);
    transition: transform .22s cubic-bezier(.22,.7,.3,1);
    z-index: 80;
  }
  .rail.is-open { transform: none; }
  .rail__scrim.is-on {
    display: block; position: fixed; inset: 0; z-index: 79;
    background: rgba(16,24,32,.4);
  }
  .menu-btn { display: inline-flex; }
  .topbar { padding: 0 16px; gap: 10px; }
  .view { padding: 18px 16px 56px; }
  .grid-2, .grid-3, .split { grid-template-columns: 1fr; }
  .stats { grid-template-columns: 1fr 1fr; }
  .stat { border-bottom: 1px solid var(--hair-soft); }
  .stat:nth-child(2n) { border-right: 0; }
  .stepper { flex-wrap: wrap; }
  .step { flex-basis: calc(50% - 2px); border-radius: var(--r) !important; }
  .drawer { width: 100vw; }
  .funnel-row__name { width: 84px; font-size: 11.5px; }
}

@media (max-width: 560px) {
  /* A fixed label column leaves too little room on a phone and every row
     wraps. Stacking is both shorter and easier to scan. */
  .login__row { flex-direction: column; gap: 3px; padding: 8px 0; }
  .login__row-key { width: auto; }
  .login__row-val { font-size: 13px; }

  .stats { grid-template-columns: 1fr; }
  .stat { border-right: 0; }
  .stub { padding: 22px 18px 20px; }
  .stub__watermark { display: none; }
  .topbar { height: 60px; }
  .h1 { font-size: 20px; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
  }
}

@media print {
  .rail, .topbar, .btn, .toasts { display: none !important; }
  .view { padding: 0; }
  .panel, .stub { border-color: #ccc; box-shadow: none; }
}

/* ==========================================================================
   Signatures — the account section, the placement editor and the record
   Added 2026-09-07 with the send-for-signature feature.
   ========================================================================== */

/* Status on a document. Deliberately built on .chip rather than .badge: these
   sit at the end of a row of text at reading size, and a badge at 11px next to
   a 13px filename reads as a footnote rather than as the thing you scan for. */
.chip--blue { background: var(--blue-lt);    border-color: var(--blue-lt);    color: var(--blue); }
.chip--ok   { background: var(--green-lt);   border-color: var(--green-lt);   color: var(--green); }
.chip--err  { background: var(--crimson-lt); border-color: var(--crimson-lt); color: var(--crimson); }
.chip--blue:hover, .chip--ok:hover, .chip--err:hover { border-color: currentColor; }

/* A neutral aside inside the signing screens. NOT `.note`, which this
   stylesheet deliberately leaves unstyled and which forty other places use for
   plain text. */
.signote {
  padding: 11px 13px;
  border: 1px solid var(--hair);
  border-left: 3px solid var(--blue);
  border-radius: var(--r-sm);
  background: var(--blue-lt);
  color: var(--ink-2);
  font-size: 13px; line-height: 1.55;
}
.signote--ok { border-left-color: var(--green); background: var(--green-lt); }
/* A send going out with the agent's own boxes empty. Amber rather than red on
   purpose: Greg's answer to question 5 (2026-09-17) was warn, never refuse, and
   a red panel beside a button that still works reads as a fault rather than a
   note. Found needed by the four-step send flow. */
.signote--warn { border-left-color: var(--amber); background: var(--amber-lt); }

/* The seal. Monospace and allowed to break anywhere, because 64 hex characters
   in a proportional face is unreadable and 64 that overflow their box is
   worse. */
.seal {
  font-family: var(--f-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
  font-size: 12px; line-height: 1.6; letter-spacing: .01em;
  color: var(--ink-2); word-break: break-all;
}

/* ---- The three-step send ------------------------------------------------ */
.steps { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.steps__s { display: flex; align-items: center; gap: 7px; }
.steps__s + .steps__s::before {
  content: ""; width: 22px; height: 1px; background: var(--hair); margin-right: 7px;
}
.steps__n {
  width: 22px; height: 22px; flex: none; border-radius: 50%;
  border: 1px solid var(--hair); background: var(--card);
  display: flex; align-items: center; justify-content: center;
  font-size: 11.5px; font-weight: 600; color: var(--steel-lt);
}
.steps__t { font-size: 12.5px; color: var(--steel); }
.steps__s.is-on .steps__n { background: var(--accent); border-color: var(--accent); color: #fff; }
.steps__s.is-on .steps__t { color: var(--ink); font-weight: 600; }
.steps__s.is-done .steps__n { background: var(--green-lt); border-color: var(--green-lt); color: var(--green); }

/* ---- The placement editor ----------------------------------------------- */
.fieldbar {
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
  padding: 9px 11px; border: 1px solid var(--hair); border-radius: var(--r);
  background: var(--paper);
  position: sticky; top: 0; z-index: 3;
}
.fieldbar__hint { font-size: 12px; color: var(--steel-lt); margin-right: 2px; }
.fieldbar__k {
  border: 1px solid var(--hair); background: var(--card);
  border-radius: 999px; padding: 5px 11px;
  /* Longhand: `inherit` is not a valid family inside the font shorthand, so
     `font: 600 12px/1 inherit` is dropped entirely and the button renders in
     the browser default. Same bug as the signing page's consent block. */
  font-family: inherit; font-size: 12px; font-weight: 600; line-height: 1;
  color: var(--steel); cursor: pointer;
}
.fieldbar__k:hover { border-color: var(--mist); color: var(--ink); }
.fieldbar__k.is-on { background: var(--ink); border-color: var(--ink); color: #fff; }

.docpage {
  position: relative; border: 1px solid var(--hair); border-radius: var(--r);
  overflow: hidden; background: var(--card);
}
/* ⚠ The image is the coordinate frame every field is measured against, so it
   must fill the width exactly and carry no border of its own. A field's x is a
   fraction of THIS element's box; anything that changes that box relative to
   the rendered page moves every box on it. */
.docpage__img { display: block; width: 100%; height: auto; }
.docpage__no {
  position: absolute; right: 8px; top: 8px;
  background: rgba(16, 24, 32, .62); color: #fff;
  border-radius: 999px; padding: 2px 9px; font-size: 11px;
}

.fieldbox {
  position: absolute;
  border: 1.5px dashed var(--blue);
  background: rgba(43, 108, 176, .12);
  border-radius: 3px;
  cursor: move; touch-action: none;
  display: flex; align-items: center;
  min-width: 14px; min-height: 12px;
}
.fieldbox--signature, .fieldbox--initials {
  border-style: solid; background: rgba(43, 108, 176, .20);
}
/* Each signer gets a colour, because on a two-signer agreement the only thing
   distinguishing "the merchant signs here" from "we countersign here" is which
   box is which, and reading a number in 9px type is not that. */
.fieldbox--s2 { border-color: var(--green); background: rgba(28, 122, 86, .14); }
.fieldbox--s3 { border-color: var(--amber); background: rgba(160, 110, 20, .14); }
.fieldbox--s4 { border-color: var(--crimson); background: rgba(187, 32, 49, .12); }

/* Who fills a box, legible on the page rather than only inside the dialog that
   sets it. Greg's answer to question 4 (2026-09-17) was three sources, and an
   editor where the important property is invisible until you double-click is an
   editor where half the fields are wrong and nobody can see it.
   ⚠ These come AFTER the per-signer colours so that a record or agent box does
   not also read as signer 2's. */
.fieldbox--fill-record {
  border-style: solid; border-color: var(--steel);
  background: rgba(88, 104, 122, .12);
}
.fieldbox--fill-sender {
  border-style: solid; border-color: var(--green);
  background: rgba(28, 122, 86, .12);
}
.fieldbox__label {
  font-size: 10.5px; font-weight: 600; color: inherit;
  padding: 0 4px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  pointer-events: none;
}
.fieldbox__x {
  position: absolute; right: -8px; top: -8px;
  width: 17px; height: 17px; border-radius: 50%;
  border: 1px solid var(--hair); background: var(--card);
  color: var(--steel); font-size: 12px; line-height: 1; cursor: pointer;
  display: flex; align-items: center; justify-content: center; padding: 0;
}
.fieldbox__x:hover { background: var(--crimson); border-color: var(--crimson); color: #fff; }
.fieldbox__grip {
  position: absolute; right: -4px; bottom: -4px;
  width: 11px; height: 11px; border-radius: 2px;
  background: var(--card); border: 1.5px solid currentColor;
  cursor: nwse-resize;
}
/* Required, said out loud. It was always enforced in sign_document(), but the
   only way to reach it was a double-click nothing mentioned — so on the
   signing screen it read as a feature that did not exist. Mirrors __x on the
   opposite corner so the two controls read as a pair. */
.fieldbox__req {
  position: absolute; left: -8px; top: -8px;
  width: 17px; height: 17px; border-radius: 50%;
  border: 1px solid var(--hair); background: var(--card);
  color: var(--steel-lt); font: 700 13px/1 var(--f-body); cursor: pointer;
  display: flex; align-items: center; justify-content: center; padding: 0;
}
.fieldbox__req:hover { border-color: var(--steel); color: var(--ink); }
.fieldbox__req.is-on { background: var(--crimson); border-color: var(--crimson); color: #fff; }
/* The page being dragged onto. Outline rather than border: a border would
   change .docpage's box, and every field's x is a fraction of that box. */
.docpage.is-over { outline: 2px dashed var(--crimson); outline-offset: 3px; }

/* ---- The record --------------------------------------------------------- */
.kvgrid {
  display: grid; grid-template-columns: 150px 1fr; gap: 4px 14px;
  font-size: 13px; align-items: baseline;
}
.kvgrid__k {
  font-size: 10px; font-weight: 700; letter-spacing: .07em; text-transform: uppercase;
  color: var(--steel-lt);
}
.kvgrid__v { color: var(--ink-2); }

/* The trail. Three columns so the times line up down the page — a list of
   events whose timestamps do not align is a list nobody reads twice. */
.trail {
  display: grid; grid-template-columns: minmax(140px, auto) 1fr minmax(110px, auto);
  gap: 3px 14px; font-size: 12.5px; align-items: baseline;
}
.trail__t { color: var(--steel-lt); font-variant-numeric: tabular-nums; }
.trail__e { color: var(--ink-2); }
.trail__ip { color: var(--steel); font-variant-numeric: tabular-nums; text-align: right; }

.filerow--click { cursor: pointer; }
.filerow--click:hover { border-color: var(--mist); background: var(--paper); }
.filerow--click:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.panel--flat { border: 1px solid var(--hair); border-radius: var(--r); padding: 12px 14px; box-shadow: none; }
/* The gap lives ON the grid, not on a utility class beside it. Written this way
   because the first use said `grid2 gap-10` — and .gap-10 does not exist on the
   scale (4/6/8/12/16/24), so the columns touched and nothing errored. A layout
   class that needs a second class to be usable will eventually be used without
   it. Found by check-classes on the signing screens, 2026-09-07. */
.grid2 { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 12px; }
.btnrow { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }

@media (max-width: 640px) {
  .kvgrid { grid-template-columns: 1fr; gap: 1px 0; }
  .kvgrid__k { margin-top: 8px; }
  .trail { grid-template-columns: 1fr; gap: 0; }
  .trail__t { margin-top: 8px; }
  .trail__ip { text-align: left; }
}
