/*
 * chrome.css — the buyer-facing design system.
 *
 * WHY THIS FILE EXISTS
 * --------------------
 * Before this, every buyer page declared its own `:root`. index.html,
 * phone.html, show.html, claim.html and home.html each had a different ground
 * colour, a different border radius scale and, between them, three unrelated
 * typefaces (system-ui, Zilla Slab, Archivo Black). A buyer walking the real
 * path — claim → editor → send the guest link — crossed three visual identities
 * in four clicks. That is the same drift the vendored-fonts.css header warns
 * about, and the same fix: one file, every page.
 *
 * THE DIRECTION (cockpit #371, Rob picked direction 3, 2026-08-29)
 * ----------------------------------------------------------------
 * Notion's database/table register: light architectural, dense information,
 * sharp aligned grid, pastel tags doing category work without shouting,
 * disciplined sans hierarchy from a heavy display H1 down to 14px cells.
 *
 * Why it fits weaver rather than being a skin: **the editor is already a
 * database view that has never been drawn as one.** It has properties (fields
 * with a label, a value and a limit), rows (guest replies with a name and a
 * status) and a record set (the pages of a multi-page template). All three were
 * drawn as soft floating cards, which reads as "an app" but carries none of the
 * alignment that makes information legible. The refit draws what is already
 * there.
 *
 * THE ONE HARD CONSTRAINT
 * -----------------------
 * The buyer's artwork must render EXACTLY as before. Nothing in this file may
 * select into the inline SVG. There are deliberately no `text`, `tspan`,
 * `image` or `svg *` rules anywhere below, and `font-family` is set on `body`
 * only — which is what the previous stylesheets did too, so inheritance into
 * the artwork is unchanged.
 */

