/* SHYS Deal Posting Portal
 *
 * Design brief: this is a ledger, not a landing page. Matt scans a queue and operates a
 * journal entry, so the craft goes into information design — column discipline, tabular
 * numerals, and state encoded in FORM (a severity stripe, a pill) as well as in words, so
 * "this one is funky" reads at a glance. He said it doesn't have to be fancy; it does have
 * to be legible at 7am.
 *
 * Brand system: the public Sandy Hook Yacht Sales identity — lighthouse mark, Proxima Nova,
 * Report display face, deep-water navy, sea-glass teal, burgundy and light gray. Semantic
 * colors remain distinct where accounting state matters more than decoration.
 */

:root {
  color-scheme: light;

  --brand-navy: #023C5B;
  --brand-navy-deep: #034159;
  --brand-teal: #4D8E9C;
  --brand-red:  #A61F38;
  --brand-gray: #E7E8E9;
  --brand-gold: #E6C04C;

  --paper:      #F3F5F5;
  --surface:    #FFFFFF;
  --surface-2:  #EEF2F3;
  --line:       #D3DADC;
  --line-soft:  #E6EAEB;
  --ink:        #102733;
  --ink-2:      #385462;
  --ink-3:      #6A7F89;

  --accent:     var(--brand-navy);
  --accent-ink: #FFFFFF;
  --accent-bg:  #E2EEF1;

  --blocked:    var(--brand-red);
  --blocked-bg: #F8E8EC;
  --review:     #735A08;
  --review-bg:  #FFF7DA;
  --good:       #246657;
  --good-bg:    #E3F1EC;

  --radius: 5px;
  --sans: "proxima-nova", "Proxima Nova", "Avenir Next", Avenir, "Segoe UI", Arial, sans-serif;
  --display: "report", "Avenir Next Condensed", "Arial Narrow", var(--sans);
  --mono: ui-monospace, "SF Mono", "JetBrains Mono", Menlo, Consolas, monospace;
}

* { box-sizing: border-box; }
html { min-width: 0; overflow-x: hidden; }

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font: 15px/1.5 var(--sans);
  -webkit-font-smoothing: antialiased;
}

a { color: var(--accent); }

/* ---------------------------------------------------------------- chrome */
.topbar {
  display: flex; align-items: center; gap: 18px;
  min-height: 88px; padding: 8px 24px;
  background: var(--brand-gray);
  border-top: 3px solid var(--brand-navy);
  border-bottom: 1px solid #C8CED0;
  position: sticky; top: 0; z-index: 20;
  box-shadow: 0 2px 12px rgb(2 60 91 / 8%);
}
.brand {
  display: inline-flex; align-items: center; flex: 0 0 auto;
  color: inherit; text-decoration: none;
}
.brand img { display: block; width: 156px; height: 68px; object-fit: contain; }
.portal-title {
  min-width: 0; padding-left: 18px; border-left: 1px solid rgb(2 60 91 / 24%);
}
.portal-title .eyebrow {
  display: block; margin-bottom: 1px; color: var(--brand-teal);
  font-size: 10px; font-weight: 600; letter-spacing: 0.18em; text-transform: uppercase;
}
.portal-title h1 {
  margin: 0; color: var(--brand-navy); font-family: var(--display);
  font-size: 19px; font-weight: 600; letter-spacing: 0.035em; line-height: 1.15;
}
.portal-nav {
  display: flex; align-items: center; gap: 4px; margin-left: 6px;
}
.portal-nav a {
  padding: 8px 10px; border-radius: var(--radius);
  color: var(--ink-2); font-size: 13px; font-weight: 600; line-height: 1.2;
  text-decoration: none; white-space: nowrap;
}
.portal-nav a:hover,
.portal-nav a:focus-visible,
.portal-nav a[aria-current="page"] {
  background: rgb(2 60 91 / 9%); color: var(--brand-navy);
}
.portal-nav a:focus-visible {
  outline: 2px solid var(--brand-teal); outline-offset: 2px;
}
.topbar .who { margin-left: auto; color: var(--ink-3); font-size: 13px; }

/* ---------------------------------------------------------------- the account menu
 * A <details>/<summary> disclosure, not a scripted dropdown. It opens with no JavaScript, closes
 * on Escape, and is keyboard- and screen-reader-operable for free. The portal ships one script
 * and a menu that only works once that script has loaded is a menu that fails on a boat-show
 * phone with two bars of signal — which is exactly where this one gets used.
 *
 * It carries the sign-in for anonymous visitors, now that /market is public: the page has no
 * other affordance saying that Sandy Hook staff get more here.
 */
/* Hard right, past everything else. `.topbar .who` claims the free space with margin-left:auto,
   and the menu sits after it in the DOM, so `order` is what puts the button at the very edge —
   where every other site on the internet puts it, and where a thumb expects it. */
.usermenu { position: relative; margin-left: 8px; order: 10; flex: 0 0 auto; }

/* ⚠️ The topbar is `--brand-gray` (#E7E8E9), a LIGHT grey — not navy. The first version of this
   button was white bars inside a 28%-white border, which is the styling you would write for a
   dark bar and is very nearly invisible on this one. Solid Sandy Hook navy, white bars, light
   white rim: it reads as a button at a glance, which is the entire job of the only control in
   the header. */
