/* ==========================================================================
   Takahashi Properties — components

   House rules:
     · nothing comes to a point except the brand glyph. Status is a round
       dot, corners are generous, buttons are soft
     · labels are sentence case at a size you can read across a desk. Tiny
       tracked-out capitals are what made the last pass feel sharp
     · one job per screen. An agent picks what they did and fills it in; a
       manager works the payment run top to bottom
     · the accent is the logo's blush-to-rose gradient, spent on the chosen
       thing, the primary action, and the figure that answers the screen's
       question
   ========================================================================== */

/* ==========================================================================
   1. Top line

   The only persistent chrome. An agent navigates from the hub and its
   pages, so there is nothing here but the brand and their account; a
   manager gets tabs, because they move between five places all day.
   ========================================================================== */
.topline {
  position: sticky;
  top: 0;
  z-index: 60;
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px 24px;
  min-height: var(--topline);
  padding: 12px 44px;
  background: var(--surface-glass);
  backdrop-filter: blur(20px) saturate(150%);
  -webkit-backdrop-filter: blur(20px) saturate(150%);
  border-bottom: var(--edge-w) solid var(--line);
}

.brand {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 4px 8px 4px 0;
  border: 0;
  background: transparent;
  cursor: pointer;
  flex-shrink: 0;
}

/* The mark with 高橋 breaking out of its top right edge, as in the logo.
   The kanji is larger than the artwork's proportion so it can be read, so
   it runs past the diamond; margin-right keeps the wordmark clear of it. */
.brand-glyph {
  position: relative;
  display: block;
  width: 48px;
  height: 48px;
  margin-right: 8px;
  flex-shrink: 0;
  transition: transform 0.4s var(--ease), filter 0.2s var(--ease);
}
.brand:hover .brand-glyph { transform: scale(1.06); filter: brightness(1.12); }

/* logo-mark.png, drawn at 4x for sharp screens */
.brand-mark {
  width: 48px;
  height: 48px;
  display: block;
}

/* A halo in the top line's own colour cuts the frame back around the
   characters, the way the artwork leaves a gap in the frame for them. */
.brand-kanji {
  position: absolute;
  left: 32px;
  top: 11px;
  font-family: var(--font-kanji);
  font-weight: 500;
  font-size: 10.5px;
  line-height: 1;
  letter-spacing: 0;
  white-space: nowrap;
  color: var(--taupe);
  text-shadow: 0 0 2px #151215, 0 0 2px #151215, 0 0 3px #151215;
}

.brand-word {
  font-family: var(--font-ui);
  font-weight: 300;
  font-size: 0.74rem;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--text);
  line-height: 1.4;
  text-align: left;
  white-space: nowrap;
}
/* Second line. Tracked to the same optical width as the first rather than
   the same letter-spacing — "REALTOR PORTAL" is the longer string, so
   matching the tracking would make it overhang the name it belongs to. */
.brand-word span {
  display: block;
  font-size: 0.63rem;
  letter-spacing: 0.15em;
  color: var(--text-dim);
}

.topline-right {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-left: auto;
  flex-shrink: 0;
}

/* Manager's peek at the agent side */
.modes {
  display: flex;
  gap: 3px;
  padding: 3px;
  border-radius: var(--radius);
  background: var(--surface-2);
}
.mode {
  height: 32px;
  padding: 0 14px;
  border: 0;
  border-radius: 10px;
  background: transparent;
  color: var(--text-ghost);
  font-family: var(--font-ui);
  font-size: 0.84rem;
  font-weight: 600;
  white-space: nowrap;
  cursor: pointer;
  transition: color 0.2s var(--ease), background 0.2s var(--ease);
}
.mode:hover { color: var(--text-dim); }
.mode[aria-pressed="true"] { background: var(--surface); color: var(--accent); }

/* Shifts: the same switch, but any number can be on (a checkbox in each) */
.shift-pick .mode { flex: 1; height: 40px; display: inline-flex; align-items: center; justify-content: center; position: relative; cursor: pointer; color: var(--text-dim); font-weight: 600; }
.shift-pick .mode:hover { color: var(--text); }
.shift-pick .mode input { position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none; }
.shift-pick .mode:has(input:checked) { background: var(--accent-grad); color: var(--accent-ink); }
.shift-pick .mode:has(input:focus-visible) { outline: 2px solid var(--accent); outline-offset: 1px; }
.shift-pick.needs-one { box-shadow: inset 0 0 0 var(--edge-w) var(--neg); }

.account {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 5px 12px 5px 5px;
  border: var(--edge-w) solid transparent;
  border-radius: var(--radius-pill);
  background: transparent;
  color: var(--text);
  font-family: var(--font-ui);
  text-align: left;
  cursor: pointer;
  transition: border-color 0.2s var(--ease), background 0.2s var(--ease);
}
.account:hover { background: var(--accent-wash); }
/* A person is shown by their initials, from the name set in the portal,
   in the pink of the primary buttons: the same bubble everywhere as the
   signed-in person's in the top line (Matt, 2026-09-28). */
.avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  border-radius: 50%;
  background: var(--accent-grad);
  color: var(--accent-ink);
  font-size: 0.8rem;
  font-weight: 700;
  letter-spacing: 0.02em;
  line-height: 1;
  flex-shrink: 0;
  user-select: none;
}
.account .avatar {
  width: 34px;
  height: 34px;
  font-size: 0.76rem;
}
.account-text { display: flex; flex-direction: column; min-width: 0; }
.account-name {
  font-size: 0.88rem;
  font-weight: 700;
  line-height: 1.25;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.account-meta {
  font-size: 0.76rem;
  line-height: 1.25;
  color: var(--text-faint);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.account svg { width: 16px; height: 16px; color: var(--text-ghost); flex-shrink: 0; }

@media (max-width: 1000px) {
  .topline { padding: 10px 22px; gap: 14px; }
  .brand-word { display: none; }
  .account-text { display: none; }
  .account { padding: 4px; }
  .account svg { display: none; }
  /* The Realtor / Manager switch used to be dropped here to buy room. It
     cannot be: a manager now signs in on the realtor side like everyone
     else, so this switch is the only way to reach the payment run, and
     hiding it strands them. The brand word and account name give up their
     space instead — and the two labels are short. */
}

@media (max-width: 620px) {
  .topline { padding: 10px 16px; gap: 10px; }
  .modes { padding: 2px; gap: 2px; }
  .mode { height: 30px; padding: 0 10px; font-size: 0.8rem; }
}

/* ==========================================================================
   2. Page headings — every screen names itself, since the chrome no longer
   does it for them.
   ========================================================================== */
.page-head { margin-bottom: 30px; }
.page-head h1 { font-size: 2rem; letter-spacing: -0.025em; }
.page-head p { margin-top: 6px; max-width: 64ch; font-size: 1rem; }

/* The way back up the flow: a pill like the hub links (opaque, foil edge),
   so it holds its own against the patterned page. It was bare faint text,
   which Matt found got lost in the background. */
.backlink {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  height: 40px;
  margin-bottom: 22px;
  padding: 0 18px 0 14px;
  border: var(--edge-w) solid transparent;
  border-radius: var(--radius-pill);
  background: var(--surface);
  color: var(--text);
  font-family: var(--font-ui);
  font-size: 0.94rem;
  font-weight: 700;
  cursor: pointer;
  transition: color 0.2s var(--ease), background 0.2s var(--ease), transform 0.2s var(--ease);
}
.backlink svg { width: 17px; height: 17px; color: var(--accent); }
.backlink:hover {
  color: var(--accent);
  background: linear-gradient(var(--accent-wash), var(--accent-wash)), var(--surface);
  transform: translateX(-3px);
}

/* ==========================================================================
   3. Buttons — soft, sentence case, sized to be hit easily
   ========================================================================== */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  height: 44px;
  padding: 0 20px;
  border: var(--edge-w) solid transparent;
  border-radius: var(--radius);
  background: transparent;
  color: var(--text);
  font-family: var(--font-ui);
  font-size: 0.92rem;
  font-weight: 700;
  white-space: nowrap;
  cursor: pointer;
  transition: background 0.2s var(--ease), color 0.2s var(--ease),
              transform 0.14s var(--ease), box-shadow 0.2s var(--ease);
}
.btn svg { width: 17px; height: 17px; flex-shrink: 0; }
.btn:hover { color: var(--accent); background: var(--accent-wash); }
.btn:active { transform: translateY(1px); }

/* The gradient is laid from the outer edge (border-box). By default it is
   sized to the padding box and repeats under the transparent 2px border,
   which left a thin strip of the wrong pink down each end. */
.btn-primary {
  border-color: transparent;
  background: var(--accent-grad) border-box;
  color: var(--accent-ink);
}
.btn-primary:hover {
  color: var(--accent-ink);
  background: var(--accent-grad) border-box;
  filter: brightness(1.06);
  box-shadow: 0 10px 26px -12px var(--accent-line);
}

/* Something that can't be undone (deleting a staff member): the plain button,
   in the red the money figures use for a loss. */
.btn-danger, .btn-danger:hover { color: var(--neg); }

/* A button kept apart from Cancel / Save, at the far left of a dialog's foot */
.modal-foot .foot-left { margin-right: auto; }
.modal-text { font-size: 0.92rem; color: var(--text-dim); }
.modal-text + .field-group { margin-top: 18px; }

.btn-ghost { border-color: transparent; color: var(--text-faint); }
.btn-ghost:hover { border-color: transparent; background: var(--surface-2); color: var(--text); }

.btn-icon { width: 44px; padding: 0; }
.btn-icon svg { width: 19px; height: 19px; }

.btn-sm { height: 34px; padding: 0 14px; font-size: 0.84rem; border-radius: 10px; }
.btn-sm svg { width: 14px; height: 14px; }
.btn-icon.btn-sm { width: 34px; }

.btn-lg { height: 52px; padding: 0 28px; font-size: 1rem; }

.btn-wide { width: 100%; }

.btn:focus-visible,
.hub-link:focus-visible,
.account:focus-visible,
.backlink:focus-visible,
.choice:focus-visible,
.demo-tab:focus-visible,
.demo-pick:focus-visible,
.slider:focus-visible,
.x-btn:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px var(--accent-wash), 0 0 0 1px var(--accent-line);
}

.x-btn {
  width: 36px;
  height: 36px;
  border: 0;
  border-radius: var(--radius);
  background: transparent;
  color: var(--text-faint);
  font-size: 1.5rem;
  line-height: 1;
  cursor: pointer;
  transition: color 0.2s var(--ease), background 0.2s var(--ease);
}
.x-btn:hover { color: var(--text); background: var(--surface-2); }