:root {
  /* --- ground ------------------------------------------------------------
     Warmer than Notion's neutral grey and cooler than weaver's old cream.
     Pure #F7F7F5 orphaned the warm gouache artwork most templates use; the
     old #F7F4EC made the chrome compete with it. This sits between. */
  --ground:      #FBFAF8;   /* page */
  --surface:     #FFFFFF;   /* rows, inputs, cards */
  --panel:       #F3F2EE;   /* the artwork stage, secondary rails */
  --panel-deep:  #EDEBE6;   /* pressed / inset */

  /* --- ink ---------------------------------------------------------------
     Warm near-black rather than the old navy. Navy on cream reads as
     stationery; this register wants the type to read as instrument. */
  /* Ratios below are measured, not estimated. The first draft of this file put
     --ink-3 at #85827A and asserted "4.6:1"; it is 3.84:1 on white, which is
     under the AA floor — and --ink-3 is what every PROPERTY LABEL is set in, so
     a buyer would have been reading "BRIDE-TO-BE'S NAME" below the threshold.
     Caught by computing the numbers instead of trusting the comment. */
  --ink:    #1F1E1B;        /* 16.67:1 on --surface, 16.15:1 on --ground */
  --ink-2:  #55534D;        /*  7.69:1 on --surface — secondary text        */
  --ink-3:  #6F6B61;        /*  5.31:1 on --surface, 4.74:1 on --panel      */

  /* --- structure ---------------------------------------------------------
     The hairline is the workhorse of this register. Two weights only. */
  --line:        #E7E5DF;
  --line-strong: #D6D3CB;

  /* --- accent ------------------------------------------------------------
     Deep pine. NOT Notion's blue (that would be a copy) and NOT weaver's old
     gold, which measured 2.3:1 on white and was being used for focus rings.
     #2F6F5E is 5.9:1 on white both ways, so it works as text, as a ring, and
     as a filled button with white type. It also sits quietly beside almost any
     invitation palette, which gold did not. */
  --accent:      #2F6F5E;
  --accent-deep: #245646;
  --accent-tint: #EAF1EE;
  --bad:         #A23B2E;   /* 6.0:1 on --surface */

  /* --- tags: pastel, doing category work without shouting -----------------
     Each pair is checked to clear 4.5:1 text-on-fill. */
  --tag-yes-bg:   #E9F0EA;  --tag-yes-ink:   #2C563B;  --tag-yes-line:   #D4E2D7;
  --tag-maybe-bg: #FAF1DE;  --tag-maybe-ink: #74561A;  --tag-maybe-line: #EEE2C6;
  --tag-no-bg:    #F7EAE7;  --tag-no-ink:    #8A3A2E;  --tag-no-line:    #ECD9D4;
  --tag-flat-bg:  #F1F0EC;  --tag-flat-ink:  #55534D;  --tag-flat-line:  #E4E2DC;

  /* --- type --------------------------------------------------------------
     One family, two weights. design-rules #8: a single typeface with a clear
     weight jump is a valid pairing, and Inter has exactly 400 and 700 vendored
     — so there is no 600 to fake and no third family to drift to.
     Inter is loaded by /vendored-fonts.css, which every buyer page already
     links for the artwork's own faces. */
  --face: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif;

  --t-display: 700 30px/1.15 var(--face);   /* page H1 */
  --t-h2:      700 19px/1.25 var(--face);   /* section head */
  --t-h3:      700 15px/1.35 var(--face);   /* row / card head */
  --t-body:    400 14px/1.5  var(--face);   /* cells, prose, table text */
  --t-input:   400 16px/1.4  var(--face);   /* 16px floor or iOS zooms on focus */
  --t-meta:    400 12px/1.4  var(--face);   /* counts, captions */

  /* --- rhythm ------------------------------------------------------------
     4px base. Everything below is a multiple; nothing in the refitted pages
     uses a raw pixel value that is not one of these. The old pages used
     3/5/6/7/9/11/13/22 and the misalignment is what read as "templated". */
  --s1: 4px;  --s2: 8px;  --s3: 12px; --s4: 16px;
  --s5: 24px; --s6: 32px; --s7: 48px; --s8: 64px;

  /* --- shape -------------------------------------------------------------
     4px, near-square. The old scale ran 8/10/14/999 mixed on one screen.
     999px is now reserved for tags and nothing else — a pill that means
     "category" cannot also mean "button". */
  --r:     4px;
  --r-lg:  6px;
  --r-tag: 999px;
}

* { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }

/* `hidden` is only a UA display:none, so ANY rule below that sets `display`
   silently outranks it. Several do. This restores the attribute as the
   authority — it is the reason the RSVP form once showed on a dead link. */
[hidden] { display: none !important; }

body {
  margin: 0;
  background: var(--ground);
  color: var(--ink);
  font: var(--t-input);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

/* --- type primitives ------------------------------------------------------ */

.wv-display { font: var(--t-display); letter-spacing: -0.022em; margin: 0; }
.wv-h2      { font: var(--t-h2);      letter-spacing: -0.014em; margin: 0; }
.wv-h3      { font: var(--t-h3);      letter-spacing: -0.006em; margin: 0; }
.wv-body    { font: var(--t-body);    color: var(--ink-2); margin: 0; }
.wv-meta    { font: var(--t-meta);    color: var(--ink-3); margin: 0; }

/* The property label. Uppercase, tracked, 11px — the one place tracking is
   used, so it reads as a system rather than as decoration. */
.wv-label {
  display: block; margin: 0;
  font: 700 11px/1.2 var(--face);
  letter-spacing: 0.07em; text-transform: uppercase;
  color: var(--ink-3);
}

/* Anything that counts. A count that shifts width as it ticks is the tell of
   a page that was never looked at while it changed. */
.wv-num { font-variant-numeric: tabular-nums; }

/* --- surfaces ------------------------------------------------------------- */

.wv-card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
}

/* A section header in the table register: label on the left, count on the
   right, hairline underneath. Used for GUEST REPLIES and SEND TO YOUR GUESTS. */
