/* ══ The document design system ══════════════════════════════════════════════
   One source of truth for the proposal, the invoice and the contract. Every
   part the three documents have in common — the sheet, the letterhead, the
   meta band, parties, section bands, label/value fields, text blocks, the
   schedule card, totals and the footer — is defined once, here. An edit to a
   shared component changes all three documents; that is the whole point of
   this file.

   Loaded by all six document pages (the three *_public.html and the three
   *_edit.html) BEFORE that document's own stylesheet:

     fonts_doc.css → doc_core.css → <doc>_doc.css → doc_print.css → _doc_brand

   What still belongs in a per-document stylesheet is only what genuinely
   exists in one document: the proposal's package cards, add-ons and timeline;
   the invoice's line items, amount-due callout and payment panel; the
   contract's numbered clauses, signature blocks and audit trail. If you find
   yourself writing the same rule in two of them, it belongs here instead.

   ── Class naming ──
   Components are named for what they are, not for the document they came
   from: .text-block, not .term or .clause; .field, not .fact or .sc-cell.

   Every rule also lists the older per-document class names as extra
   selectors. Those aliases are load-bearing and must not be dropped: a saved
   proposal/invoice/contract is a frozen HTML snapshot (Proposal.content,
   Agent.*_template_html, …) written with whatever class names were current
   the day the vendor saved it. Nothing ever rewrites that markup, so a rule
   that only matched the new name would leave every existing document
   unstyled. New markup should use the modular name; both render identically.
   ═════════════════════════════════════════════════════════════════════════ */

:root {
  /* ── Brand pipeline — do not rename. _doc_brand.html overrides these from
     Agent.doc_theme_vars via an inline <style> after this file, so source
     order alone lets a vendor's color win. These are the fallbacks. ── */
  --accent:     #2d64bc;   /* text-safe blue (~5:1 on white) */
  --accent-lt:  #e9f0fb;
  --accent-mid: #5b86cb;
  --accent-dk:  #25539e;
  --accent-ink: #1d417a;

  /* ── Platform UI palette — deliberately NOT part of the brand pipeline ──
     Everything above is repainted per vendor by _doc_brand.html. That is right
     for the document and wrong for the tool wrapped around it: the toolbar,
     modals, menus, add/remove controls and the contenteditable focus ring are
     Zulli's own UI, not the vendor's stationery, and they should look the same
     in every account. So the editor chrome reads --ui-* and the document reads
     --accent/--brand; nothing ever overrides the tokens below.

     Values are ui_concept.css's light theme (--accent/--brand-hover/
     --brand-deep/--accent-wash/--brand-line/--on-brand) — the doc pages are
     white-paper surfaces, so they take the light side of the platform brand.
     Keep them in step with that file by hand: these pages don't load it. ── */
  --ui-brand:       #2d64bc;
  --ui-brand-fill:  #2d64bc;
  --ui-brand-hover: #27579f;
  --ui-brand-deep:  #1b3f7a;
  --ui-brand-wash:  #eaf0fa;
  --ui-brand-line:  #c6d8f2;
  --ui-on-brand:    #ffffff;

  /* ── Ink ramp. Each has a second name because the three stylesheets grew up
     apart and named the same colour differently; both spellings are live in
     saved markup and in doc_editor_chrome.css. ── */
  --ink:       #0f172a;
  --muted:     #64748b;
  --faint:     #94a0b0;
  --hairline:  rgba(15, 23, 42, .10);
  --page:      #f5f6f8;
  --sheet:     #ffffff;
  --ink-mid:   var(--muted);
  --ink-light: var(--faint);
  --rule:      var(--hairline);
  --bg:        var(--page);
  --surface:   var(--sheet);
  --brand:      var(--accent);
  --brand-deep: var(--accent-dk);
  --tint:       var(--accent-lt);

  /* Status colours. */
  --danger:    #b4232a;
  --danger-bg: #fcebec;
  --red:       var(--danger);
  --red-bg:    var(--danger-bg);
  --paid:      #1a6b45;
  --paid-bg:   #d4f0e4;
  --info:      #2a40b8;
  --info-bg:   #e8eeff;

  /* Tinted band fill — the meta strip, the terms/acceptance bands, the
     schedule card's header. One value so they can never drift apart. */
  --band-tint: #fafbfc;

  --font-sans:  'DM Sans', system-ui, -apple-system, sans-serif;
  --font-serif: 'Fraunces', Georgia, 'Iowan Old Style', ui-serif, serif;
  --font-mono:  'IBM Plex Mono', ui-monospace, SFMono-Regular, Menlo, monospace;

  /* ── Geometry ──
     One sheet width and one spacing scale for all three documents. The
     invoice used to be 800px against the other two at 820, and each document
     had its own vertical rhythm (the proposal padded its sections by up to
     52px, the invoice by up to 30, the contract by 22), so the same stack of
     bands measured differently in each. These are the contract's values.
     doc_print.css re-pins --sec-x for paper. */
  --col-w: 820px;
  --sec-x: clamp(24px, 4.5vw, 52px);   /* band side padding */
  --sec-y: 22px;                        /* band top/bottom padding */
  --band-y: 18px;                       /* the tighter meta band */
  --head-y: clamp(26px, 4.5vw, 34px);   /* letterhead top */
  --head-y-end: clamp(20px, 3.5vw, 26px);
}

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