.linkish {
  border: 0;
  background: none;
  padding: 0;
  font: inherit;
  font-weight: 700;
  color: var(--accent);
  cursor: pointer;
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-color: var(--accent-line);
}
.linkish:hover { text-decoration-color: var(--accent); }

/* ==========================================================================
   4. Fields — big, plainly labelled
   ========================================================================== */
.field-group { margin-bottom: 20px; }
.field-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 18px; }

.field-label {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 8px;
  font-size: 0.88rem;
  font-weight: 700;
  color: var(--text);
}
.field-label .faint { font-weight: 400; font-size: 0.82rem; color: var(--text-faint); }

/* Inputs carry the foil too, but neither of the other two techniques works
   on them: pseudo-elements do not render on a replaced element, so no ring,
   and border-image would square off the radius. They get it from two
   background layers — the fill clipped to the padding box, the foil clipped
   to the border box — which is a genuine border, crisp corners and all.

   THE FILL HAS TO BE OPAQUE. background-clip paints the foil under the
   whole element, not just the rim, so a translucent fill lets roughly an
   eighth of it through and washes the inside of the input pink. That
   version shipped once and was rejected on sight. #1f1b1f and #171416 are
   --surface-2 and --surface already composited over the ground, so the
   input looks identical to the translucent version over the page — it just
   stops being a window. Which is right: a field is a well you read your own
   typing out of, not a view onto the sheet. */