.wv-section-head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: var(--s3);
  padding-bottom: var(--s2);
  border-bottom: 1px solid var(--line);
  margin-bottom: var(--s2);
}

/* --- controls ------------------------------------------------------------- */

.wv-field {
  width: 100%;
  font: var(--t-input);
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--line-strong);
  border-radius: var(--r);
  padding: 10px var(--s3);
}
.wv-field::placeholder { color: var(--ink-3); }

/* One focus treatment for every focusable thing on every buyer page. Ring, not
   a colour swap, so it is visible on a filled button and on a white input. */
.wv-field:focus,
.wv-btn:focus-visible,
button:focus-visible,
a:focus-visible,
select:focus-visible,
input:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
  border-color: var(--accent);
}
.wv-field:focus { outline-offset: -1px; }

.wv-btn {
  font: 700 14px/1 var(--face);
  letter-spacing: 0.005em;
  padding: 11px var(--s4);
  min-height: 40px;
  border-radius: var(--r);
  border: 1px solid var(--line-strong);
  background: var(--surface);
  color: var(--ink);
  cursor: pointer;
}
.wv-btn:hover { background: var(--panel); }
.wv-btn[disabled] { opacity: .45; cursor: default; }

.wv-btn-primary {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
}
.wv-btn-primary:hover { background: var(--accent-deep); border-color: var(--accent-deep); }

/* --- tags: the pastel category vocabulary --------------------------------- */

.wv-tag {
  display: inline-flex; align-items: center; gap: var(--s1);
  font: 700 11px/1 var(--face);
  letter-spacing: 0.03em;
  padding: 4px var(--s2);
  border-radius: var(--r-tag);
  border: 1px solid var(--tag-flat-line);
  background: var(--tag-flat-bg);
  color: var(--tag-flat-ink);
  white-space: nowrap;
}
.wv-tag-yes   { background: var(--tag-yes-bg);   color: var(--tag-yes-ink);   border-color: var(--tag-yes-line); }
.wv-tag-maybe { background: var(--tag-maybe-bg); color: var(--tag-maybe-ink); border-color: var(--tag-maybe-line); }
.wv-tag-no    { background: var(--tag-no-bg);    color: var(--tag-no-ink);    border-color: var(--tag-no-line); }

/* --- the table ------------------------------------------------------------
   The signature of this refit. The guest replies were a loose list of names
   with pale pills beside them; they are a record set with a name, a status and
   an identity, so they are drawn as rows. */

.wv-table { display: grid; gap: 0; }

.wv-thead {
  display: grid; grid-template-columns: 1fr auto;
  gap: var(--s2);
  padding: 0 0 var(--s1);
  border-bottom: 1px solid var(--line-strong);
  font: 700 10px/1.2 var(--face);
  letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--ink-3);
}

.wv-row {
  display: grid; grid-template-columns: 1fr auto;
  gap: var(--s2); align-items: center;
  padding: var(--s2) 0;
  border-bottom: 1px solid var(--line);
  font: var(--t-body);
}
.wv-row:last-of-type { border-bottom: 0; }

.wv-cell-name { display: flex; align-items: center; gap: var(--s2); min-width: 0; }
.wv-cell-name span {
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  color: var(--ink);
}

/* Inline avatar. Initials on a tinted disc — an identity the row actually has,
   never a stock face. */
.wv-avatar {
  flex: 0 0 auto;
  width: 22px; height: 22px; border-radius: var(--r-tag);
  display: grid; place-items: center;
  background: var(--accent-tint);
  color: var(--accent-deep);
  font: 700 10px/1 var(--face);
  letter-spacing: 0.02em;
}
/* Painted from the attribute, never from a text node — see rsvp.mjs for why. */
.wv-avatar::before { content: attr(data-initials); }

/* A guest's note is a second line under their name, not a third column: the row
   is `1fr auto` and a third child would be squeezed to nothing. */