.usermenu > summary {
  display: flex; align-items: center; justify-content: center; gap: 7px;
  min-width: 44px; min-height: 40px; padding: 0 11px;
  background: var(--brand-navy);
  border: 1px solid rgb(255 255 255 / 55%);
  border-radius: var(--radius); cursor: pointer; list-style: none;
  box-shadow: 0 1px 3px rgb(2 60 91 / 28%);
  transition: background 120ms ease, border-color 120ms ease;
}
.usermenu > summary::-webkit-details-marker { display: none; }
.usermenu > summary::marker { content: ""; }
.usermenu > summary:hover,
.usermenu[open] > summary { background: var(--brand-navy-deep); border-color: #FFFFFF; }
/* Navy, not white: a white focus ring on a light grey bar is the same mistake again. */
.usermenu > summary:focus-visible { outline: 2px solid var(--brand-navy); outline-offset: 2px; }

.hamburger { display: flex; flex-direction: column; gap: 3px; width: 18px; }
.hamburger i { display: block; height: 2px; background: #FFFFFF; border-radius: 1px; }
.who-initial {
  display: inline-flex; align-items: center; justify-content: center;
  width: 22px; height: 22px; border-radius: 50%;
  background: color-mix(in srgb, #FFFFFF 20%, transparent);
  color: #FFFFFF; font-size: 11px; font-weight: 700;
}

.usermenu-panel {
  position: absolute; right: 0; top: calc(100% + 6px); z-index: 40;
  min-width: 244px; max-width: min(84vw, 320px); padding: 8px;
  background: var(--surface); color: var(--ink);
  border: 1px solid var(--line); border-radius: var(--radius);
  box-shadow: 0 10px 30px rgba(2, 60, 91, 0.22);
}
.usermenu-panel a {
  display: block; padding: 10px 10px; min-height: 40px;
  color: var(--ink); text-decoration: none; border-radius: 4px; font-size: 14px;
}
.usermenu-panel a:hover { background: var(--surface-2); }
.usermenu-who {
  margin: 2px 0 6px; padding: 0 10px; color: var(--ink-3);
  font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.06em;
  overflow-wrap: anywhere;
}
.usermenu-login {
  background: var(--accent); color: var(--accent-ink) !important; font-weight: 650;
  text-align: center;
}
.usermenu-login:hover { background: var(--brand-navy-deep) !important; }
.usermenu-note {
  margin: 8px 2px 2px; padding: 0 8px; color: var(--ink-3);
  font-size: 12px; line-height: 1.45;
}

/* Sandbox must be unmissable. A tool that writes to the live books and a tool that writes
   nothing must never look alike — the whole value of a rehearsal is knowing you're in one. */
.topbar.sandbox { border-bottom: 3px solid var(--brand-gold); }
.sandbox-pill {
  background: var(--brand-gold); color: var(--brand-navy-deep);
  font-weight: 700; letter-spacing: 0.035em;
}

.wrap { max-width: 1180px; margin: 0 auto; padding: 24px; }
.wrap.wide { max-width: 1440px; }

/* ----------------------------------------------------------- report-only home */
.reports-home {
  width: min(960px, calc(100% - 40px));
  margin: 72px auto;
}
.reports-intro { max-width: 680px; }
.reports-intro h2 {
  margin: 8px 0 12px; color: var(--brand-navy); font-family: var(--display);
  font-size: clamp(2rem, 5vw, 3.5rem); font-weight: 600;
}
.reports-intro p { color: var(--ink-2); line-height: 1.6; }
.report-links {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 20px; margin-top: 36px;
}
.report-link {
  display: grid; gap: 10px; min-height: 180px; padding: 28px;
  border: 1px solid var(--line); border-top: 4px solid var(--brand-teal);
  border-radius: 8px; background: var(--surface); color: var(--ink-2);
  text-decoration: none; box-shadow: 0 12px 32px rgb(2 60 91 / 8%);
  transition: transform 120ms ease, border-color 120ms ease;
}
.report-link:hover,
.report-link:focus-visible { border-top-color: var(--brand-red); transform: translateY(-2px); }
.report-link:focus-visible { outline: 2px solid var(--brand-teal); outline-offset: 3px; }
.report-link strong {
  color: var(--brand-navy); font-family: var(--display); font-size: 1.65rem;
}
.report-link span:last-child { line-height: 1.5; }

/* ---------------------------------------------------------------- queue */
.section { margin-bottom: 34px; }
.section > header { margin-bottom: 10px; }
.section h2 {
  margin: 0; color: var(--brand-navy); font-family: var(--display);
  font-size: 14px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.1em;
}
.section .hint { color: var(--ink-3); font-size: 13px; margin-top: 2px; }

/* Where the closed-deal list states its own base: when the register was pulled, what window
   the reconciliation covered, and what "no match" does and does not mean. A count without its
   denominator reads as a finding, so the denominator travels with it. */
.provenance {
  margin-top: 12px; padding: 14px 16px;
  background: var(--paper-2, #F6F7F8); border: 1px solid var(--line);
  border-radius: var(--radius); color: var(--ink-2); font-size: 13px; line-height: 1.55;
}
.provenance p { margin: 0 0 8px; }
.provenance p:last-child { margin-bottom: 0; }
.provenance strong { color: var(--brand-navy); font-weight: 600; }
.provenance .caveat { color: var(--ink-3); font-size: 12.5px; border-top: 1px solid var(--line-soft);
                      padding-top: 8px; }
a.pill { text-decoration: none; }
a.pill:hover { filter: brightness(0.94); }

.rows { display: flex; flex-direction: column; gap: 1px; background: var(--line-soft);
        border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden; }

.row {
  display: grid;
  grid-template-columns: 4px 78px minmax(160px, 1.4fr) minmax(130px, 1fr) 108px 130px auto;
  align-items: center; gap: 14px;
  padding: 0; background: var(--surface);
  text-decoration: none; color: inherit;
}
.row > * { padding: 12px 0; }
.row > :first-child { padding: 0; }
.row > :nth-child(2) { padding-left: 14px; }
.row > :last-child { padding-right: 14px; }
.row:hover { background: #F3F8F9; }
.row:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
/* A closed deal with no extraction on file has no page to open. It keeps the row shape — it is
   still a deal that closed — but must not offer the hover of something clickable. */
.row.is-unopenable { cursor: default; }
.row.is-unopenable:hover { background: var(--surface); }

/* The severity stripe: state as form, readable before any word is. */
.stripe { align-self: stretch; background: var(--line); }
.row.is-blocked   .stripe { background: var(--blocked); }
.row.is-review    .stripe { background: var(--review); }
.row.is-ready     .stripe { background: var(--good); }
.row.is-posted    .stripe { background: var(--ink-3); }
.row.is-golden    .stripe { background: var(--accent); }
/* Taken: grey like posted, because both are end states somebody decided rather than gates
   still to clear. Deliberately quieter than blocked — a taken deal wants no action. */
.row.is-taken     .stripe { background: var(--line); }
.row.is-taken     { opacity: 0.78; }

.dealno { font: 600 13px/1 var(--mono); color: var(--ink-2); }
.who-line { font-weight: 600; letter-spacing: -0.005em; }
.unit { color: var(--ink-3); font-size: 13px; }
.family { color: var(--ink-2); font-size: 13px; }
.amount {
  text-align: right; font: 500 14px/1 var(--mono);
  font-variant-numeric: tabular-nums;
}
.badges { display: flex; gap: 6px; justify-content: flex-end; flex-wrap: wrap; }

.pill {
  display: inline-block; padding: 2px 8px; border-radius: 100px;
  font-size: 11px; font-weight: 650; letter-spacing: 0.02em;
  background: var(--surface-2); color: var(--ink-2); white-space: nowrap;
}
.pill.blocked { background: var(--blocked-bg); color: var(--blocked); }
.pill.review  { background: var(--review-bg);  color: var(--review); }
.pill.good    { background: var(--good-bg);    color: var(--good); }
.pill.accent  { background: var(--accent-bg);  color: var(--accent); }

.empty { color: var(--ink-3); font-size: 14px; padding: 14px;
         border: 1px dashed var(--line); border-radius: var(--radius); }

/* When the DealerRock sweep last reported in. Deliberately quiet while it is healthy — it is
   status, not news, and a permanent banner is a banner nobody reads. It goes red only when the
   sweep has actually stopped happening, which is the state that otherwise looks identical to a
   week with no closings. */
.sweepline { color: var(--ink-3); font-size: 13px; line-height: 1.5;
             margin: 0 2px 18px; }
.sweepline.bad { color: var(--blocked); background: var(--blocked-bg);
                 border: 1px solid var(--blocked); border-radius: var(--radius);
                 padding: 10px 12px; }

/* What a group is NOT showing, and the one click that shows it. Quiet, but never absent:
   a list that stops without saying so reads as a complete list. */
.more { color: var(--ink-3); font-size: 13px; margin: 10px 2px 0; line-height: 1.5; }
.more a { color: var(--accent); font-weight: 600; text-decoration: none; white-space: nowrap; }
.more a:hover, .more a:focus-visible { text-decoration: underline; }

/* ---------------------------------------------------------------- detail */
.dealhead {
  display: flex; align-items: flex-start; gap: 20px; flex-wrap: wrap;
  padding-bottom: 16px; margin-bottom: 20px; border-bottom: 1px solid var(--line);
}
.dealhead h2 { margin: 0 0 4px; color: var(--brand-navy); font-family: var(--display);
               font-size: 27px; font-weight: 600; letter-spacing: 0.015em;
               text-wrap: balance; }
.dealhead .meta { color: var(--ink-2); font-size: 14px; }
.dealhead .actions { margin-left: auto; display: flex; gap: 10px; align-items: center; }

.layout { display: grid; grid-template-columns: minmax(0, 1fr) 316px; gap: 24px; align-items: start; }
@media (max-width: 1080px) { .layout { grid-template-columns: 1fr; } }

.card {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius); margin-bottom: 18px;
  box-shadow: 0 1px 4px rgb(2 60 91 / 5%);
}
.card > h3 {
  margin: 0; padding: 11px 14px; border-bottom: 1px solid var(--line-soft);
  background: #F7F9F9; color: var(--brand-navy); font-family: var(--display);
  font-size: 13px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.09em;
}
.card .body { padding: 14px; }

/* The office's already-posted entry. Deliberately unlike the editable draft above it: a green
   rule and flat, input-free cells, so nobody spends a second wondering which table they can
   change. Nothing in here is a form control — it is a quotation from the ledger. */
.office-entry { border-color: var(--good); }
.office-entry > h3 { background: var(--good-bg); color: var(--good);
  display: flex; align-items: center; gap: 12px; justify-content: space-between; }
.office-copy { margin: 0; }

/* Approving over a blocker. Folded away by default and rendered in the refusal's own colour:
   it should never be the obvious next click, only a reachable one. */
/* The approve-over-a-blocker disclosure was withdrawn 2026-08-09 (app._overridable);
   its styles went with it. */

/* A deal the office took by hand: the rail card that offers it back. */
.taken-card { border-color: var(--line); }

/* The question holding a deal. Amber like the review notices — it is not a refusal, it is the
   pipeline declining to guess, and one answer clears it. */
.needs-answer { border-color: var(--review); margin-bottom: 16px; }
.needs-answer > h3 { background: var(--review-bg); color: var(--review); }
.needs-answer .hint { color: var(--ink-3); font-size: 13px; line-height: 1.5; margin: 0 0 12px; }
.answerbox { display: grid; gap: 8px; padding: 12px; border: 1px solid var(--line);
  border-radius: 8px; background: var(--surface-2); }
.answerbox + .answerbox { margin-top: 10px; }
.answer-line { display: flex; justify-content: space-between; align-items: baseline; gap: 12px; }
.answer-line .amount { font: 600 14px/1 var(--mono); }
.answerbox select { font: inherit; padding: 7px 9px; border: 1px solid var(--line);
  border-radius: 6px; background: var(--surface); max-width: 100%; }
.answerbox select:focus { outline: none; border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-bg); }
.answer-scope { border: 0; margin: 0; padding: 0; display: grid; gap: 4px;
  font-size: 13px; color: var(--ink-2); }
.answer-scope label { display: flex; gap: 7px; align-items: flex-start; line-height: 1.45; }
.answerbox button { justify-self: start; }
.office-entry .hint { color: var(--ink-3); font-size: 13px; line-height: 1.5; margin: 0 0 12px; }
.office-entry table.je td { padding: 5px 6px; }
.office-entry .entry-meta { margin-bottom: 12px; }

/* Facts: a definition grid, not a table — it isn't tabular data. */
.facts { display: grid; grid-template-columns: auto 1fr; gap: 7px 14px; font-size: 13.5px; }
.facts dt { color: var(--ink-3); }
.facts dd { margin: 0; font-variant-numeric: tabular-nums; }

.entry-meta { margin-bottom: 14px; }
.entry-field {
  padding: 7px 9px; min-height: 38px; max-width: 100%;
  font: inherit; color: var(--ink); background: var(--surface);
  border: 1px solid var(--line); border-radius: 4px;
}
.entry-field:focus {
  outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-bg);
}
.entry-doc-number { width: 220px; font-family: var(--mono); }
.entry-date { width: 130px; font-family: var(--mono); }
.entry-memo { width: 320px; }

.doclist { display: flex; flex-direction: column; gap: 8px; }
.doclist button {
  display: flex; align-items: center; gap: 9px; width: 100%; text-align: left;
  padding: 9px 11px; font: inherit; font-size: 13.5px;
  background: var(--surface-2); color: var(--ink);
  border: 1px solid var(--line); border-radius: var(--radius); cursor: pointer;
}
.doclist button:hover { border-color: var(--accent); color: var(--accent); }
.doclist button::before { content: "▤"; color: var(--ink-3); }

/* ---------------------------------------------------------------- the JE table */
.tablewrap { overflow-x: auto; }

table.je { width: 100%; border-collapse: collapse; font-size: 13.5px; }
table.je th {
  text-align: left; padding: 8px 10px; font-size: 11px; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.06em; color: var(--ink-3);
  border-bottom: 1px solid var(--line);
  position: sticky; top: 0; background: var(--surface);
}
table.je th.num, table.je td.num { text-align: right; }
table.je td { padding: 3px 6px; border-bottom: 1px solid var(--line-soft); vertical-align: middle; }
table.je tr:last-child td { border-bottom: 0; }

.line-flag-key {
  display: flex; align-items: center; gap: 8px;
  margin: 0 0 12px; color: var(--blocked); font-size: 13px; font-weight: 650;
}
.line-flag-swatch {
  width: 22px; height: 10px; flex: 0 0 auto;
  background: var(--blocked-bg); border-left: 4px solid var(--blocked);
}
table.je tr.flagged-line td {
  background: var(--blocked-bg);
  border-top: 1px solid color-mix(in srgb, var(--blocked) 25%, transparent);
  border-bottom-color: color-mix(in srgb, var(--blocked) 25%, transparent);
}
table.je tr.flagged-line td:first-child { border-left: 4px solid var(--blocked); }
table.je tr.flagged-line input,
table.je tr.flagged-line select { color: var(--blocked); font-weight: 650; }
.line-flag-mark {
  display: inline-grid; place-items: center;
  width: 17px; height: 17px; margin-left: 5px; border-radius: 50%;
  background: var(--blocked); color: #fff; font: 700 11px/1 var(--sans);
}

table.je input, table.je select {
  width: 100%; padding: 6px 7px; font: inherit; font-size: 13.5px;
  color: var(--ink); background: transparent;
  border: 1px solid transparent; border-radius: 4px;
}
table.je input:hover, table.je select:hover { border-color: var(--line); }
table.je input:focus, table.je select:focus {
  outline: none; border-color: var(--accent); background: var(--surface);
  box-shadow: 0 0 0 3px var(--accent-bg);
}
table.je input.money {
  text-align: right; font-family: var(--mono); font-variant-numeric: tabular-nums;
}
table.je select.acct { font-family: var(--mono); font-size: 12.5px; }
td.acctcell { min-width: 250px; }
td.desccell { min-width: 180px; }
td.namecell { min-width: 150px; }
td.moneycell { width: 122px; }
.linecell { text-align: right; }

/* --- adding and removing a line ------------------------------------------------------- */
table.je th.toolhead, td.rowtools { width: 34px; text-align: center; padding: 3px 4px; }
.sr-only {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}
button.rowdel {
  width: 26px; height: 26px; padding: 0; border-radius: 5px; cursor: pointer;
  border: 1px solid transparent; background: transparent;
  color: var(--ink-3); font: 600 16px/1 var(--sans);
}
button.rowdel:hover { border-color: var(--blocked); color: var(--blocked); }
button.rowdel:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }

/* A removed line stays on the page, struck through, until Save — so the reviewer can see what
   is about to go and put it back. Its fields are disabled, which is what stops the browser
   submitting them; the styling only makes that visible. */
table.je tr.row-deleted td { background: var(--line-soft); }
table.je tr.row-deleted input,
table.je tr.row-deleted select {
  color: var(--ink-3); text-decoration: line-through; opacity: 0.75;
}
table.je tr.row-deleted .lineno { color: var(--ink-3); }
button.rowdel[title="Put this line back"] { color: var(--accent); }

.rowadd-bar { display: flex; align-items: center; gap: 12px; margin-top: 12px; flex-wrap: wrap; }

tfoot td {
  padding: 10px; border-top: 2px solid var(--line); font-weight: 650;
  font-variant-numeric: tabular-nums;
}
tfoot td.num { font-family: var(--mono); }
.balance-ok   { color: var(--good); }
.balance-off  { color: var(--blocked); }

/* ---------------------------------------------------------------- notices */
.notice {
  display: flex; gap: 10px; padding: 11px 13px; border-radius: var(--radius);
  font-size: 13.5px; line-height: 1.45; margin-bottom: 12px;
  border: 1px solid transparent;
}
.notice strong { font-weight: 650; }
.notice.blocked { background: var(--blocked-bg); color: var(--blocked); border-color: color-mix(in srgb, var(--blocked) 25%, transparent); }
.notice.review  { background: var(--review-bg);  color: var(--review);  border-color: color-mix(in srgb, var(--review) 25%, transparent); }
.notice.good    { background: var(--good-bg);    color: var(--good);    border-color: color-mix(in srgb, var(--good) 25%, transparent); }
.notice.flat    { background: var(--surface-2);  color: var(--ink-2);   border-color: var(--line); }
.notice ul { margin: 4px 0 0; padding-left: 18px; }
.notice li { margin: 2px 0; }

/* ---------------------------------------------------------------- buttons */
.btn {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 9px 16px; font: inherit; font-size: 14px; font-weight: 600;
  border-radius: var(--radius); border: 1px solid var(--line);
  background: var(--surface); color: var(--ink); cursor: pointer; text-decoration: none;
}
.btn:hover { border-color: var(--ink-3); }
.btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.btn.primary { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); }
.btn.primary:hover { filter: brightness(1.08); }
.btn.danger { color: var(--blocked); }
.btn[disabled], .btn.disabled { opacity: 0.45; cursor: not-allowed; }
.btn.small { padding: 6px 11px; font-size: 13px; }
.form-actions {
  display: flex; gap: 10px; align-items: center; margin-top: 16px; flex-wrap: wrap;
}