.field {
  width: 100%;
  height: 48px;
  padding: 0 16px;
  border: var(--edge-w) solid transparent;
  border-radius: var(--radius);
  background: linear-gradient(#1f1b1f, #1f1b1f) padding-box,
              var(--foil-rule) border-box;
  color: var(--text);
  font-family: var(--font-ui);
  font-size: 1rem;
  transition: box-shadow 0.2s var(--ease), background 0.2s var(--ease);
}
.field::placeholder { color: var(--text-ghost); }
.field:focus {
  outline: none;
  background: linear-gradient(#171416, #171416) padding-box,
              var(--accent-grad) border-box;
  box-shadow: 0 0 0 3px var(--accent-wash);
}
.field[readonly] { color: var(--text-faint); cursor: not-allowed; }
.field.num, input[type="number"].field { font-variant-numeric: tabular-nums lining-nums; }

/* Money is step="0.01", so the spinner would nudge by a cent — useless, and
   it crowds the value it sits on top of. People type amounts. */
input[type="number"].field::-webkit-outer-spin-button,
input[type="number"].field::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}
input[type="number"].field { -moz-appearance: textfield; appearance: textfield; }
.field.mono { font-family: var(--font-mono); font-size: 0.86rem; }

textarea.field { height: auto; padding: 14px 16px; line-height: 1.6; resize: vertical; }

select.field {
  appearance: none;
  -webkit-appearance: none;
  padding-right: 40px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%237d7076' stroke-width='2.2' stroke-linecap='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 14px center;
  background-size: 16px;
  cursor: pointer;
}

/* ── Dropdowns (dropdowns.js) ───────────────────────────────────────────
   The browser's own <select> menu and <datalist> suggestions are a grey
   system list that no style reaches. Both are replaced by one list drawn in
   the portal's material. The real <select> stays in the form, hidden, and
   holds the value. */
select.field.dd-native {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}

.dd-button {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  text-align: left;
  cursor: pointer;
}
.dd-value { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dd-chev {
  width: 16px;
  height: 16px;
  flex-shrink: 0;
  color: var(--text-ghost);
  transition: transform 0.22s var(--ease), color 0.2s var(--ease);
}
.dd-button:hover .dd-chev { color: var(--text-dim); }
.dd-button.dd-open {
  background: linear-gradient(#171416, #171416) padding-box, var(--accent-grad) border-box;
  box-shadow: 0 0 0 3px var(--accent-wash);
}
.dd-button.dd-open .dd-chev { transform: rotate(180deg); color: var(--accent); }

/* The open list. Opaque, for the same reason the inputs are: it floats over
   text, and a translucent list would let that text read through it. */
div.dd-pop {               /* div.: outranks the foil block's position: relative */
  position: fixed;
  z-index: 300;              /* over dialogs (200), under the demo tab and toasts */
  display: flex;
  flex-direction: column;
  overflow: hidden;          /* the options scroll in .dd-scroll, so the edge stays put */
  border: var(--edge-w) solid transparent;
  border-radius: var(--radius);
  background: #1f1b1f;
  box-shadow: var(--lift), var(--bevel);
  --foil-edge: 0.82;
  animation: dd-in 0.16s var(--ease);
  scrollbar-width: thin;
}
.dd-pop[hidden] { display: none; }
.dd-scroll { min-height: 0; padding: 6px; overflow-y: auto; scrollbar-width: thin; overscroll-behavior: contain; }
.dd-pop[data-side="up"] { animation-name: dd-in-up; }
@keyframes dd-in    { from { opacity: 0; transform: translateY(-4px); } }
@keyframes dd-in-up { from { opacity: 0; transform: translateY(4px); } }
@media (prefers-reduced-motion: reduce) { .dd-pop { animation: none; } }

.dd-option {
  display: flex;
  align-items: center;
  gap: 12px;
  min-height: 42px;
  padding: 9px 12px;
  border-radius: 10px;
  color: var(--text-dim);
  font-size: 0.95rem;
  cursor: pointer;
}
.dd-option.active { background: var(--accent-wash); color: var(--text); }
.dd-option[aria-selected="true"] { color: var(--accent); font-weight: 700; }
.dd-label { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dd-meta {
  flex-shrink: 0;
  font-size: 0.84rem;
  color: var(--text-faint);
  font-variant-numeric: tabular-nums;
}
.dd-option.active .dd-meta { color: var(--text-dim); }
.dd-tick { width: 16px; height: 16px; flex-shrink: 0; }

.field-hint {
  display: block;
  margin-top: 8px;
  font-size: 0.84rem;
  line-height: 1.55;
  color: var(--text-faint);
}

.check {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  font-size: 0.92rem;
  color: var(--text-dim);
  cursor: pointer;
}
.check input {
  width: 18px;
  height: 18px;
  margin-top: 3px;
  accent-color: var(--accent);
  flex-shrink: 0;
  cursor: pointer;
}

/* The auto / manual flag on the derived realtor fee */
.derived { font-size: 0.82rem; font-weight: 600; color: var(--taupe); white-space: nowrap; }
.derived.manual { color: var(--warn); }
.derived .linkish { font-size: 0.82rem; }

/* Filter */
.search { position: relative; display: flex; align-items: center; }
.search svg {
  position: absolute;
  left: 14px;
  width: 16px;
  height: 16px;
  color: var(--text-ghost);
  pointer-events: none;
}
.search .field { height: 40px; width: 230px; padding-left: 40px; font-size: 0.9rem; }
@media (max-width: 760px) { .search { width: 100%; } .search .field { width: 100%; } }

/* "Per page" beside a table's search box */
.per-page { display: flex; align-items: center; gap: 10px; font-size: 0.86rem; color: var(--text-dim); white-space: nowrap; }
.per-page .dd-button { height: 40px; width: 100px; font-size: 0.9rem; }

/* ==========================================================================
   4b. Foil rules

   Every edge in the app is drawn in the same pink foil. Two techniques,
   because a border-color cannot hold a gradient, but one material.

   ROUNDED BOXES get a ring from ::after: the foil fills the box and is then
   masked by itself minus its own content box, leaving only the band between
   the two, which follows the radius.

   This was tried at 1px and abandoned — subtracting two antialiased curves
   a single pixel apart leaves the arc visibly stepped. At --edge-w (2px)
   there is enough headroom in the subtraction for the curve to come out
   clean, checked against a real border at 1:1 and on a pill, where the arc
   is hardest. If --edge-w ever goes back to 1px, this has to go too.

   The ring sits at `inset: 0`, the padding-box edge, not `-1px`. `.choice`,
   `.flow` and `.modal-content` clip to `overflow: hidden`, and a ring pushed
   out to the border box is clipped clean away on exactly those.

   THE BORDER UNDER A RING MUST BE TRANSPARENT, and every ringed rule says so
   itself rather than leaning on the `border-color` below — those rules come
   later in this file, so a colour there wins and paints a SECOND edge
   outside the ring. On the straights the two sit flush and read as one
   thick line, but through a corner they separate: the border's inner arc has
   radius R-2 while the ring inherits R, so the two curves pull apart and
   leave a dark wedge of background between them at 45°. That was the
   "rough corners" for months. One edge per box, always.

   STATE IS THE RING, not a second edge: --foil-edge is the ring's opacity
   and any rule can raise it (an active step, the lead figure), and the two
   places where colour carries meaning rather than emphasis — .note.attn and
   .note.bad — recolour the ring's own background instead.

   STRAIGHT RULES have no curve, so they take the foil through border-image
   and cost no extra element. Table cells are the one exception: table.tbl
   is `border-collapse: collapse`, where border-image is not reliable, so
   its row hairlines stay flat --line-soft.
   ========================================================================== */
.topline, .panel-head, .flow-actions, .done-lines, .done-line, .flow-side,
.drawer, .drawer-head, .modal-header, .modal-foot, .rate,
.calc-grid > div:last-child, .rate-preview > div {
  border-image: var(--foil-rule) 1;
}

.panel, .inset, .money-item, .choice, .hub-link, .backlink, .flow, .done, .step,
.modal-content, .auth-card, .account, .demo-pop, .demo-tab, .note, .signin-notice,
.modal-body .table-wrap, .tag.mute, .dd-pop,
.btn:not(.btn-primary):not(.btn-ghost) {
  position: relative;
  border-color: transparent;
}

.panel::after, .inset::after, .money-item::after, .choice::after,
.hub-link::after, .backlink::after, .flow::after, .done::after, .step::after,
.modal-content::after, .auth-card::after, .account::after,
.demo-pop::after, .demo-tab::after, .note::after, .signin-notice::after,
.modal-body .table-wrap::after, .tag.mute::after, .dd-pop::after,
.btn:not(.btn-primary):not(.btn-ghost)::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  padding: var(--edge-w);
  background: var(--tex-foil);
  opacity: var(--foil-edge);
  -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
  mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
  -webkit-mask-composite: xor;
  mask-composite: exclude;
  pointer-events: none;
  transition: opacity 0.24s var(--ease);
}

/* Hover lifts the foil rather than recolouring an edge that no longer has a
   colour of its own to recolour. */
.choice:hover::after, .hub-link:hover::after, .backlink:hover::after, .demo-tab:hover::after,
.account:hover::after, .btn:not(.btn-primary):not(.btn-ghost):hover::after {
  opacity: 0.95;
}

/* A step above every other edge. It is the one rule that separates the whole
   app from its chrome, and the extra pixel gives the foil room to show its
   range rather than averaging to a flat pink. */
.topline { border-bottom-width: calc(var(--edge-w) + 1px); }

/* ==========================================================================
   5. Panels
   ========================================================================== */
.panel {
  background: var(--surface);
  border: var(--edge-w) solid transparent;
  border-radius: var(--radius-lg);
  box-shadow: var(--bevel);
  padding: 26px 30px 28px;
  margin-bottom: 26px;
}
.panel:last-child { margin-bottom: 0; }

.panel-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 24px;
  flex-wrap: wrap;
  padding-bottom: 18px;
  border-bottom: var(--edge-w) solid var(--line);
}
.panel-head h2 { font-size: 1.16rem; }
.panel-head p { margin-top: 5px; max-width: 76ch; font-size: 0.9rem; }

.panel-count {
  margin-left: 10px;
  font-size: 0.95rem;
  font-weight: 700;
  color: var(--text-ghost);
  font-variant-numeric: tabular-nums;
}
/* Open bids out of ten; amber past it */
.bid-count { color: var(--text-dim); }
.bid-count .bid-count-of { color: var(--text-ghost); }
.bid-count.over, .bid-count.over .bid-count-of { color: var(--warn); }
/* Past ten: the warning in line after the count, with the amber dot notes use */
.bids-over {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin-left: 18px;
  font-size: 0.92rem;
  font-weight: 600;
  color: var(--warn);
  vertical-align: 2px;
}
.bids-over::before {
  content: '';
  flex: none;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--warn);
}

/* Realtor bids (manager): a dropdown per realtor (the Payments page's cards), the holder picked per bid */
.panel-head + .payees { margin-top: 18px; }   /* clear of the heading's rule, as the head is of its title */
.realtor-bids .payee-head { grid-template-columns: 40px minmax(0, 1fr) auto auto; }
.realtor-bids-count .panel-count { margin-left: 0; font-size: 1.05rem; }
.realtor-bids .payee-body, .realtor-bids.open .payee-body { padding-left: 0; padding-right: 0; }
.bid-holder .dd-button { min-width: 210px; }
/* On a phone the count stays before Show/Hide (Payments moves its toggle to the end) */
@media (max-width: 640px) {
  .realtor-bids .payee-head { grid-template-columns: 36px minmax(0, 1fr) auto auto; }
  .realtor-bids .payee-toggle { grid-column: auto; grid-row: auto; }
}

.panel-head-actions { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
/* A row's own buttons (My bids: Record sale, Edit, Remove), kept on one line */
.row-actions { display: inline-flex; justify-content: flex-end; gap: 8px; white-space: nowrap; }

.inset {
  background: var(--surface-2);
  border: var(--edge-w) solid transparent;
  border-radius: var(--radius);
  padding: 22px 24px;
}

/* ==========================================================================
   6. Money strip — the plain figure row both roles get
   ========================================================================== */
.money {
  display: flex;
  flex-wrap: wrap;
  gap: 14px;
  margin-bottom: 26px;
}

.money-item {
  flex: 1 1 180px;
  min-width: 0;
  padding: 20px 22px;
  background: var(--surface);
  border: var(--edge-w) solid transparent;
  border-radius: var(--radius-lg);
  box-shadow: var(--bevel);
}
.money-label { display: block; font-size: 0.88rem; font-weight: 600; color: var(--text-faint); }
.money-value {
  display: block;
  margin-top: 6px;
  font-size: 1.72rem;
  font-weight: 800;
  line-height: 1.15;
  letter-spacing: -0.02em;
  color: var(--text);
  font-variant-numeric: tabular-nums lining-nums;
}
.money-note { display: block; margin-top: 4px; font-size: 0.82rem; color: var(--text-faint); }

/* The wash is composited over an opaque surface rather than used alone:
   at 13% alpha the petals drift straight through it and cross the figure. */
.money-item.lead {
  flex: 1.4 1 240px;
  /* emphasis is the foil lifted, not a second edge painted over it */
  --foil-edge: 0.95;
  background: linear-gradient(var(--accent-wash), var(--accent-wash)), var(--surface);
}
.money-item.lead .money-value { color: var(--accent); font-size: 2rem; }
.money-value.warn { color: var(--warn); }

/* ==========================================================================
   7. The hub — an agent's whole starting point

   Four doors, then the things they might want to look at, then their
   money. Choosing a door leaves this page entirely.
   ========================================================================== */
/* The full logo, faint, in the bottom right corner behind every realtor and
   manager screen, running off the edge. Fixed to the window, so it stays put
   while a page scrolls; a fixed box that runs off the window adds no
   scrolling. It sits with the lattice (z-index -2, after it in the page), so
   the falling petals still pass in front of it. Hidden on sign-in and the
   waiting card (data-authed="false"), which show the logo itself. */
.page-watermark {
  position: fixed;
  right: -70px;
  bottom: -110px;
  z-index: -2;
  width: 560px;
  height: auto;
  opacity: 0.08;
  pointer-events: none;
  user-select: none;
}
.shell[data-authed="false"] > .page-watermark { display: none; }
@media (max-width: 620px) {
  .page-watermark { width: 320px; right: -40px; bottom: -60px; }
}

.hub-greet { margin-bottom: 34px; }
.hub-greet h1 { font-size: 2.4rem; letter-spacing: -0.03em; }
.hub-greet p { margin-top: 8px; font-size: 1.05rem; }

/* Four doors, and they have to read as one row of four — 258px min left
   the fourth stranded on its own line at this measure. */
.choices {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(226px, 1fr));
  gap: 18px;
  margin-bottom: 34px;
}

.choice {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 8px;
  min-height: 212px;
  padding: 28px 28px 26px;
  border: var(--edge-w) solid transparent;
  border-radius: var(--radius-lg);
  background: var(--surface);
  box-shadow: var(--bevel);
  color: var(--text);
  font-family: var(--font-ui);
  text-align: left;
  cursor: pointer;
  overflow: hidden;
  transition: transform 0.24s var(--ease), box-shadow 0.24s var(--ease);
}
.choice:hover {
  transform: translateY(-4px);
  box-shadow: var(--lift-sm), var(--bevel);
}

.choice-mark {
  width: 52px;
  height: 52px;
  margin-bottom: 10px;
  display: grid;
  place-items: center;
  border-radius: 16px;
  background: var(--surface-3);
  color: var(--accent);
  transition: background 0.24s var(--ease), color 0.24s var(--ease);
}
.choice-mark svg { width: 26px; height: 26px; }
.choice:hover .choice-mark { background: var(--accent-wash); }

.choice-name { font-size: 1.24rem; font-weight: 700; letter-spacing: -0.015em; }
.choice-note { font-size: 0.94rem; color: var(--text-faint); line-height: 1.5; }
/* On the manager's home, a door with something waiting behind it says so */
.choice-note.attn { color: var(--accent); font-weight: 600; }
/* A second, quieter fact under the note (when pay last went out) */
.choice-sub { margin-top: -4px; font-size: 0.84rem; color: var(--text-faint); }

/* Payments: when pay last went out, which is also the verification window */
.last-pay {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 4px 10px;
  margin: -6px 0 22px;
  font-size: 0.94rem;
  color: var(--text-faint);
}
.last-pay strong { color: var(--text); font-weight: 700; }

.bid-verdict { margin: 18px 0; }

/* A field holding a figure that cannot be right. The edge is the input's
   own foil layer recoloured, so it stays one edge, not a second. */
.field.invalid,
.field.invalid:focus {
  background: linear-gradient(#1f1b1f, #1f1b1f) padding-box,
              linear-gradient(var(--neg), var(--neg)) border-box;
}
/* --neg sits close to the pink foil, so the glow is what makes it read as wrong */
.field.invalid { box-shadow: 0 0 0 3px rgba(224, 148, 154, 0.22); }
.field.invalid:focus { box-shadow: 0 0 0 4px rgba(224, 148, 154, 0.3); }
.field-hint.error { color: var(--neg); font-weight: 600; }
.field-hint[hidden] { display: none; }

/* The requested bid, when there is one, is the answer — and whether it is
   enough is said in words, not only in colour. */
.bid-total { position: relative; }
.bid-total.bad {
  background: linear-gradient(rgba(224, 148, 154, 0.12), rgba(224, 148, 154, 0.12)), var(--surface);
  border-color: rgba(224, 148, 154, 0.45);
}
.bid-total.bad .total-value { color: var(--text); }
.bid-badge {
  position: absolute;
  top: 22px;
  right: 22px;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  height: 28px;
  padding: 0 12px;
  border-radius: var(--radius-pill);
  font-size: 0.84rem;
  font-weight: 700;
}
.bid-badge::before { content: ''; width: 7px; height: 7px; border-radius: 50%; background: currentColor; }
.bid-badge.ok  { color: var(--pos); background: rgba(134, 201, 164, 0.14); }
.bid-badge.bad { color: var(--neg); background: rgba(224, 148, 154, 0.16); }
.bid-need { margin-left: 6px; font-size: 0.8rem; font-weight: 400; color: var(--text-faint); }
/* inline, unlike the note's own heading <strong> */
.bid-needed { color: var(--text); font-weight: 700; white-space: nowrap; }

/* An agent's lookup row carries two actions side by side */
.lookup-actions { display: inline-flex; gap: 8px; }

.choice-go {
  margin-top: auto;
  padding-top: 16px;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 0.92rem;
  font-weight: 700;
  color: var(--accent);
  opacity: 0;
  transform: translateX(-6px);
  transition: opacity 0.24s var(--ease), transform 0.24s var(--ease);
}
.choice-go svg { width: 16px; height: 16px; }

/* A door that is there but not built yet: greyed, flat, no hover. */
.choice.soon { cursor: default; filter: grayscale(1); opacity: 0.45; }
.choice.soon:hover { transform: none; box-shadow: var(--bevel); }
.choice.soon:hover::after { opacity: var(--foil-edge); }
.choice.soon:hover .choice-mark { background: var(--surface-3); }
.choice-soon {
  margin-top: auto;
  padding-top: 16px;
  font-size: 0.92rem;
  font-weight: 600;
  color: var(--text-faint);
}
.choice:hover .choice-go, .choice:focus-visible .choice-go { opacity: 1; transform: none; }

/* No hover on a phone, so the affordance has to be there from the start */
@media (hover: none) {
  .choice-go { opacity: 1; transform: none; }
}

/* Secondary destinations — not things you do, things you look at.

   Centred, because this is the one row on the hub that does not fill the
   measure. The four doors above and the money strip below both run the full
   width, so their centre is the page's centre; left-aligning a short row
   between them left it hanging off to one side. Centred, every group of
   buttons on the page shares one axis. */
.hub-links {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 10px;
  margin-bottom: 36px;
}
.hub-link {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  height: 44px;
  padding: 0 20px;
  border: var(--edge-w) solid transparent;
  border-radius: var(--radius-pill);
  /* opaque, not transparent — these pills sit straight on the page, and a
     petal drifting behind one cuts through the label */
  background: var(--surface);
  color: var(--text-dim);
  font-family: var(--font-ui);
  font-size: 0.94rem;
  font-weight: 600;
  cursor: pointer;
  transition: color 0.2s var(--ease), background 0.2s var(--ease);
}
/* The realtor hub's links, and the money cards under them, each come as an
   equal pair: every item as wide as the widest in its own row needs, no
   wider, centred under the doors. 1fr tracks in a max-content grid come out
   equal, which is what does it. */
.hub-links.even, .money.even {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: 1fr;
  width: max-content;
  max-width: 100%;
  margin-left: auto;
  margin-right: auto;
}
.hub-links.even .hub-link { justify-content: center; }
.money.even .money-item { padding-right: 34px; }
@media (max-width: 620px) {
  .money.even { grid-auto-flow: row; width: 100%; }
}

.hub-link:hover {
  color: var(--accent);
  background: linear-gradient(var(--accent-wash), var(--accent-wash)), var(--surface);
}
.hub-link-count { font-weight: 700; color: var(--text-ghost); font-variant-numeric: tabular-nums; }

/* ==========================================================================
   8. A flow page — one form, on its own, with the running total beside it
   ========================================================================== */
.flow-head { margin-bottom: 30px; }
.flow-head h1 { font-size: 2.1rem; letter-spacing: -0.028em; }
.flow-head p { margin-top: 7px; max-width: 62ch; font-size: 1rem; }

.flow {
  display: grid;
  grid-template-columns: minmax(0, 1.12fr) minmax(300px, 0.88fr);
  gap: 0;
  background: var(--surface);
  border: var(--edge-w) solid transparent;
  border-radius: var(--radius-lg);
  box-shadow: var(--bevel);
  overflow: hidden;
}

.flow-form { padding: 32px 36px 34px; }
.flow-side {
  padding: 32px 36px 34px;
  border-left: var(--edge-w) solid var(--line);
  background: var(--surface-2);
}

.flow-actions {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  margin-top: 28px;
  padding-top: 26px;
  border-top: var(--edge-w) solid var(--line);
}
/* The note gets a line of its own and the buttons sit together under it,
   on the right, however long the submit button's label is. */
.flow-actions { justify-content: flex-end; }
.flow-actions .spread { flex: 1 0 100%; font-size: 0.9rem; color: var(--text-faint); }

@media (max-width: 900px) {
  .flow { grid-template-columns: minmax(0, 1fr); }
  .flow-form { padding: 26px 22px 28px; }
  .flow-side { padding: 26px 22px 28px; border-left: 0; border-top: var(--edge-w) solid var(--line); }
}

/* The answer to "what do I get for this", at the top of the side column */
.total {
  padding: 24px 26px;
  border-radius: var(--radius-lg);
  background: linear-gradient(var(--accent-wash), var(--accent-wash)), var(--surface);
  border: 1px solid var(--accent-line);
  margin-bottom: 22px;
}
.total-label { font-size: 0.95rem; font-weight: 600; color: var(--text-dim); }
.total-value {
  display: block;
  margin-top: 4px;
  font-size: 2.5rem;
  font-weight: 800;
  line-height: 1.1;
  letter-spacing: -0.03em;
  color: var(--accent);
  font-variant-numeric: tabular-nums lining-nums;
}
.total-note { display: block; margin-top: 6px; font-size: 0.9rem; color: var(--text-faint); }
.total-note.warn { color: var(--warn); font-weight: 600; }

/* ==========================================================================
   8b. The success screen that ends every flow
   ========================================================================== */
.done {
  max-width: 620px;
  margin: 18px auto 0;
  padding: 44px 44px 40px;
  text-align: center;
  background: var(--surface);
  border: var(--edge-w) solid transparent;
  border-radius: var(--radius-xl);
  box-shadow: var(--lift), var(--bevel);
}

/* The firm's logo heads the confirmation, as it heads the sign-in card */
.done-mark {
  display: block;
  width: 150px;
  height: auto;
  margin: -8px auto 18px;
}

.done h1 { font-size: 1.9rem; letter-spacing: -0.028em; }
.done > p { margin-top: 8px; font-size: 1rem; }

.done-lines {
  margin: 28px 0 8px;
  text-align: left;
  border-top: var(--edge-w) solid var(--line);
}
.done-line {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 20px;
  padding: 14px 2px;
  border-bottom: 1px solid var(--line-soft);
  font-size: 0.95rem;
  color: var(--text-dim);
}
.done-line > span:last-child {
  font-weight: 700;
  color: var(--text);
  font-variant-numeric: tabular-nums lining-nums;
  text-align: right;
}
.done-line.lead > span:last-child { color: var(--accent); font-size: 1.3rem; }
/* A second line under a label: a payee's State ID and count on the pay summary */
.done-line small { display: block; margin-top: 2px; font-size: 0.8rem; color: var(--text-faint); }
.done-line > span:first-child { text-align: left; }
/* A line that breaks down the one above it (each person under Total paid): indented, a little quieter */
.done-line.sub { padding-left: 26px; font-size: 0.92rem; }
.done-line.sub > span:last-child { font-weight: 600; color: var(--text-dim); }

.done-actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 10px;
  margin-top: 30px;
}

@media (max-width: 620px) {
  .done { padding: 34px 22px 30px; }
  .done h1 { font-size: 1.6rem; }
}

/* ==========================================================================
   8b. Sale summary — everything recorded for one sale
   ========================================================================== */
.sale-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 16px 28px;
  flex-wrap: wrap;
}
.sale-state { display: flex; align-items: center; gap: 12px; padding-bottom: 4px; }
/* The status as a boxed badge, tinted its own colour, so it holds its corner */
.sale-state .state {
  padding: 8px 16px;
  font-size: 0.92rem;
  font-weight: 700;
  border: 1px solid color-mix(in srgb, currentColor 45%, transparent);
  border-radius: 999px;
  background: color-mix(in srgb, currentColor 12%, var(--surface));
}