.rsvp-note {
  grid-column: 1 / -1;
  margin: var(--s1) 0 0 30px;   /* clears the 22px avatar + its 8px gap */
  font: var(--t-meta); font-style: italic;
  color: var(--ink-3);
}

/* The status tag reads lowercase in the DOM (that is the API's own value and
   what the tests assert on) and uppercase on the screen. */
.rsvp-table .wv-tag { text-transform: uppercase; }

.rsvp-counts { display: flex; flex-wrap: wrap; gap: var(--s1); margin-bottom: var(--s3); }

/* The ghost row. Notion's "New page" row, doing honest work: it tells the buyer
   the table is live and will grow, which is the one question they have while
   they wait. Deliberately NOT interactive and deliberately not styled like a
   button — there is nothing here for them to click. */
.wv-ghost {
  display: flex; align-items: center; gap: var(--s2);
  padding: var(--s2) 0 var(--s1);
  border-top: 1px dashed var(--line-strong);
  font: var(--t-meta);
  color: var(--ink-3);
}
.wv-ghost::before {
  content: "+";
  display: grid; place-items: center;
  width: 22px; height: 22px; border-radius: var(--r-tag);
  border: 1px dashed var(--line-strong);
  color: var(--ink-3);
  font: 400 13px/1 var(--face);
}

/* --- page / record pills --------------------------------------------------
   Multi-page templates. These are a record set, so they are numbered cells of
   a fixed width, not stadium buttons that stretch to fill their container.
   They used to: `button { flex: 1 }` in index.html applied to every button on
   the page, and nothing reset it here, so on a 1440px laptop page one was a
   275px-wide navy stadium. */
.wv-pages { display: flex; flex-wrap: wrap; gap: var(--s1); }
.wv-pages button {
  flex: 0 0 auto;
  min-width: 30px; min-height: 30px;
  padding: 0 var(--s2);
  font: 700 12px/1 var(--face);
  font-variant-numeric: tabular-nums;
  border: 1px solid var(--line);
  border-radius: var(--r);
  background: var(--surface);
  color: var(--ink-2);
  cursor: pointer;
}
.wv-pages button:hover { background: var(--panel); color: var(--ink); }
.wv-pages button.sel {
  background: var(--ink); border-color: var(--ink); color: var(--surface);
}

/* --- the page rail --------------------------------------------------------
   The numbered pills above are kept for any picker that has no SVG to draw;
   the real multi-page control is this — a rail of the actual pages. `1 2 3 4 5`
   never said which one was the invitation and which was the itinerary, so
   finding a page cost a click and a look. See pagerail.mjs.

   The thumbnail is a real inline SVG scaled by the browser, not an image, so it
   carries the buyer's live values and costs no extra request. */
.wv-pagerail {
  display: flex; gap: var(--s2);
  overflow-x: auto; overflow-y: hidden;
  scrollbar-width: none;
  padding: var(--s1) 0;
}
.wv-pagerail::-webkit-scrollbar { display: none; }

.wv-pagerail-item {
  flex: 0 0 auto;
  display: block;
  padding: 0;
  width: var(--rail-w, 46px);
  border: 1px solid var(--line);
  border-radius: var(--r);
  background: var(--surface);
  cursor: pointer;
  overflow: hidden;
  /* The thumbnail is the button's whole surface, so the button must not add a
     baseline gap under it. */
  line-height: 0;
}
.wv-pagerail-item:hover { border-color: var(--line-strong); }
.wv-pagerail-item.sel {
  border-color: var(--ink);
  box-shadow: 0 0 0 1px var(--ink);
}

/* The page preview. `aspect-ratio` is not set here: the SVG carries its own
   viewBox, so letting it size itself is what keeps a 5x7 card and a landscape
   itinerary page both correct in one rail. */