/* Custom scrollbar — thin, subtle gray, no arrows. Same treatment as the
   rest of the site (see base.css). WebKit/Blink only: the standard
   scrollbar-width/scrollbar-color props are intentionally omitted — setting
   them makes Chromium ignore these ::-webkit-scrollbar rules (and re-adds
   the native arrow buttons). Firefox falls back to its own scrollbars,
   which have no arrows anyway. Shared here since doc_core.css loads on all
   six document pages (editor + public/print). */
@supports selector(::-webkit-scrollbar){
  *{ scrollbar-width: auto; }
}
*::-webkit-scrollbar{ width: 8px; height: 8px; }
*::-webkit-scrollbar-track{ background: transparent; }
*::-webkit-scrollbar-thumb{
  background: rgba(128,128,140,.4);
  border-radius: 20px;
  border: 2px solid transparent;
  background-clip: padding-box;
}
*::-webkit-scrollbar-thumb:hover{
  background: rgba(128,128,140,.65);
  background-clip: padding-box;
}
*::-webkit-scrollbar-button,
*::-webkit-scrollbar-button:single-button,
*::-webkit-scrollbar-button:start,
*::-webkit-scrollbar-button:end,
*::-webkit-scrollbar-button:horizontal,
*::-webkit-scrollbar-button:vertical{
  display: none; width: 0; height: 0;
}
*::-webkit-scrollbar-corner{ background: transparent; }

body {
  font-family: var(--font-sans);
  background: var(--page);
  color: var(--ink);
  min-height: 100vh;
  font-size: 15px;
  line-height: 1.55;
  font-feature-settings: "tnum" 1;
  -webkit-font-smoothing: antialiased;
}

@media (prefers-reduced-motion: reduce) {
  *{ animation-duration: 0.001ms !important; animation-iteration-count: 1 !important; transition-duration: 0.001ms !important; }
}