.sale-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: 22px;
  align-items: start;
  margin-bottom: 26px;
}
.sale-grid .panel { margin-bottom: 0; }

.facts { margin-top: 4px; }
.fact {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 20px;
  padding: 12px 0;
  border-bottom: 1px solid var(--line-soft);
  font-size: 0.92rem;
  color: var(--text-dim);
}
.fact:last-child { border-bottom: 0; padding-bottom: 0; }
.fact > span:first-child { flex-shrink: 0; }
.fact > span:last-child {
  font-weight: 700;
  color: var(--text);
  text-align: right;
  overflow-wrap: anywhere;
  font-variant-numeric: tabular-nums lining-nums;
}
.fact > span.faint:last-child { font-weight: 400; color: var(--text-faint); }
.fact.lead > span:last-child { color: var(--accent); font-size: 1.2rem; }
.fact.wide { flex-direction: column; align-items: flex-start; gap: 6px; }
.fact.wide > span:last-child { text-align: left; font-weight: 600; }

.sale-agreement-doc { max-width: 820px; margin: 24px auto 0; }

/* ==========================================================================
   9. The payment run — numbered steps
   ========================================================================== */
.steps { display: flex; flex-direction: column; gap: 18px; }

/* Under step 3: the one way to say the pay run is done */
.pay-finish { margin-top: 18px; }
.pay-finish .btn { width: 100%; height: 60px; font-size: 1.12rem; border-radius: var(--radius); }
/* Greyed out until something on the page has been paid */
.pay-finish .btn:disabled {
  background: var(--surface-3);
  color: var(--text-ghost);
  box-shadow: none;
  cursor: not-allowed;
  filter: none;
  transform: none;
}
.pay-finish-hint { margin-top: 10px; text-align: center; font-size: 0.88rem; color: var(--text-faint); }

.step {
  display: grid;
  grid-template-columns: 52px minmax(0, 1fr);
  gap: 20px;
  padding: 24px 28px 26px;
  background: var(--surface);
  border: var(--edge-w) solid transparent;
  border-radius: var(--radius-lg);
  box-shadow: var(--bevel);
}

.step-n {
  width: 44px;
  height: 44px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: var(--surface-3);
  color: var(--text-faint);
  font-size: 1.1rem;
  font-weight: 800;
  font-variant-numeric: lining-nums;
}
.step[data-state="active"] { --foil-edge: 0.95; }
.step[data-state="active"] .step-n { background: var(--accent-grad); color: var(--accent-ink); }
.step[data-state="done"] .step-n { background: var(--pos); color: var(--bg); }
.step[data-state="done"] { opacity: 0.82; }

.step-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 20px;
  flex-wrap: wrap;
}
.step-title { font-size: 1.18rem; font-weight: 700; }
.step-note { margin-top: 3px; font-size: 0.92rem; color: var(--text-faint); max-width: 70ch; }
.step-body { margin-top: 20px; }
.step-body:empty { display: none; }

/* A step's list bleeds to both card edges. The left pull has to clear the
   number column and the grid gap as well as the card padding
   (28 padding + 52 column + 20 gap), or the table lines up on the right
   and floats on the left. */
.step-body > .table-wrap { margin: 0 -28px -26px -100px; }
.step-body > .table-wrap .tbl th:first-child,
.step-body > .table-wrap .tbl td:first-child { padding-left: 28px; }
.step-body > .table-wrap .tbl th:last-child,
.step-body > .table-wrap .tbl td:last-child { padding-right: 28px; }

/* The "nothing to do here" line inside a step */
.step-clear {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-top: 14px;
  font-size: 0.92rem;
  color: var(--pos);
  font-weight: 600;
}
.step-clear::before {
  content: '';
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--pos);
  flex-shrink: 0;
}