.wv-pagerail-thumb {
  display: block;
  background: var(--panel);
  border-radius: 3px;
  overflow: hidden;
}
.wv-pagerail-thumb > svg {
  display: block;
  width: 100%; height: auto;
  /* The stage's own rules give #stage svg a shadow and a fixed height. This is
     a different surface and must not inherit either. */
  box-shadow: none;
}

/* The number sits UNDER the page, not over it. The first cut put it in the
   thumbnail's bottom-left corner to save 13px of band height; on the real
   five-page suite it covered the lemon on page 1 and the honouree's name on
   page 5 — a picker that hides the thing it is a picture of. */
.wv-pagerail-num {
  display: block;
  padding: 0 2px;
  font: 700 9px/13px var(--face);
  font-variant-numeric: tabular-nums;
  text-align: center;
  color: var(--ink-3);
  background: var(--surface);
  border-top: 1px solid var(--line);
}
.wv-pagerail-item.sel .wv-pagerail-num {
  color: var(--surface); background: var(--ink); border-color: var(--ink);
}

/* --- preview modes --------------------------------------------------------
   A segmented control, not three buttons: these are three views of one thing
   and exactly one is always on, which is the shape a segmented control means.
   See previewmode.mjs for why there are three and not the four the refit list
   named. */
.wv-modes {
  display: inline-flex;
  border: 1px solid var(--line-strong);
  border-radius: var(--r);
  overflow: hidden;
  background: var(--surface);
}
.wv-modes button {
  flex: 0 0 auto;
  font: 700 12px/1 var(--face);
  padding: 0 var(--s3); min-height: 28px;
  border: 0; border-left: 1px solid var(--line);
  background: var(--surface); color: var(--ink-3);
  cursor: pointer; white-space: nowrap;
}
.wv-modes button:first-child { border-left: 0; }
.wv-modes button:hover { background: var(--panel); color: var(--ink); }
.wv-modes button.sel { background: var(--ink); color: var(--surface); }

.wv-mode-hint { font: var(--t-meta); color: var(--ink-3); white-space: nowrap; }

/* The presentations themselves.
   These have to outrank `#stage svg` in index.html and phone.html, which is an
   id plus an element. `#stage[data-preview=...] svg` adds an attribute
   selector, so it wins without either page needing !important or a copy of
   these rules. */
#stage[data-preview="phone"] {
  /* A guest's screen, not a scaled-down card: the artwork fills 390px the way
     it fills their browser, and the stage keeps its own padding around it. */
  align-content: start;
}
#stage[data-preview="phone"] svg {
  width: min(390px, 100%); height: auto;
  max-height: none; max-width: 100%;
  border-radius: 0;
}
#stage[data-preview="print"] svg {
  /* `toSvg` emits width="5in" height="7in" on the root, so the browser already
     knows the physical size — the stage only has to stop overriding it. */
  width: auto; height: auto;
  max-width: 100%; max-height: 100%;
}

/* --- motion ---------------------------------------------------------------
   One transition duration for the whole product, and none of it if the reader
   asked for none. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

/* ---- print: the buyer editor's Save-as-PDF prints every page (T-509) ------
 * The stage shows one page; the hidden #wv-print view (built on beforeprint by
 * buyer-app.mjs) holds them all. Scoped to `body.wv-has-print` so show.html and
 * the other surfaces that share this stylesheet keep printing normally. Each
 * SVG carries its own physical width/height in inches, so it prints actual
 * size, one card per sheet. */
#wv-print { display: none; }
@media print {
  @page { margin: 0; }
  body.wv-has-print > *:not(#wv-print) { display: none !important; }
  body.wv-has-print #wv-print { display: block; }
  body.wv-has-print #wv-print .wv-print-page { break-after: page; page-break-after: always; }
  body.wv-has-print #wv-print .wv-print-page:last-child { break-after: auto; page-break-after: auto; }
  body.wv-has-print #wv-print svg { display: block; width: auto; height: auto; max-width: 100%; }
}