/* ---------------------------------------------------------------- lightbox */
.lightbox {
  position: fixed; inset: 0; z-index: 60; display: none;
  background: color-mix(in srgb, #04090C 78%, transparent);
  padding: 28px;
}
.lightbox[open], .lightbox.open { display: flex; flex-direction: column; }
.lightbox header {
  display: flex; align-items: center; gap: 14px; padding-bottom: 12px; color: #fff;
}
.lightbox header .name { font-weight: 600; font-size: 14px; }
.lightbox header .hint { color: #A9BCC6; font-size: 13px; }
.lightbox header button { margin-left: auto; }
.lightbox iframe {
  flex: 1; width: 100%; border: 0; border-radius: var(--radius); background: #fff;
}

.diff { font-size: 13px; }
.diff li { margin: 3px 0; }
.diff code { font-family: var(--mono); font-size: 12.5px; }

.rejectbox { display: flex; gap: 8px; margin-top: 10px; }
.rejectbox input {
  flex: 1; padding: 8px 10px; font: inherit; font-size: 13.5px;
  border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--surface); color: var(--ink);
}
.rejectbox input:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-bg); }

/* ---------------------------------------------------------------- mobile
 * The desktop view stays a dense ledger. On phones, the queue and each JE line become cards:
 * no sideways page scrolling, no tiny tap targets, and every editable value keeps its label.
 */