/* Off-screen until it receives keyboard focus. */
.skip-link {
  position: absolute; left: 8px; top: -48px; z-index: 1000;
  background: var(--sheet, #fff); color: var(--ink);
  padding: 10px 16px; border-radius: 8px;
  box-shadow: 0 2px 10px rgba(0,0,0,.25);
  font-size: 14px; font-weight: 600; text-decoration: none;
  transition: top .15s ease;
}
.skip-link:focus { top: 8px; }

/* ── The stage and the sheet ──
   .doc-sheet is the modular name; .doc is the proposal's and contract's,
   .invoice is the invoice's. */
.pdoc-stage { display: flex; flex-direction: column; align-items: center; width: 100%; padding: clamp(14px, 3vw, 32px) 12px 80px; } .doc, .invoice{
  background: var(--sheet);
  width: 100%;
  max-width: var(--col-w);
  margin: 0 auto;
  border: 1px solid var(--rule);
  border-radius: 4px;
  box-shadow: 0 1px 2px rgba(15,23,42,.04), 0 14px 34px -20px rgba(15,23,42,.22);
  position: relative;
  overflow: hidden;
}

/* The accent bar across the very top of every document. */
.rule { height: 3px; background: var(--brand); }
.serif { font-family: var(--font-serif); }
.pad,
.items-section, .party-section,
.recitals, .scope, .clauses, .acceptance, .audit,
.doc > .parties,
/* Retired proposal bands (see the Legacy compat note in proposal_doc.css). */
.intro, .event-overview, .services, .alacarte, .investment,
.payment-terms, .timeline, .terms.psection{
  padding: var(--sec-y) var(--sec-x);
}
.party-section,
.recitals, .scope, .clauses, .acceptance, .audit,
.doc > .parties,
.intro, .event-overview, .services, .alacarte, .investment,
.payment-terms, .timeline, .terms.psection{
  border-bottom: 1px solid var(--rule);
} .terms-band, .accept, .acceptance, .audit{ background: var(--band-tint); }

/* ── Letterhead ──
   The contract's layout, which the other two now share. Grid with two fixed
   halves, deliberately not a wrapping flex row: flex breaks lines on each
   item's max-content width, so a long tagline (which sets the left block's
   max-content to the whole line) pushed the document-type column onto its own
   row at full width instead of letting it shrink. Grid columns never wrap,
   and min-width:0 lets the tagline wrap inside its own half. */
.letterhead, .cover {
  display: grid; grid-template-columns: 1fr 1fr; align-items: start; gap: 24px;
  padding: var(--head-y) var(--sec-x) var(--head-y-end);
  border-bottom: 1px solid var(--rule);
}
.letterhead > *, .cover > * { min-width: 0; }
.mark-name, .company-name { font-family: var(--font-serif); font-size: 25px; font-weight: 500; line-height: 1.15; letter-spacing: -.015em; color: var(--ink); }
/* The tagline is the vendor's own sentence, so it is set as written — sans,
   sentence case, no tracking. Small-caps styling turned a line of prose into
   what looked like a mis-set field label, and a long one wrapped into a block
   of tracked-out uppercase beside the business name. */
.mark-name small {
  display: block; font-family: var(--font-sans); font-size: 12.5px; font-weight: 400;
  letter-spacing: 0; text-transform: none; color: var(--ink-mid);
  margin-top: 6px; line-height: 1.45;
}
.company-meta { font-size: 12.5px; color: var(--ink-light); line-height: 1.6; margin-top: 8px; }

.doc-type, .doc-badge { text-align: right; }
.doc-label, .doc-word { font-size: 10px; font-weight: 600; letter-spacing: .18em; text-transform: uppercase; color: var(--brand); margin: 0 0 5px; }
.doc-num, .doc-sub { font-family: var(--font-mono); font-size: 23px; font-weight: 500; letter-spacing: -.01em; margin: 0; line-height: 1.05; color: var(--ink); }

.status-pill {
  display: inline-block; margin-top: 9px; padding: 3px 10px; border-radius: 999px;
  font-size: 10px; font-weight: 600; letter-spacing: .06em; text-transform: uppercase;
  -webkit-user-select: none; user-select: none;
}
.status-pill.draft    { background: rgba(15,23,42,.06); color: var(--ink-mid); }
.status-pill.sent     { background: var(--info-bg); color: var(--info); }
.status-pill.accepted { background: var(--paid-bg); color: var(--paid); }
.status-pill.paid     { background: var(--paid-bg); color: var(--paid); }
.status-pill.executed { background: var(--paid-bg); color: var(--paid); }
.status-pill.signed   { background: #fff4d6; color: #8a6100; }
.status-pill.unpaid   { background: var(--red-bg); color: var(--red); }
.status-pill.declined { background: var(--red-bg); color: var(--red); }
.status-pill.void     { background: rgba(15,23,42,.06); color: var(--ink-mid); } .meta, .meta-strip{
  display: flex; flex-wrap: wrap; gap: 14px 24px;
  padding: var(--band-y) var(--sec-x);
  border-bottom: 1px solid var(--rule);
  background: var(--band-tint);
} .meta > div, .meta-cell{ flex: 1 1 0; min-width: 0; }
.meta-label, .sc-label, .ov-label,
.meta > div span, .fact span{
  display: block;
  font-size: 10.5px; font-weight: 600; letter-spacing: .1em; text-transform: uppercase;
  color: var(--ink-light); margin-bottom: 3px;
}
.meta-value, .sc-value, .ov-value,
.meta > div b, .fact b{
  font-weight: 500; font-size: 13.5px; letter-spacing: -.005em; color: var(--ink);
}
.meta-cell.late .meta-value { color: var(--red); } .facts, .scope-grid, .overview-grid{ display: flex; flex-wrap: wrap; gap: 14px 30px; }
.field, .fact, .sc-cell, .ov-cell { flex: 1 1 136px; min-width: 0; }
.field.full, .fact.full, .sc-cell.full, .ov-cell.full { flex-basis: 100%; } .fact.full b, .sc-cell.full .sc-value, .ov-cell.full .ov-value{ font-weight: 400; line-height: 1.5; } .fact b, .sc-value, .ov-value{ font-size: 14px; } .facts + .facts, .fact-files, .deliverables{
  margin-top: 20px; padding-top: 20px; border-top: 1px solid var(--rule);
}

/* ── Kicker — the small uppercase label that opens a band ── */
.kicker, .sec-label, .section-label {
  font-size: 11px; font-weight: 600; letter-spacing: .16em; text-transform: uppercase;
  color: var(--brand); margin: 0 0 12px;
}

/* ── Headings ──
   Display type is the serif, body type is the sans: the one typographic rule
   the three documents share. h3–h6 exist so a heading in vendor-authored
   content can't inherit body's DM Sans and come out in the wrong voice. */
h1 { font-family: var(--font-serif); font-weight: 400; font-size: clamp(28px, 4.6vw, 40px); line-height: 1.1; letter-spacing: -.015em; margin: 0 0 16px; }
h2 { font-family: var(--font-serif); font-weight: 500; font-size: 20px; letter-spacing: -.01em; line-height: 1.25; margin: 0; }
h3, h4, h5, h6 { font-family: var(--font-serif); font-weight: 500; }
.lede, .intro-body, .services-note, .acceptance-note { color: var(--ink-mid); font-size: 14.5px; margin: 0 0 22px; max-width: 64ch; }

/* ── Parties ──
   "Prepared for / Prepared by", "Billed to / From", "The Client / The
   Vendor" — the same block under three sets of names. Undivided: the vertical
   rule between the two halves was the contract's alone. */
.parties, .party-section { display: flex; flex-wrap: wrap; gap: 20px 34px; }
.party { flex: 1 1 240px; min-width: 0; }
.party-label, .party-role {
  font-size: 10.5px; font-weight: 600; letter-spacing: .1em; text-transform: uppercase;
  color: var(--brand); margin: 0 0 9px;
}
/* The vendor's own side is the quieter of the two, whichever name it carries. */
.party.you .party-label, .party.from .party-label, .party + .party .party-role { color: var(--ink-light); }
.party-name { font-family: var(--font-serif); font-size: 17px; font-weight: 500; line-height: 1.25; color: var(--ink); margin: 0 0 6px; }
.party-line, .party-detail { font-size: 13px; color: var(--ink-mid); margin: 0; line-height: 1.65; }
.divider { height: 1px; background: var(--rule); } .term, .clause, .term-item{ flex: 1 1 260px; min-width: 0; } .terms, .terms-grid{ display: flex; flex-wrap: wrap; gap: 20px 34px; } .term-title, .clause-title{
  font-size: 13.5px; font-weight: 600; letter-spacing: -.005em; color: var(--ink); margin: 0 0 5px;
} .term-body, .clause-body{
  margin: 0; font-size: 13px; color: var(--ink-mid); line-height: 1.6;
} .clause-body p{ margin: 0 0 9px; } .clause-body p:last-child{ margin-bottom: 0; }
.term-title { position: relative; padding-top: 13px; }
.term-title::before { content: ""; position: absolute; top: 0; left: 0; right: 0; height: 1.5px; background: var(--brand); }

/* ── Schedule card ──
   Payment milestones. The proposal builds it from divs and the contract from
   a <table> frozen into every saved snapshot, so both markups are styled into
   the same ruled, rounded card with a tinted header strip.

   border-collapse: separate is what makes the table's rounded corners
   possible at all — a collapsed table shares cell borders and the radius has
   nothing to clip. The corner cells carry their own radii because
   `overflow: hidden` on a <table> is not reliable in either engine. */
.schedule { margin-top: 24px; border: 1px solid var(--rule); border-radius: 10px; overflow: hidden; }
.payment-table {
  width: 100%; margin: 14px 0 0;
  border: 1px solid var(--rule); border-radius: 10px;
  border-collapse: separate; border-spacing: 0;
}
.schedule-head, .payment-table thead tr, .payment-table th {
  background: var(--band-tint);
  font-size: 10.5px; font-weight: 600; letter-spacing: .1em; text-transform: uppercase;
  color: var(--ink-mid);
}
.schedule-head { padding: 11px 16px; border-bottom: 1px solid var(--rule); }
.payment-table th { padding: 11px 16px; text-align: left; border-bottom: 1px solid var(--rule); }
.payment-table th:first-child { border-top-left-radius: 10px; }
.payment-table th:last-child { border-top-right-radius: 10px; }
.payment-table th.right { text-align: right; }

.srow { display: flex; align-items: center; gap: 14px; padding: 12px 16px; border-bottom: 1px solid var(--rule); }
.srow:last-child { border-bottom: 0; }
.payment-table td { padding: 12px 16px; font-size: 13.5px; color: var(--ink); border-bottom: 1px solid var(--rule); }
.payment-table tbody tr:last-child td { border-bottom: 0; }
/* when · what · amount, under both markups. */
.srow-when, .payment-table td.muted { font-size: 12.5px; font-weight: 500; color: var(--ink-mid); }
.srow-when { width: 96px; flex: none; }
.srow-what { flex: 1; min-width: 0; font-size: 13.5px; }
.srow-what small { display: block; color: var(--ink-mid); font-size: 12px; }
.srow-amt, .payment-table td.right { font-size: 14px; font-weight: 600; white-space: nowrap; }
.payment-table td.right { text-align: right; }

/* ── Totals ──
   The last line of money on a document: "Total investment", "Total Due",
   "Total". The label is sans, the figure is the serif. */
.total-row, .total-line, .tline, .inv-row {
  display: flex; justify-content: space-between; align-items: baseline; gap: 16px;
}
.tline, .inv-row { padding: 9px 0; font-size: 14px; border-bottom: 1px solid var(--rule); }
.tline span, .inv-row .il { color: var(--ink-mid); }
.tline b, .inv-row .iv { font-weight: 500; }
.total-row { padding: 8px 0; font-size: 13.5px; }
.total-row .tl { color: var(--ink-mid); }
.total-row .tv { font-weight: 500; color: var(--ink); }
.total-row.sum { border-top: 1px solid var(--rule); }

.tline.grand, .total-row.grand, .total-line, .inv-row.grand {
  border-top: 1.5px solid var(--ink); margin-top: 4px; padding-top: 12px; border-bottom: 0;
}
.tline.grand span, .total-row.grand .tl, .total-line .tl-label, .inv-row.grand .il {
  color: var(--ink); font-weight: 500; font-size: 15px;
}
.tline.grand b, .total-row.grand .tv, .total-line .tl-value, .inv-row.grand .iv {
  font-family: var(--font-serif); font-size: 22px; font-weight: 500; letter-spacing: -.01em; color: var(--ink);
}

/* ── Footer ── */
.doc-foot, .footer {
  display: flex; justify-content: space-between; align-items: center; gap: 14px; flex-wrap: wrap;
  padding: 15px var(--sec-x); border-top: 1px solid var(--rule);
  font-size: 12px; color: var(--ink-light);
}
.footer-thanks { font-family: var(--font-serif); font-size: 13.5px; font-style: italic; color: var(--ink-light); }
.footer-contact { font-size: 11.5px; color: var(--ink-light); text-align: right; line-height: 1.5; }
/* PDF-only running-footer source (doc_pdf.css / _doc_foot_src.html) —
   string-set has no effect in a browser, so it must stay invisible here on
   its own merits; it exists only to be captured, never to be seen. */
.doc-foot-src { visibility: hidden; position: absolute; height: 0; overflow: hidden; }

/* ── Editing affordances ──
   Only active while a field is genuinely editable; a harmless no-op on the
   client page, where JS forces contenteditable=false. Platform blue, not the
   vendor's brand: this ring says "you can type here", which is the editor
   talking, not the document. (The hover dash was already a hard-coded
   #2d64bc; the focus ring followed --brand and so drifted per vendor.) */
[contenteditable="true"] { outline: none; border-radius: 4px; cursor: text; }
[contenteditable="true"]:hover { outline: 1px dashed rgba(45,100,188,.45); outline-offset: 4px; }
[contenteditable="true"]:focus { outline: 1.5px solid var(--ui-brand); outline-offset: 4px; background: rgba(45,100,188,.035); }
[contenteditable="true"]:empty::before { content: attr(data-ph); color: var(--ink-light); }
/* The prompt is editor copy. WeasyPrint runs no scripts, so on the PDF the
   contenteditable attribute is still there and the rule above printed "Phone"
   as if it were the vendor's number. Unfilled inline fields are also removed
   from the client copy server-side (services.strip_unfilled_fields); this
   catches any other prompt-carrying element. */
.is-public [data-ph]:empty::before { content: none; }

/* ── Editor chrome that a saved snapshot baked in ──
   The row-add/remove buttons are stripped at save time now, but documents
   saved before that still carry them, and a client opening one was offered
   "+ Add Line Item" on an invoice they were being asked to pay. `.is-public`
   marks the client-facing document root (the three *_public templates), so
   this can never reach the editor, which is the one place those controls are
   supposed to work. CSS rather than the JS strip in proposal_public.html /
   contract_public.html: WeasyPrint renders these same templates into the PDF
   and runs no scripts, so a JS-only fix leaves the downloaded copy wrong. */
.is-public .item-controls,
.is-public .ctrl-btn,
.is-public .peditor-ctl { display: none !important; }

/* ── Narrow screens ── */
@media (max-width: 640px) {
  .letterhead, .cover { grid-template-columns: 1fr; gap: 14px; align-items: start; }
  .doc-type, .doc-badge { text-align: left; }
  .mark-name, .company-name { font-size: 21px; } .meta, .meta-strip{ gap: 14px 20px; } .meta > div, .meta-cell{ flex-basis: 40%; }
.meta-cell.full, .meta > div.full{ flex-basis: 100%; } .facts > .fact, .scope-grid > .sc-cell, .overview-grid > .ov-cell,
  .parties > .party, .party-section > .party, .terms > .term,
  .terms-grid > .term-item{ flex-basis: 100%; }

  /* .payment-table (the contract's payment schedule) is a real <table> with
     three columns — Milestone/Due/Amount — that a narrow screen has no room
     for side by side, so each column squeezed down to a wrapped 2-3 word
     sliver. Reflow each row into the same compact shape the proposal's own
     div-based .srow schedule already uses: milestone and amount share a top
     line (amount pushed flush right by the milestone cell's flex-grow), the
     due date drops to a small subtitle line below. The header row's labels
     don't map onto that shape, so it's dropped — the layout speaks for
     itself once it's a row of cards instead of a grid. */
  .payment-table thead { display: none; }
  .payment-table, .payment-table tbody { display: block; }
  .payment-table tr {
    display: flex; flex-wrap: wrap; align-items: baseline; column-gap: 12px;
    padding: 12px 16px; border-bottom: 1px solid var(--rule);
  }
  .payment-table tr:last-child { border-bottom: 0; }
  .payment-table td { display: block; padding: 0; border-bottom: 0; }
  .payment-table td:first-child { order: 1; flex: 1 1 auto; min-width: 0; font-weight: 600; }
  .payment-table td.right { order: 2; flex: none; }
  .payment-table td.muted { order: 3; flex-basis: 100%; margin-top: 3px; }

  /* .srow (the proposal's own div-based payment schedule row) hits the same
     wall: a fixed 96px "when" column plus a nowrap amount left too little
     room for the milestone title and its percentage subtitle, wrapping
     mid-word ("Retainer / Deposit" broke right after the "/"). Same reflow
     as .payment-table above: title + amount share the top line, "when"
     drops to its own full-width line below instead of squeezing them. */
  .srow { flex-wrap: wrap; row-gap: 3px; }
  .srow-what { order: 1; }
  .srow-amt { order: 2; }
  .srow-when { order: 3; flex: 0 0 100%; width: auto; margin-top: 2px; }
}