@media (max-width: 620px) {
  .step { grid-template-columns: minmax(0, 1fr); gap: 14px; padding: 22px 18px 24px; }
  .step-body > .table-wrap { margin: 0 -18px -24px; }
  .step-body > .table-wrap .tbl th:first-child,
  .step-body > .table-wrap .tbl td:first-child { padding-left: 18px; }
  .step-body > .table-wrap .tbl th:last-child,
  .step-body > .table-wrap .tbl td:last-child { padding-right: 18px; }
}

/* ==========================================================================
   10. Tables
   ========================================================================== */
.table-wrap { overflow-x: auto; }
.panel > .table-wrap, .panel-rows > .table-wrap { margin: 4px -30px -28px; }

/* A table split into pages keeps its bottom edge for the page controls. */
.panel-rows > .table-wrap.paged, .lookup .table-wrap.paged { margin: 4px -30px 0; }
.pager {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding-top: 18px;
  border-top: 1px solid var(--line-soft);
}
.pager-count { font-size: 0.86rem; color: var(--text-faint); font-variant-numeric: tabular-nums; }
.pager-buttons { display: flex; align-items: center; gap: 12px; }
.pager-at { font-size: 0.86rem; color: var(--text-dim); white-space: nowrap; }
.pager .btn:disabled { opacity: 0.4; cursor: default; }

/* Import bank records: a place to drop the file, then what it verified. */
.drop {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  padding: 44px 24px;
  border: 1.5px dashed color-mix(in srgb, var(--accent) 45%, transparent);
  border-radius: var(--radius);
  background: var(--surface-2);
  text-align: center;
  cursor: pointer;
  transition: border-color 0.2s var(--ease), background 0.2s var(--ease);
}
.drop:hover, .drop.over { border-color: var(--accent); background: var(--accent-wash); }
.drop svg { width: 38px; height: 38px; margin-bottom: 4px; color: var(--accent); }
.drop strong { font-size: 1.05rem; color: var(--text); }
.drop span { font-size: 0.9rem; color: var(--text-faint); }
.drop u { color: var(--accent); text-underline-offset: 3px; }
.drop.busy { cursor: default; }
.drop.busy svg { animation: drop-busy 1s var(--ease) infinite alternate; }
@keyframes drop-busy { to { opacity: 0.35; } }

/* "or paste the download link": a rule with words in it, then the link box and its button. */
.or-rule { display: flex; align-items: center; gap: 14px; margin: 20px 0 14px; font-size: 0.86rem; color: var(--text-faint); }
.or-rule::before, .or-rule::after { content: ''; flex: 1; height: 1px; background: var(--line); }
.link-row { display: flex; gap: 10px; }
.link-row .field { flex: 1; min-width: 0; }
.link-row .btn { flex-shrink: 0; height: 48px; }

.bank-file {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 14px 16px;
  border-radius: var(--radius);
  background: var(--surface-2);
}
.bank-file svg { width: 26px; height: 26px; flex-shrink: 0; color: var(--accent); }
.bank-file > span { display: flex; flex-direction: column; min-width: 0; }
.bank-file strong { color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.bank-file > span > span { font-size: 0.86rem; color: var(--text-faint); }
.bank-verdict { display: flex; align-items: baseline; gap: 12px; margin: 22px 0 6px; }
.bank-verdict b { font-size: 2.3rem; font-weight: 800; line-height: 1; color: var(--text-dim); font-variant-numeric: tabular-nums; }
.bank-verdict.ok b { color: var(--accent); }
.bank-verdict span { font-size: 1.05rem; font-weight: 700; color: var(--text); }
.bank-section { margin: 26px 0 0; font-size: 0.98rem; font-weight: 700; color: var(--text); }
.modal-body .table-wrap .faint { font-size: 0.82rem; font-weight: 400; }

.modal-body .table-wrap {
  margin-top: 8px;
  border: var(--edge-w) solid transparent;
  border-radius: var(--radius);
}
.modal-body .tbl thead th { padding-top: 14px; }
.modal-body .tbl th:first-child, .modal-body .tbl td:first-child { padding-left: 18px; }
.modal-body .tbl th:last-child,  .modal-body .tbl td:last-child  { padding-right: 18px; }

table.tbl { width: 100%; border-collapse: collapse; font-size: 0.92rem; }

.tbl thead th {
  padding: 18px 16px 12px;
  text-align: left;
  white-space: nowrap;
  font-size: 0.82rem;
  font-weight: 700;
  color: var(--text-faint);
}
.tbl th.right, .tbl td.right { text-align: right; }

/* Words wrap so a table fits its card; figures, statuses and buttons never
   break. Only a phone-width card is narrow enough to need the sideways scroll. */
.tbl tbody td {
  padding: 16px;
  border-top: 1px solid var(--line-soft);
  color: var(--text-dim);
  vertical-align: middle;
}
.tbl tbody td.right, .tbl tbody td.who, .tbl td .state, .tbl td .btn, .tbl td .tag { white-space: nowrap; }
.tbl tbody td.key { color: var(--text); font-weight: 600; }
.tbl .cell-date, .tbl .cell-time { display: block; white-space: nowrap; }
.tbl .cell-time { margin-top: 2px; font-size: 0.8rem; color: var(--text-faint); }

.tbl th:first-child, .tbl td:first-child { padding-left: 30px; }
.tbl th:last-child,  .tbl td:last-child  { padding-right: 30px; }

.tbl tbody tr { transition: background 0.16s var(--ease); }
.tbl tbody tr:hover { background: var(--surface-2); }

.tbl tbody td.figure, .tbl tbody td .figure {
  font-weight: 700;
  font-size: 1rem;
  color: var(--text);
}
.tbl tbody td.accent, .tbl tbody td.figure.accent { color: var(--accent); }
.tbl tbody td.taupe { color: var(--taupe); }
.tbl tbody td.pos   { color: var(--pos); }
.tbl tbody td.neg   { color: var(--neg); }
.tbl tbody td.faint { color: var(--text-faint); }

/* Rare row actions appear on hover so they don't compete with the data */
.row-quiet { opacity: 0; transition: opacity 0.2s var(--ease); }
.tbl tbody tr:hover .row-quiet,
.row-quiet:focus-visible { opacity: 1; }

.row-person { display: flex; align-items: center; gap: 12px; min-width: 0; }

/* The position picker in an account request: wide enough for the longest
   position name. */
.request-position .dd-button { min-width: 250px; }
.tbl td .btn-sm + .btn-sm { margin-left: 8px; }

/* A row that opens its sale's summary */
.tbl tr.row-link { cursor: pointer; }
.tbl tr.row-link:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; background: var(--surface-2); }

.tbl tr.expandable { cursor: pointer; }
.tbl tr.expandable > td:first-child { width: 34px; }
.chev {
  display: inline-flex;
  color: var(--text-ghost);
  transition: transform 0.28s var(--ease), color 0.2s var(--ease);
}
.tbl tr.expandable:hover .chev { color: var(--accent); }
.tbl tr.expandable[data-open="true"] { background: var(--surface-2); }
.tbl tr.expandable[data-open="true"] .chev { transform: rotate(90deg); color: var(--accent); }

/* ==========================================================================
   10b. Property lookup — one search box, then the matches

   The search is the whole point of the screen, so it is the full width and
   the height of a form field rather than the small filter in a panel head.
   The manager's filter reuses the Realtor / Manager switch from the top line.
   ========================================================================== */
.lookup-bar {
  display: flex;
  align-items: center;
  gap: 14px;
  flex-wrap: wrap;
}
.lookup-search { flex: 1 1 320px; }
.lookup-search .field { width: 100%; height: 52px; padding-left: 44px; font-size: 1rem; }
.lookup-search svg { left: 16px; width: 18px; height: 18px; }
.lookup-search .field::-webkit-search-cancel-button { filter: grayscale(1) opacity(0.6); }

.lookup-filter { flex-shrink: 0; }
.lookup-filter .mode { height: 40px; padding: 0 16px; }
.lookup-n { margin-left: 4px; font-weight: 700; color: var(--text-ghost); font-variant-numeric: tabular-nums; }
.lookup-filter .mode[aria-pressed="true"] .lookup-n { color: inherit; opacity: 0.7; }

.lookup-count { margin: 16px 0 0; font-size: 0.88rem; color: var(--text-faint); }

/* The results bleed to the panel's edges like every other panel table. */
.lookup .table-wrap { margin: 4px -30px -28px; }

.lookup-tag { margin-left: 10px; font-weight: 600; vertical-align: 1px; }
.lookup-note { margin-top: 3px; font-size: 0.82rem; font-weight: 400; white-space: normal; }

/* A price field sitting in a table row — the input is the cell's content,
   so it is sized to the figure rather than to a form. */
.tbl .lookup-price {
  width: 150px;
  height: 40px;
  padding: 0 12px;
  text-align: right;
  font-size: 0.95rem;
  font-weight: 700;
}
.tbl .lookup-price:placeholder-shown { font-weight: 400; }

/* A saved price answers with a brief blush along its row. */
@keyframes lookup-saved {
  from { background: var(--accent-wash); }
  to   { background: transparent; }
}
.tbl tbody tr.saved { animation: lookup-saved 1.4s var(--ease); }

@media (prefers-reduced-motion: reduce) {
  .tbl tbody tr.saved { animation: none; }
}

/* ==========================================================================
   11. Status + tags — round, sentence case
   ========================================================================== */
.state {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 0.88rem;
  font-weight: 600;
  color: var(--text-dim);
  white-space: nowrap;
}
.state::before {
  content: '';
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: currentColor;
  flex-shrink: 0;
}
.state.paid    { color: var(--pos); }
.state.payable { color: var(--accent); }
.state.held    { color: var(--warn); }
.state.review  { color: var(--taupe); }

.tag {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 28px;
  padding: 0 13px;
  border-radius: var(--radius-pill);
  background: var(--surface-3);
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--text-faint);
  white-space: nowrap;
}
.tag.on   { background: var(--accent-wash); color: var(--accent); }
.tag.mute { background: transparent; border: var(--edge-w) solid transparent; color: var(--text-ghost); }

/* ==========================================================================
   12. Empty states
   ========================================================================== */
.empty {
  padding: 54px 24px 58px;
  text-align: center;
  color: var(--text-faint);
  font-size: 0.92rem;
  line-height: 1.6;
}
.empty::before {
  content: '';
  display: block;
  width: 10px;
  height: 10px;
  margin: 0 auto 18px;
  border-radius: 50%;
  background: var(--line-strong);
}
.empty strong {
  display: block;
  margin-bottom: 6px;
  font-size: 1.1rem;
  font-weight: 700;
  color: var(--text);
}

/* ==========================================================================
   13. Payout drawer
   ========================================================================== */