@media (max-width: 780px) {
  body { font-size: 16px; }

  .topbar {
    align-items: center; gap: 6px 10px; min-height: 0; padding: 7px 12px 9px;
    flex-wrap: wrap;
  }
  .brand img { width: 126px; height: 58px; }
  .portal-title { flex: 1; padding-left: 10px; }
  .portal-title h1 { font-size: 15px; }
  .portal-title .eyebrow { font-size: 9px; }
  .portal-nav {
    width: 100%; order: 3; margin: 0; overflow-x: auto;
    padding: 1px 0 2px; scrollbar-width: thin;
  }
  .portal-nav a { min-height: 40px; display: inline-flex; align-items: center; }
  .topbar .who {
    width: 100%; margin-left: 0; order: 5; font-size: 12px;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  .topbar .sandbox-pill {
    width: 100%; order: 4; padding: 4px 10px; text-align: center;
  }
  /* Keep the menu on the first row beside the title, not stranded below the nav. */
  .usermenu { order: 2; margin-left: auto; }
  .usermenu > summary { min-height: 44px; }
  .usermenu-panel { max-width: min(90vw, 320px); }
  .usermenu-panel a { min-height: 44px; line-height: 24px; }

  .wrap, .wrap.wide { width: 100%; padding: 16px 12px 28px; }
  .reports-home { width: 100%; margin: 32px auto; padding: 0 12px 28px; }
  .report-links { grid-template-columns: 1fr; gap: 14px; margin-top: 24px; }
  .report-link { min-height: 0; padding: 22px; }
  .section { margin-bottom: 26px; }
  .section .hint { line-height: 1.35; }

  .rows { gap: 8px; border: 0; background: transparent; overflow: visible; }
  .row {
    grid-template-columns: 4px minmax(0, 1fr) auto;
    grid-template-rows: auto auto auto auto;
    gap: 5px 10px; padding: 12px 12px 12px 0;
    border: 1px solid var(--line); border-radius: var(--radius);
  }
  .row > * { min-width: 0; padding: 0; }
  .row > :nth-child(2) { padding-left: 0; }
  .row > :last-child { padding-right: 0; }
  .row .stripe { grid-column: 1; grid-row: 1 / -1; margin: -12px 0 -12px; border-radius: var(--radius) 0 0 var(--radius); }
  .row .dealno { grid-column: 2; grid-row: 1; align-self: center; }
  .row .customer-cell { grid-column: 2 / 4; grid-row: 2; }
  .row .family { grid-column: 2; grid-row: 3; align-self: center; }
  .row .amount { grid-column: 3; grid-row: 1; align-self: center; }
  .row .date { grid-column: 3; grid-row: 3; text-align: right; }
  .row .badges { grid-column: 2 / 4; grid-row: 4; justify-content: flex-start; padding-top: 3px; }
  .who-line { display: inline-block; font-size: 16px; line-height: 1.3; }
  .unit, .family { font-size: 12px; }
  .amount { font-size: 13px; }
  .pill { padding: 3px 8px; }

  .dealhead { gap: 12px; margin-bottom: 16px; }
  .dealhead h2 { font-size: 22px; line-height: 1.2; }
  .dealhead .meta { font-size: 13px; line-height: 1.45; overflow-wrap: anywhere; }
  .dealhead .actions { width: 100%; margin-left: 0; }
  .dealhead .actions .btn { width: 100%; justify-content: center; }

  .layout { gap: 6px; }
  .card { margin-bottom: 14px; overflow: hidden; }
  .card .body { padding: 12px; }
  .notice { padding: 11px; overflow-wrap: anywhere; }

  .entry-meta { display: block; }
  .entry-meta dt { margin-top: 9px; font-size: 12px; font-weight: 650; }
  .entry-meta dt:first-child { margin-top: 0; }
  .entry-meta dd { margin-top: 3px; }
  .entry-field, .entry-doc-number, .entry-date, .entry-memo {
    width: 100%; min-height: 44px; font-size: 16px;
  }

  .tablewrap { overflow: visible; }
  table.je, table.je tbody, table.je tfoot { display: block; width: 100%; }
  table.je thead {
    position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
    overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
  }
  table.je tbody { display: flex; flex-direction: column; gap: 12px; }
  table.je tbody tr {
    display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: 9px 10px; padding: 11px;
    border: 1px solid var(--line); border-radius: var(--radius);
    background: var(--surface-2);
  }
  table.je tbody tr.flagged-line {
    background: var(--blocked-bg);
    border-color: color-mix(in srgb, var(--blocked) 35%, var(--line));
    border-left: 4px solid var(--blocked);
  }
  table.je tbody tr.flagged-line td:first-child { border-left: 0; }
  table.je tbody td {
    display: block; width: auto; min-width: 0; padding: 0; border: 0;
    text-align: left;
  }
  table.je tbody td::before {
    content: attr(data-label); display: block; margin-bottom: 3px;
    color: var(--ink-3); font-size: 10px; font-weight: 700;
    text-transform: uppercase; letter-spacing: 0.06em;
  }
  table.je tbody .linecell {
    grid-column: 1; text-align: left; font-family: var(--mono);
  }
  /* The remove button rides beside the line number on the card's top row. Full width and
     44px tall, because a 26px hit target next to a money field is a mis-tap waiting to
     happen — and this one deletes a journal line. */
  table.je tbody .rowtools { grid-column: 2; justify-self: end; width: auto; }
  table.je tbody .rowtools::before { content: none; }
  table.je tbody button.rowdel {
    width: auto; min-height: 40px; padding: 0 16px; font-size: 18px;
    border-color: var(--line); background: var(--surface);
  }
  table.je tfoot .rowtools { display: none; }
  table.je tbody .acctcell,
  table.je tbody .desccell,
  table.je tbody .namecell { grid-column: 1 / -1; }
  table.je input, table.je select {
    min-height: 44px; padding: 9px; font-size: 16px;
    background: var(--surface); border-color: var(--line);
  }
  table.je select.acct { font-size: 14px; }
  table.je tfoot { margin-top: 12px; }
  table.je tfoot tr {
    display: grid; grid-template-columns: minmax(0, 1fr) auto auto;
    gap: 8px; align-items: center;
  }
  table.je tfoot td { display: block; padding: 9px 3px; border-bottom: 1px solid var(--line-soft); }
  table.je tfoot td:first-child { grid-column: 1; }
  table.je tfoot td:nth-child(2) { grid-column: 2; }
  table.je tfoot td:nth-child(3) { grid-column: 3; }
  table.je tfoot td[colspan="2"] { grid-column: 2 / 4; }

  .form-actions { align-items: stretch; }
  .form-actions .btn { width: 100%; min-height: 46px; justify-content: center; }
  .form-actions .unit { width: 100%; line-height: 1.4; }
  .doclist button { min-height: 46px; font-size: 15px; }

  .rejectbox { flex-direction: column; }
  .rejectbox input, .rejectbox .btn { width: 100%; min-height: 46px; }

  .lightbox { padding: 0; }
  .lightbox header {
    flex-wrap: wrap; padding: max(10px, env(safe-area-inset-top)) 12px 10px;
    background: #071014;
  }
  .lightbox header .hint { display: none; }
  .lightbox header button { min-height: 44px; }
  .lightbox iframe { border-radius: 0; }
}

@media (max-width: 390px) {
  .brand img { width: 112px; height: 52px; }
  .portal-title h1 { font-size: 13px; }
  .portal-title .eyebrow { display: none; }
  .row { grid-template-columns: 4px minmax(0, 1fr); }
  .row .stripe { grid-row: 1 / 7; }
  .row .customer-cell { grid-column: 2; }
  .row .amount { grid-column: 2; grid-row: 3; text-align: left; margin-top: 2px; }
  .row .family { grid-column: 2; grid-row: 4; }
  .row .date { grid-column: 2; grid-row: 5; text-align: left; }
  .row .badges { grid-column: 2; grid-row: 6; }
}

@media (prefers-reduced-motion: reduce) {
  * { animation: none !important; transition: none !important; }
}

/* The auto-intake confirmation. Deliberately not styled as a quiet aside: it is the only thing
   standing between a document nobody has opened and a signed-off journal entry. */
.confirm-docs {
  display: flex; gap: 10px; align-items: flex-start;
  margin: 16px 0 4px; padding: 12px 14px;
  border: 1px solid var(--amber, #c08a2e); border-radius: 6px;
  background: color-mix(in srgb, var(--amber, #c08a2e) 8%, transparent);
  font-size: 0.92rem; line-height: 1.45;
}
.confirm-docs input { margin-top: 3px; flex: 0 0 auto; width: 16px; height: 16px; }
.confirm-docs em { display: block; margin-top: 4px; opacity: 0.75; font-style: normal; }

/* ---------------------------------------------------------------- trade valuation (PRD 06)
   Standalone form controls: the existing input rules are scoped under `table.je` and
   `.answerbox select`, so a form outside the deal page inherits nothing. Phone-first, because
   the stated user is a broker standing in front of a customer — the current workflow is that
   he phones the owner instead. */

.tool-intro { margin: 26px 0 18px; }
.tool-intro h2 { margin: 2px 0 6px; font-family: var(--display); font-size: 1.5rem; }

.market-form {
  display: flex; flex-wrap: wrap; gap: 12px; align-items: flex-end;
  padding: 16px; background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius);
}
.market-form .field { display: flex; flex-direction: column; gap: 4px; flex: 1 1 130px; }
.market-form label {
  font-size: 0.78rem; letter-spacing: 0.04em; text-transform: uppercase; color: var(--ink-3);
}
.market-form label .unit { text-transform: none; letter-spacing: 0; }
.market-form input {
  font: inherit; font-size: 1rem; padding: 9px 10px; color: var(--ink);
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius);
  min-width: 0;
}
.market-form input:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.market-form button { flex: 0 0 auto; padding: 10px 18px; }

.acv-figure {
  margin: 4px 0 2px; font-family: var(--display); font-size: 2.4rem; line-height: 1.1;
  color: var(--brand-navy);
}
.acv-figure.muted { color: var(--ink-3); }
/* The basis is not decoration. A median without its n reads as a measurement rather than a
   policy setting, and this number replaces a human's judgement. */
.acv-basis { margin: 0 0 6px; font-size: 0.95rem; color: var(--ink-2); }

.table-scroll { overflow-x: auto; }
table.comps, table.sources { width: 100%; border-collapse: collapse; font-size: 0.94rem; }
table.comps th, table.sources th {
  text-align: left; font-size: 0.76rem; letter-spacing: 0.05em; text-transform: uppercase;
  color: var(--ink-3); font-weight: 600; padding: 6px 10px; border-bottom: 1px solid var(--line);
  white-space: nowrap;
}
table.comps td, table.sources td {
  padding: 8px 10px; border-bottom: 1px solid var(--line-soft); vertical-align: top;
}
table.comps td.price { font-variant-numeric: tabular-nums; font-weight: 600; white-space: nowrap; }
table.comps td.num, table.sources td.num { font-variant-numeric: tabular-nums; text-align: right; }
/* The heading has to sit over its own column. Left-aligned titles above right-aligned figures
   read as a misprint and make the eye travel to pair each one with its column. */
table.comps th.num, table.sources th.num { text-align: right; }
table.comps td.srcs { white-space: nowrap; }
table.comps td.srcs a { color: var(--accent); }
table.comps .muted, table.sources .muted { color: var(--ink-3); }
table.comps tr.flagrow td { border-bottom: 1px solid var(--line-soft); padding-top: 0; }
.why { color: var(--review); font-size: 0.86rem; }
table.sources tr.bad td { color: var(--blocked); }

/* A price cut sits under the asking price because it qualifies it: this is what the seller
   wanted before the market said otherwise. Same weight as the flags, not a badge. */
table.comps .cut {
  display: block; margin-top: 2px; font-weight: 500; font-size: 0.8rem; color: var(--review);
  white-space: nowrap;
}
/* Age is a soft fact — a floor on how long we have watched it — so it reads quieter than price
   and length, which are the sites' own numbers. */
table.comps td.age { color: var(--ink-2); font-size: 0.86rem; white-space: nowrap; }
/* The boat's own name, where a site published one. Small caps and quiet — it identifies the
   hull, it is not part of the model. */
table.comps .vessel {
  display: block; margin-top: 2px; font-size: 0.78rem; letter-spacing: 0.04em;
  text-transform: uppercase; color: var(--ink-3);
}
/* A read that did not cover everything the site holds. Coloured, because "31" and "31 of 67"
   should not look equally settled. */
table.sources td.num.partial { color: var(--review); }

/* The field rules, above the fold and above any result. Indented off the form so it reads as a
   note about the form rather than as part of the report.
   One rule per line: run together as a paragraph they read as a wall and the three separate
   facts — what length does, what year does, why there is no model box — blur into one. */
ul.hint.rules {
  max-width: 68ch; margin: 12px 0 0; padding: 0 0 0 12px;
  border-left: 2px solid var(--line);
  list-style: none;
}
ul.hint.rules li { margin-bottom: 8px; line-height: 1.5; }
ul.hint.rules li:last-child { margin-bottom: 0; }
/* The lead clause is the scannable part — a broker should be able to read only the bold text
   and still know what the three fields do. */
ul.hint.rules strong { color: var(--ink); }

/* What was searched, and the funnel from listings read to comparables. This sits ABOVE the ACV
   because it is the sentence that stops "43 read, 6 in the report" reading as a fault. */
.section.searched { margin-bottom: 18px; }
.searched-note {
  margin: 0 0 6px; font-weight: 600; color: var(--brand-navy); font-size: 0.95rem;
}
.funnel { margin: 0 0 4px; color: var(--ink-2); font-size: 0.95rem; }
.funnel strong { color: var(--ink-1); font-variant-numeric: tabular-nums; }

/* What the ACV median is made of, when it spans more than one model. Length-first searching
   returns a cohort — a Sea Ray SDX 290 and an SLX 310 are both 31-footers and $130,000 apart —
   so the composition sits directly under the figure it explains. */
.mix { margin-top: 16px; padding-top: 14px; border-top: 1px solid var(--line-soft); }
.mix-head { margin: 0 0 10px; font-size: 0.9rem; color: var(--ink-2); max-width: 70ch; }
table.mix-table { width: 100%; border-collapse: collapse; font-size: 0.94rem; }
table.mix-table th {
  text-align: left; font-size: 0.76rem; text-transform: uppercase; letter-spacing: 0.05em;
  color: var(--ink-3); font-weight: 600; padding: 0 10px 6px 0;
  border-bottom: 1px solid var(--line);
}
table.mix-table th.num, table.mix-table td.num { text-align: right; }
table.mix-table td {
  padding: 7px 10px 7px 0; border-bottom: 1px solid var(--line-soft);
  font-variant-numeric: tabular-nums;
}
table.mix-table td:first-child { font-weight: 600; font-variant-numeric: normal; }
table.mix-table th:last-child, table.mix-table td:last-child { padding-right: 0; }
/* The per-model ACV is the number a broker actually leaves with, so it carries the weight. */
table.mix-table td.acv { font-weight: 700; color: var(--brand-navy); }
/* Fewer than three listings: a median of one is that listing. Still shown, visibly weaker. */
table.mix-table tr.thin td { color: var(--ink-3); }
table.mix-table tr.thin td.acv { color: var(--ink-3); font-weight: 600; }

/* ---------------------------------------------------------------------------
   A phone at a boat show.

   Matt, 2026-08-13: *"How could this exist on someone's phone? … this is just going to be a real
   quick, kind of, jump in, boat shows, everyone's going to be in it, just all over the place."*

   So below 780px every table on this page stops being a table and becomes cards. A seven-column
   comp table in a horizontal-scroll box is technically readable and useless in one hand on a dock,
   and the per-model breakout is six columns wide.

   Two rules, both inherited from the JE tables above rather than invented here:

     * **The label sits ABOVE its value, never beside it.** A label-left/value-right split looks
       tidy until a model name or a location wraps, at which point the two columns tear apart and
       the pairing is lost. Stacking survives any content length.
     * `data-label` carries the heading, so one set of markup serves both layouts and there is no
       duplicated text to drift out of sync.

   Tap targets are 44px minimum, which is the reason the form fields and links grow rather than
   shrink here. Everything else is padding: a report read at arm's length on a dock needs air
   between the numbers more than it needs to fit more of them on screen.
   --------------------------------------------------------------------------- */
@media (max-width: 780px) {
  /* ---- the form: full-width fields, thumb-sized, 16px so iOS does not zoom on focus ---- */
  .market-form {
    flex-direction: column; align-items: stretch; gap: 14px;
    padding: 14px; border: 1px solid var(--line); border-radius: var(--radius);
    background: var(--surface);
  }
  .market-form .field { flex: 1 1 auto; }
  .market-form input { min-height: 44px; font-size: 16px; padding: 10px 12px; }
  .market-form button { width: 100%; min-height: 46px; font-size: 16px; }

  .tool-intro { margin-bottom: 14px; }
  .tool-intro h2 { font-size: 22px; line-height: 1.2; }
  ul.hint.rules { margin-top: 14px; padding: 2px 0 2px 12px; }
  ul.hint.rules li { margin-bottom: 12px; line-height: 1.5; }

  .section.searched { margin-bottom: 20px; }
  .funnel { line-height: 1.5; }
  .acv-figure { font-size: 2.1rem; line-height: 1.1; }
  .acv-basis { line-height: 1.45; }

  /* Cards, not scrollers. Anything already inside a scroll box gets to breathe instead. */
  .table-scroll { overflow-x: visible; }

  table.comps, table.comps tbody, table.comps tr, table.comps td,
  table.sources, table.sources tbody, table.sources tr, table.sources td,
  table.mix-table, table.mix-table tbody, table.mix-table tr, table.mix-table td {
    display: block; width: auto;
  }
  table.comps thead, table.sources thead, table.mix-table thead {
    position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
    overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
  }
  table.comps tr, table.sources tr, table.mix-table tr {
    border: 1px solid var(--line); border-radius: var(--radius);
    padding: 14px; margin-bottom: 12px; background: var(--surface);
  }
  table.comps td, table.sources td, table.mix-table td {
    border: 0; padding: 0; text-align: left; overflow-wrap: anywhere;
  }
  /* The stacked label. Same size and weight as the JE cards, so the two pages feel like one app. */
  table.comps td[data-label], table.sources td[data-label], table.mix-table td[data-label] {
    margin-top: 10px;
  }
  table.comps td[data-label]::before,
  table.sources td[data-label]::before,
  table.mix-table td[data-label]::before {
    content: attr(data-label); display: block; margin-bottom: 3px;
    color: var(--ink-3); font-size: 10px; font-weight: 700;
    text-transform: uppercase; letter-spacing: 0.06em;
  }
  table.comps td.num, table.sources td.num, table.mix-table td.num { text-align: left; }

  /* ---- comps: price and boat are the card's headline, the rest is labelled beneath ---- */
  table.comps td.price { font-size: 1.25rem; line-height: 1.2; }
  table.comps td.price .cut { display: block; margin-top: 3px; }
  table.comps td:nth-child(2) { font-weight: 650; font-size: 1.02rem; margin-top: 2px; }
  table.comps td.srcs, table.comps td.age { white-space: normal; }
  /* Links are the one thing on this card anyone taps. */
  table.comps td.srcs a {
    display: inline-block; min-height: 32px; line-height: 32px; padding-right: 4px;
  }
  /* The flag belongs to the card above it, not to a card of its own. */
  table.comps tr.flagrow {
    border: 0; border-radius: 0; padding: 0 14px 12px; margin: -12px 0 12px;
    background: transparent;
  }
  table.comps tr.flagrow td:first-child { display: none; }

  /* ---- provenance: site name leads, the "why" is the part worth reading on a phone ---- */
  table.sources td:first-child { font-weight: 650; font-size: 1.02rem; }
  table.sources td.why { font-size: 0.86rem; line-height: 1.45; }
  table.sources td.why:empty { display: none; }

  /* ---- the per-model breakout: model heads the card, its own ACV is the payoff line ---- */
  table.mix-table td:first-child { font-weight: 700; font-size: 1.05rem; }
  table.mix-table td.acv { font-size: 1.15rem; }
  table.mix-table td.acv::before { color: var(--brand-navy); }
  .mix { margin-top: 18px; padding-top: 16px; }
  .mix-head { line-height: 1.45; margin-bottom: 12px; }
}

/* A phone held in one hand on a dock, rather than a large one on a table. Nothing changes shape
   here — the cards already handle it — it is only that the page's own gutters get too tight. */
@media (max-width: 400px) {
  .wrap, .wrap.wide { padding-left: 10px; padding-right: 10px; }
  table.comps tr, table.sources tr, table.mix-table tr { padding: 12px; }
  table.comps tr.flagrow { padding-left: 12px; padding-right: 12px; }
  .market-form { padding: 12px; }
  .acv-figure { font-size: 1.9rem; }
}