/* Step 3: one dropdown per person owed. The manager pays each transaction
   from the banking app, so everything that app asks for is one click to copy. */
.payees { display: grid; gap: 12px; }

.payee {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface-2);
  overflow: hidden;
  transition: border-color 0.2s var(--ease);
}
.payee:hover, .payee.open { border-color: var(--accent-line, var(--line)); }

.payee-head {
  width: 100%;
  display: grid;
  grid-template-columns: 40px minmax(0, 1fr) auto auto auto;
  align-items: center;
  gap: 16px;
  padding: 14px 18px;
  border: 0;
  background: none;
  color: var(--text);
  font-family: var(--font-ui);
  text-align: left;
  cursor: pointer;
}
.payee-head:hover { background: var(--surface-3); }
.payee-avatar { width: 40px; height: 40px; font-size: 0.86rem; }
.payee-who { display: flex; flex-direction: column; min-width: 0; }
.payee-name { font-size: 1.02rem; font-weight: 700; }
.payee-id { font-size: 0.84rem; color: var(--text-faint); font-variant-numeric: tabular-nums; }
.payee-count { font-size: 0.88rem; color: var(--text-faint); white-space: nowrap; }
.payee-owed { font-size: 1.16rem; font-weight: 700; color: var(--accent); min-width: 96px; text-align: right; }
.payee.is-paid .payee-owed { color: var(--text-faint); text-decoration: line-through; }

/* The dropdown says it is one: a pill with a chevron that turns */
.payee-toggle {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 34px;
  padding: 0 12px 0 14px;
  border-radius: var(--radius-pill);
  background: var(--surface-3);
  font-size: 0.84rem;
  font-weight: 600;
  color: var(--text-dim);
  min-width: 82px;
  justify-content: center;
  transition: background 0.3s var(--ease), color 0.3s var(--ease);
}
.payee-toggle svg { width: 15px; height: 15px; transition: transform 0.36s var(--ease); }
.payee.open .payee-toggle { background: var(--accent-wash); color: var(--accent); }
.payee.open .payee-toggle svg { transform: rotate(180deg); }
.payee-toggle .when-open, .payee.open .payee-toggle .when-closed { display: none; }
.payee.open .payee-toggle .when-open { display: inline; }

/* Opening slides the transactions down in place: the row track grows from
   0fr to 1fr, so the height animates to whatever the content needs. */
.payee-drop {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows 0.38s var(--ease);
}
.payee.open .payee-drop { grid-template-rows: 1fr; }
.payee-body {
  min-height: 0;
  overflow: hidden;
  padding: 0 18px;
  opacity: 0;
  transform: translateY(-6px);
  transition: opacity 0.26s var(--ease), transform 0.38s var(--ease), padding 0.38s var(--ease);
}
/* The rule above the transactions is on the drop, not the body: a border
   there would leave a closed card a pixel open. */
.payee.open .payee-drop { box-shadow: inset 0 1px 0 var(--line-soft); }
.payee.open .payee-body {
  padding: 4px 18px 16px;
  opacity: 1;
  transform: none;
}
/* A redraw after Copy memo or Undo shows the page as it is, without replaying its entrance */
#manager-view-container.is-quiet .enter,
#manager-view-container.is-quiet .enter > * { animation: none; }
/* The same for a realtor's screen redrawn after the page came back from the server */
#employee-view-container.is-quiet .enter,
#employee-view-container.is-quiet .enter > *,
#employee-view-container.is-quiet .choices.enter .choice,
#employee-view-container.is-quiet .money.enter .money-item,
#employee-view-container.is-quiet .done-mark { animation: none; }
@media (prefers-reduced-motion: reduce) {
  .payee-drop, .payee-body, .payee-toggle svg { transition: none; }
}
.payee-to { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 16px; padding: 12px 0; }
.payee-warn { color: var(--warn); font-weight: 600; }
.payee-warn-note { font-size: 0.86rem; color: var(--warn); }
.payee-warn-note .linkish { margin-left: 4px; font-size: 0.86rem; }

/* A value to copy: label, value, copy icon */
.copy-chip {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  height: 34px;
  padding: 0 12px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--surface);
  color: var(--text);
  font-family: var(--font-ui);
  font-size: 0.88rem;
  cursor: pointer;
  white-space: nowrap;
  transition: border-color 0.2s var(--ease), background 0.2s var(--ease);
}
.copy-chip:hover { border-color: var(--accent); background: var(--surface-3); }
.copy-chip-label { font-size: 0.76rem; color: var(--text-faint); }
.copy-chip-value { font-weight: 700; font-variant-numeric: tabular-nums; }
.copy-chip svg { width: 14px; height: 14px; color: var(--text-ghost); }
.copy-chip:hover svg { color: var(--accent); }

/* One transaction: what it was, its memo, the amount, then Copy memo */
.pay-line {
  display: grid;
  grid-template-columns: 104px minmax(150px, 1fr) minmax(0, 1.4fr) 150px 250px;
  align-items: center;
  gap: 14px;
  padding: 12px 0;
  border-top: 1px solid var(--line-soft);
  font-size: 0.9rem;
  transition: opacity 0.2s var(--ease);
}
.pay-line .tag { justify-self: start; }
.pay-line > .copy-chip { justify-self: end; }
.pay-line-what { display: flex; flex-direction: column; min-width: 0; }
.pay-line-date { font-size: 0.8rem; color: var(--text-faint); }
.pay-line-memo {
  min-width: 0;
  font-family: var(--font-mono);
  font-size: 0.78rem;
  color: var(--text-faint);
  overflow-wrap: anywhere;
}
.pay-line-act { display: flex; align-items: center; justify-content: flex-end; gap: 10px; white-space: nowrap; }
.pay-line-act .linkish { font-size: 0.84rem; }
/* Paid: stays put, dimmed, until the manager leaves the page */
.pay-line.is-paid > :not(.pay-line-act) { opacity: 0.45; }
.pay-line.is-paid .copy-chip-value { text-decoration: line-through; }

@media (max-width: 1080px) {
  .pay-line { grid-template-columns: auto minmax(0, 1fr); }
  .pay-line-memo { grid-column: 1 / -1; }
  .pay-line > .copy-chip { justify-self: start; }
  .pay-line-act { justify-content: flex-end; }
}
@media (max-width: 640px) {
  .payee-head { grid-template-columns: 36px minmax(0, 1fr) auto; gap: 12px; padding: 12px 14px; }
  .payee-avatar { width: 36px; height: 36px; }
  .payee-count { display: none; }
  .payee-owed { grid-column: 2; min-width: 0; text-align: left; font-size: 1.04rem; }
  .payee-toggle { grid-column: 3; grid-row: 1 / span 2; }
  .payee-body { padding: 0 14px; }
  .payee.open .payee-body { padding: 4px 14px 14px; }
  .pay-line-act { grid-column: 1 / -1; flex-wrap: wrap; justify-content: flex-start; }
}

/* ==========================================================================
   14. Ledger — the calculation breakdown
   ========================================================================== */
.ledger { display: flex; flex-direction: column; }

.ledger-line {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 18px;
  padding: 10px 0;
  font-size: 0.92rem;
  color: var(--text-dim);
  border-bottom: 1px solid var(--line-soft);
}
.ledger-line:last-child { border-bottom: 0; }
.ledger-line > span:last-child {
  font-weight: 700;
  color: var(--text);
  font-variant-numeric: tabular-nums lining-nums;
  white-space: nowrap;
}

.ledger-formula { margin-left: 8px; font-size: 0.8rem; font-weight: 400; color: var(--text-ghost); }

.ledger-line.minus > span:last-child { color: var(--neg); }

.ledger-line.sum {
  margin-top: 6px;
  padding-top: 16px;
  border-top: var(--edge-w) solid var(--line-strong);
  border-bottom: 0;
}
.ledger-line.sum > span:first-child { color: var(--text); font-weight: 700; }
.ledger-line.sum > span:last-child { font-size: 1.38rem; color: var(--accent); }

/* ==========================================================================
   15. Calculator + rate preview layouts
   ========================================================================== */
.calc-grid { display: grid; grid-template-columns: minmax(0, 0.95fr) minmax(0, 1.05fr); padding-top: 24px; }
.calc-grid > div:first-child { padding-right: 40px; }
.calc-grid > div:last-child { padding-left: 40px; border-left: var(--edge-w) solid var(--line); }

@media (max-width: 900px) {
  .calc-grid { grid-template-columns: minmax(0, 1fr); }
  .calc-grid > div:first-child { padding-right: 0; padding-bottom: 28px; }
  .calc-grid > div:last-child { padding-left: 0; padding-top: 28px; border-left: 0; border-top: var(--edge-w) solid var(--line); }
}

.rate-preview { display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); padding-top: 22px; }
.rate-preview > div { min-width: 0; padding: 0 28px; border-left: var(--edge-w) solid var(--line); }
.rate-preview > div:first-child { border-left: 0; padding-left: 0; }

@media (max-width: 900px) {
  .rate-preview > div { padding: 22px 0; border-left: 0; border-top: var(--edge-w) solid var(--line); }
  .rate-preview > div:first-child { padding-top: 0; border-top: 0; }
}

/* ==========================================================================
   16. Rate controls
   ========================================================================== */
.rate { padding: 26px 0; border-bottom: var(--edge-w) solid var(--line); }
.rate:last-of-type { border-bottom: 0; }

/* The split on the left; the two state taxes stacked on the right */
.rate-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(400px, 1fr)); }
.rate-grid > .rate { padding: 26px 32px 6px 0; border-bottom: 0; }
.rate-stack { padding-left: 32px; border-left: var(--edge-w) solid var(--line); }
.rate-stack > .rate { padding: 26px 0; border-bottom: var(--edge-w) solid var(--line); }
.rate-stack > .rate:last-child { border-bottom: 0; padding-bottom: 6px; }

/* The commission split: one heading over a slider for each winning bid tier */
.rate-splits { padding: 26px 32px 6px 0; }
.rate-splits .rate-group-head { margin-bottom: 0; }
.rate-splits .rate-group-help { margin-top: 6px; }
.rate-splits > .rate { padding: 20px 0; border-bottom: var(--edge-w) solid var(--line); }
.rate-splits > .rate:last-child { border-bottom: 0; padding-bottom: 6px; }
.rate-splits > .rate .rate-name { font-size: 0.95rem; font-weight: 600; color: var(--text-dim); }

@media (max-width: 1000px) {
  .rate-grid { grid-template-columns: minmax(0, 1fr); }
  /* stacked: a rule between them instead of the divider beside them */
  .rate-grid > .rate { padding: 26px 0; border-bottom: var(--edge-w) solid var(--line); }
  .rate-splits { padding: 26px 0 6px; border-bottom: var(--edge-w) solid var(--line); }
  .rate-stack { padding-left: 0; border-left: 0; }
}

.rate-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 18px;
  flex-wrap: wrap;
  margin-bottom: 14px;
}
.rate-name { font-size: 1.05rem; font-weight: 700; color: var(--text); }

/* Something that is there but not open yet (private sales): greyed and
   inert, like the Private sale door. */
.is-soon { filter: grayscale(1); opacity: 0.45; pointer-events: none; user-select: none; }
.soon-tag {
  margin-left: 8px;
  font-size: 0.8rem;
  font-weight: 600;
  letter-spacing: normal;
  text-transform: none;
  color: var(--text-faint);
}

/* Private sale commission rates, under the two rates. */
.rate-private { margin-top: 4px; padding-top: 26px; border-top: var(--edge-w) solid var(--line); }
.rate-private .rate-top { justify-content: flex-start; gap: 0; }
.rate-private-name { font-size: 1.05rem; font-weight: 700; color: var(--text); }
.rate-chips { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; }
.rate-chips .rate-entry-box .field { width: 96px; height: 42px; font-size: 1.05rem; }
.rate-chips .field:disabled { cursor: default; }

/* The figure itself, typed: [ 70 % ], with "Agent" before it for the split. */
.rate-entry { display: inline-flex; align-items: center; gap: 10px; }
.rate-entry-lead { font-size: 0.9rem; font-weight: 600; color: var(--text-dim); }
.rate-entry-box { position: relative; display: inline-block; }
.rate-entry-box .field {
  width: 112px;
  height: 46px;
  padding: 0 34px 0 12px;
  text-align: right;
  font-size: 1.3rem;
  font-weight: 800;
  letter-spacing: -0.01em;
  color: var(--accent);
}
.rate-unit {
  position: absolute;
  right: 14px;
  top: 50%;
  transform: translateY(-50%);
  font-size: 1rem;
  font-weight: 700;
  color: var(--text-faint);
  pointer-events: none;
}

.slider {
  -webkit-appearance: none;
  appearance: none;
  display: block;
  width: 100%;
  height: 26px;
  background: transparent;
  cursor: pointer;
}
.slider::-webkit-slider-runnable-track { height: 6px; border-radius: 3px; background: var(--surface-3); }
.slider::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 22px;
  height: 22px;
  margin-top: -8px;
  border: 0;
  border-radius: 50%;
  background: var(--accent-grad);
  box-shadow: 0 2px 8px -2px rgba(0, 0, 0, 0.5);
  transition: box-shadow 0.2s var(--ease);
}
.slider:hover::-webkit-slider-thumb { box-shadow: 0 0 0 8px var(--accent-wash); }
.slider::-moz-range-track { height: 6px; border-radius: 3px; background: var(--surface-3); }
.slider::-moz-range-thumb {
  width: 22px;
  height: 22px;
  border: 0;
  border-radius: 50%;
  background: var(--accent);
}

/* The track fills up to the thumb (--fill is set from the value). */
.rate .slider::-webkit-slider-runnable-track {
  background: linear-gradient(90deg, var(--accent) 0 var(--fill, 0%), var(--surface-3) var(--fill, 0%));
}
.rate .slider::-moz-range-progress { height: 6px; border-radius: 3px; background: var(--accent); }

/* What the value means, either side of the track: "Agent 70%" … "Firm 30%". */
.rate-ends {
  display: flex;
  justify-content: space-between;
  gap: 18px;
  margin-top: 10px;
  font-size: 0.9rem;
  font-weight: 600;
  color: var(--text-dim);
  font-variant-numeric: tabular-nums;
}
.rate-help { margin-top: 12px; max-width: 72ch; font-size: 0.88rem; color: var(--text-faint); }

/* ==========================================================================
   17. Notes
   ========================================================================== */
.note {
  position: relative;
  padding: 18px 22px 19px 42px;
  border: var(--edge-w) solid transparent;
  border-radius: var(--radius);
  background: var(--surface-2);
  font-size: 0.9rem;
  line-height: 1.6;
  color: var(--text-faint);
}
.note::before {
  content: '';
  position: absolute;
  left: 20px;
  top: 24px;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--taupe);
}
.note strong { display: block; margin-bottom: 2px; font-weight: 700; color: var(--text); }
.note code, .mono-inline { font-family: var(--font-mono); font-size: 0.8rem; color: var(--taupe); }
.note .linkish { display: inline-block; margin-top: 8px; }

/* A warning is the one place the edge is NOT foil — amber and red carry
   meaning that pink cannot. It recolours the ring rather than painting a
   second edge outside it, which is what the dot does too. */
/* A note that carries its own button, on the right (Rates' "Unsaved changes" → Cancel). */
.note-with-action { align-items: center; justify-content: space-between; gap: 16px; flex-wrap: wrap; }
.note.attn::after { background: var(--warn); opacity: 0.34; }
.note.attn::before { background: var(--warn); }
.note.bad::after { background: var(--neg); opacity: 0.36; }
.note.bad::before { background: var(--neg); }

/* ==========================================================================
   18. Modals
   ========================================================================== */
.modal-overlay {
  position: fixed;
  inset: 0;
  z-index: 200;
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding: 40px 20px;
  overflow-y: auto;
  background: rgba(5, 3, 4, 0.7);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.24s var(--ease);
}
.modal-overlay.active { opacity: 1; pointer-events: auto; }

.modal-content {
  width: 100%;
  max-width: 600px;
  background: var(--surface);
  /* a modal stands away from the page, so its ring runs brighter than the
     app's — the edge used to be --line-strong before it became foil */
  --foil-edge: 0.82;
  border: var(--edge-w) solid transparent;
  border-radius: var(--radius-xl);
  box-shadow: var(--lift), var(--bevel);
  overflow: hidden;
  /* Centred in the window. Auto margins rather than align-items: center,
     so a dialog taller than the window starts at the top and scrolls
     instead of losing its top edge above the window. */
  margin: auto;
  transform: translateY(-10px) scale(0.99);
  transition: transform 0.3s var(--ease);
}
.modal-overlay.active .modal-content { transform: none; }

.modal-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 18px;
  padding: 24px 28px 20px;
  border-bottom: var(--edge-w) solid var(--line);
}
.modal-title { font-size: 1.26rem; }

.modal-body { padding: 26px 28px 28px; }

.modal-foot {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 12px;
  padding: 18px 28px 20px;
  border-top: var(--edge-w) solid var(--line);
  background: var(--surface-2);
}
.modal-foot .spread { margin-right: auto; font-size: 0.86rem; color: var(--text-faint); }

/* A long dialog whose buttons must stay in reach: only the body scrolls. */
.modal-content.scroll-body {
  display: flex;
  flex-direction: column;
  max-height: calc(100vh - 80px);
  max-height: calc(100dvh - 80px);
}
.modal-content.scroll-body > .modal-header,
.modal-content.scroll-body > .modal-foot { flex: none; }
.modal-content.scroll-body > .modal-body { flex: 1 1 auto; min-height: 0; overflow-y: auto; }
/* The same when the body and foot sit inside a form (Edit transaction) */
.modal-content.scroll-body > form { display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0; }
.modal-content.scroll-body > form > .modal-body { flex: 1 1 auto; min-height: 0; overflow-y: auto; }
.modal-content.scroll-body > form > .modal-foot { flex: none; }

/* Under a house sale's figures: the state tax the client pays on top */
/* What the client pays (house sales): its own short sum under the agent's,
   quieter than "You keep" so the two totals don't compete. */
.ledger.purchase { margin-top: 18px; padding-top: 4px; border-top: var(--edge-w) solid var(--line-strong); }
.ledger.purchase .ledger-line.sum { margin-top: 0; padding-top: 12px; border-top: 0; }
.ledger.purchase .ledger-line.sum > span:last-child { font-size: 1.12rem; color: var(--text); }

/* A locked field (a paid transaction's amounts and agent) reads as locked */
.field:disabled { opacity: 0.45; cursor: not-allowed; }

/* Edit transaction: what the changes come to, and why some fields are locked */
.edit-lock { margin-bottom: 18px; }
.edit-preview {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 22px;
  margin: 4px 0 20px;
  padding: 12px 14px;
  border-radius: 10px;
  background: var(--surface-2);
  font-size: 0.9rem;
  color: var(--text-faint);
}
.edit-preview b { color: var(--text); font-variant-numeric: tabular-nums; }
.edit-preview .changed b { color: var(--accent); }
.edit-section { margin: 22px 0 10px; font-size: 0.8rem; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; color: var(--text-faint); }
.edit-section:first-child { margin-top: 0; }

/* ==========================================================================
   19. Sign-in
   ========================================================================== */
/* One centred column on the petal field — no split, no gutter. The screen
   does exactly one thing, so it holds exactly one object. */
/* A reload while signed in: nothing to sign in to while the session is checked (app.js startRemote) */
html[data-resuming] #view-login { visibility: hidden; }

.auth {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 40px 22px;
}

.auth-card {
  position: relative;
  width: 100%;
  max-width: 424px;
  padding: 30px 38px 28px;
  text-align: center;
  /* Plain --surface, the same as every other box, and deliberately NOT
     --surface-glass. This card used to be glass over a blur(22px), which
     made it the most transparent surface on the page and the only one that
     looked solid: a 22px blur has nothing left to show of a 52px lattice or
     a 10px petal, so it flattened everything behind the card into an even
     field. Blur earns its place on the topline, where live content scrolls
     underneath it. Here there is only the sheet, and the sheet is the
     thing we want to see. */
  background: var(--surface);
  border: var(--edge-w) solid transparent;
  border-radius: var(--radius-xl);
  box-shadow: var(--lift), var(--bevel);
}

/* The transparent logo straight on the card, no plate. Its lettering was
   lifted to taupe for this background by tools/make-logo-assets.ps1. */
.auth-logo {
  display: block;
  width: 216px;
  height: auto;
  margin: 0 auto 18px;
}

/* The company name is the title here — tracked out, since this is the one
   place the wordmark is the subject rather than a label. */
.auth-title {
  font-size: 1.34rem;
  font-weight: 400;
  line-height: 1.3;
  color: var(--text);
}
.auth-lede { margin: 12px auto 24px; max-width: 34ch; font-size: 0.92rem; color: var(--text-faint); }
.auth-actions { display: flex; justify-content: center; gap: 12px; flex-wrap: wrap; }
.auth-actions .btn[hidden] { display: none; }

/* The privacy page (privacy.html): the sign-in card, wider and read left to
   right. The link to it sits quietly under the sign-in card. */
.privacy-card { max-width: 620px; text-align: left; }
.privacy-card .auth-title,
.privacy-card .auth-lede,
.privacy-card .privacy-note { text-align: center; }
.privacy-card .auth-lede { margin-bottom: 10px; }
.privacy-card .privacy-note { margin: 0 auto 4px; max-width: 40ch; color: var(--text); }
.privacy-card h2 { margin: 22px 0 6px; font-size: 1rem; font-weight: 600; color: var(--text); }
.privacy-card p,
.privacy-card li { font-size: 0.92rem; color: var(--text-faint); }
.privacy-card p + p { margin-top: 8px; }
.privacy-card ul { margin: 0; padding-left: 20px; }
.privacy-card li + li { margin-top: 6px; }
.privacy-card a,
.auth-foot a { color: inherit; }
.privacy-card .privacy-foot { margin-top: 26px; text-align: center; font-size: 0.84rem; }
.auth-foot { margin-top: 18px; font-size: 0.84rem; color: var(--text-faint); }

/* Google draws its button in its own frame. The frame's page is light: a dark
   color-scheme here would make the browser paint an opaque white box behind
   it. */
#google-signin-button {
  position: relative;
  display: flex;
  justify-content: center;
  color-scheme: light;
}
#google-signin-button:empty { display: none; }
/* The portal's pink edge, just clear of Google's pill. Both of Google's
   versions ("Sign in with Google" and "Sign in as …") draw the same 320 × 40
   pill centred in their frame, but the second's frame is larger, so the edge
   is sized to the pill and centred rather than fitted to the frame. */
#google-signin-button::after {
  content: '';
  position: absolute;
  left: 50%;
  top: 50%;
  width: 328px;
  height: 48px;
  margin: -24px 0 0 -164px;
  border-radius: 24px;
  padding: var(--edge-w);
  background: var(--tex-foil);
  opacity: var(--foil-edge);
  -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
  mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
  -webkit-mask-composite: xor;
  mask-composite: exclude;
  pointer-events: none;
  transition: opacity 0.24s var(--ease);
}
#google-signin-button:hover::after { opacity: 0.95; }

/* Stands in for the Google button while there is no Client ID. Sized and
   styled to match what GIS actually renders for the options we ask it for
   (filled_black / large / pill / 320), so the screen's proportions are
   the ones it will really have. */
.gsi-placeholder {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  width: 320px;
  max-width: 100%;
  height: 40px;
  margin: 0 auto;
  padding: 0 12px 0 44px;
  border: 1px solid #202124;
  border-radius: 20px;
  background: #202124;
  color: #fff;
  font-family: 'Roboto', var(--font-ui);
  font-size: 0.875rem;
  font-weight: 500;
  letter-spacing: 0.01em;
  cursor: pointer;
  transition: box-shadow 0.2s var(--ease), background 0.2s var(--ease);
}
.gsi-placeholder:hover { background: #2d2e31; box-shadow: 0 1px 3px rgba(0,0,0,0.25); }
/* Google's mark on its white disc at the left end */
.gsi-placeholder svg {
  position: absolute; left: 2px; top: 2px;
  width: 34px; height: 34px; padding: 8px;
  border-radius: 50%; background: #fff; flex-shrink: 0;
}

.signin-notice {
  padding: 16px 18px;
  border: var(--edge-w) solid transparent;
  border-radius: var(--radius);
  background: var(--surface-2);
  font-size: 0.88rem;
  line-height: 1.6;
  color: var(--text-faint);
}
.signin-notice strong { display: block; margin-bottom: 2px; color: var(--text); font-weight: 700; }
.signin-notice span { display: block; }
.signin-notice code { font-family: var(--font-mono); font-size: 0.8rem; color: var(--taupe); }
.signin-notice.error   { --foil-edge: 0.36; }
.signin-notice.error::after { background: var(--neg); }
.signin-notice.loading { --foil-edge: 0.9; }

@media (max-width: 620px) {
  .auth { padding: 32px 16px; }
  .auth-card { padding: 24px 22px 26px; }
  .auth-logo { width: 184px; margin-bottom: 14px; }
  .auth-title { font-size: 1.14rem; }
}

/* ==========================================================================
   19b. Demo dock

   The testbed, reduced to one tab in the bottom-left corner. It used to be
   two panels inside the sign-in card and a <select> in the top line, which
   made every screen look like a testbed — so it became a ?demo URL
   parameter, which is worse again: an affordance you cannot see.

   Corner, not centre: it is chrome, not part of the app, and it reads as a
   label on the build rather than a feature of the portal. Bottom-LEFT
   because toasts own the bottom-right, and the two must never stack.
   ========================================================================== */
.demo-dock {
  position: fixed;
  left: 20px;
  bottom: 20px;
  /* over the app, under the toasts */
  z-index: 390;
}

.demo-tab {
  display: flex;
  align-items: center;
  gap: 7px;
  height: 30px;
  padding: 0 14px 0 11px;
  /* quieter than the app's own edges — it is a label on the build */
  --foil-edge: 0.42;
  border: var(--edge-w) solid transparent;
  border-radius: var(--radius-pill);
  background: var(--surface-glass);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  color: var(--text-ghost);
  font-family: var(--font-ui);
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.17em;
  text-transform: uppercase;
  cursor: pointer;
  transition: color 0.2s var(--ease), background 0.2s var(--ease);
}
.demo-tab:hover, .demo-tab[aria-expanded="true"] { color: var(--text-faint); background: var(--surface-2); }

/* The one thing on the page that says this is not the deployed build. Lit,
   not blinking — nothing in this app pulses. */
.demo-dot {
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 6px var(--accent-line);
}

.demo-pop {
  position: absolute;
  left: 0;
  bottom: calc(100% + 9px);
  min-width: 252px;
  padding: 8px;
  border: var(--edge-w) solid transparent;
  border-radius: var(--radius);
  background: var(--surface-2);
  box-shadow: var(--lift), var(--bevel);
  animation: enter 0.18s var(--ease) both;
}
.demo-pop[hidden] { display: none; }

.demo-pop-head {
  padding: 7px 10px 5px;
  font-size: 0.66rem;
  font-weight: 700;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: var(--text-ghost);
}
.demo-pop-head + .demo-pick { margin-top: 0; }

.demo-pick {
  display: block;
  width: 100%;
  padding: 8px 10px 9px;
  border: 0;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--text);
  font-family: var(--font-ui);
  font-size: 0.88rem;
  font-weight: 600;
  text-align: left;
  cursor: pointer;
  transition: background 0.18s var(--ease);
}
.demo-pick span {
  display: block;
  margin-top: 1px;
  font-size: 0.74rem;
  font-weight: 400;
  color: var(--text-faint);
}
.demo-pick:hover { background: var(--accent-wash); }

@media (max-width: 620px) {
  .demo-dock { left: 14px; bottom: 14px; }
}

/* ==========================================================================
   20. Toasts
   ========================================================================== */
.toast-container {
  position: fixed;
  right: 24px;
  bottom: 24px;
  z-index: 400;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 10px;
}

.toast {
  position: relative;
  max-width: 400px;
  padding: 16px 22px 17px 42px;
  border: var(--edge-w) solid var(--line-strong);
  border-radius: var(--radius);
  background: var(--surface-glass);
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
  box-shadow: var(--lift), var(--bevel);
  font-size: 0.92rem;
  line-height: 1.5;
  color: var(--text);
  animation: toast-in 0.32s var(--ease);
}
.toast::before {
  content: '';
  position: absolute;
  left: 20px;
  top: 22px;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--accent);
}
.toast.success::before { background: var(--pos); }
.toast.warning::before { background: var(--warn); }
.toast.error::before   { background: var(--neg); }

@media (max-width: 620px) {
  .toast-container { right: 14px; left: 14px; bottom: 14px; align-items: stretch; }
  .toast { max-width: none; }
}

/* ==========================================================================
   21. Purchase agreement: its stylesheet is AGREEMENT_CSS in app.js, next to
       the canvas drawing of the downloadable image, sharing its colours
   ========================================================================== */

/* ==========================================================================
   22. Phone
   ========================================================================== */
@media (max-width: 620px) {
  .page-head h1 { font-size: 1.62rem; }
  .page-head p { font-size: 0.94rem; }

  .panel { padding: 22px 18px 24px; }
  .panel > .table-wrap, .panel-rows > .table-wrap, .lookup .table-wrap { margin: 4px -18px -24px; }
  .panel-rows > .table-wrap.paged, .lookup .table-wrap.paged { margin: 4px -18px 0; }
  .lookup-filter { width: 100%; }
  /* four filters don't fit in one row on a phone: two by two */
  .lookup-filter { display: grid; grid-template-columns: 1fr 1fr; }
  .lookup-filter .mode { padding: 0 8px; }
  .tbl th:first-child, .tbl td:first-child { padding-left: 18px; }
  .tbl th:last-child,  .tbl td:last-child  { padding-right: 18px; }

  .choices { grid-template-columns: minmax(0, 1fr); gap: 12px; }
  .choice { min-height: 0; padding: 22px 22px 20px; }
  .choice-mark { width: 44px; height: 44px; border-radius: 13px; }
  .choice-mark svg { width: 22px; height: 22px; }
  .hub-greet h1 { font-size: 1.8rem; }
  .flow-head h1 { font-size: 1.62rem; }
  .money-item { flex: 1 1 100%; }
  .modal-overlay { padding: 24px 12px; }
  .modal-content.scroll-body { max-height: calc(100vh - 48px); max-height: calc(100dvh - 48px); }
  .modal-header { padding: 20px 20px 16px; }
  .modal-body { padding: 20px; }
  .modal-foot { padding: 16px 20px; flex-wrap: wrap; }
  .modal-foot .spread { width: 100%; margin-right: 0; }
  .field-row { grid-template-columns: minmax(0, 1fr); }
  .calc-grid > div:first-child, .rate-grid .rate { padding-left: 0; padding-right: 0; }
}

/* ==========================================================================
   23. Print
   ========================================================================== */
@media print {
  .topline, .petals, .toast-container, .modal-header, .modal-foot { display: none !important; }
  .modal-overlay {
    position: static;
    opacity: 1;
    padding: 0;
    background: none;
    backdrop-filter: none;
    overflow: visible;
  }
  .modal-content { max-width: none; border: 0; box-shadow: none; transform: none; }
  body::before, body::after { display: none; }
}
