/* Shared base CSS for every customer-facing public page - the
 * invoice, the quote, the portal, the lead form, the card page and
 * the legal pages.
 *
 * EXTRACTED FROM web/templates/_public_page_style.html by
 * docs/archive/nav-performance-spec.md Stage 1. Byte-for-byte the same rules,
 * with one exception: --accent carried the tenant's brand colour and
 * a shared cached file cannot carry a per-tenant value. The default
 * below is overridden in the document by _public_page_brand.html, so
 * white-labelling still works and every other byte is now cacheable.
 *
 * These pages follow the DEVICE via prefers-color-scheme: a surface
 * with no settings of its own has no other way to honour a preference.
 */
/* d-adoption Phase 2: the public surfaces on the A token set.
   These pages carry their own :root because they are standalone
   documents a client opens from a text - they never load base.html -
   so the app's tokens cannot reach them and the values have to be
   restated here. Restated, not re-invented: every one is the same
   value the app ships, so a client's invoice and the operator's
   invoice are the same object in two places.

   THE LADDER APPLIES HERE TOO. --bg is the ground and --surface is the
   panel; the pages that used to draw white boxes on a white page now
   have a tone to sit on, which is what made them read as one flat
   sheet of paper before.

   DARK IS NEW, and it is a judgment call worth naming: these pages had
   no dark theme at all, so a client opening an invoice at night got a
   full-screen white flash. There is no theme switcher on a public page
   and there should not be - the client never chose Amos - so it
   follows the DEVICE via prefers-color-scheme. That is the only way a
   surface with no settings of its own can honour a preference.

   --accent stays the tenant's own brand colour. It is the one value
   here that is deliberately not ours. */
:root {
  --accent: #7A00D4;
  /* The TEXT grade of that same purple (audit8-contrast-batch-spec.md).
     --accent is a FILL: as text it measures 4.45 on the ground and
     3.67 on a panel, under AA on both. This is the identical hue at
     the grade that reads, and it is the value the app's own palette
     has carried as --brand-text all along.

     It is deliberately NOT used on pages that adopt a tenant's brand
     colour - there --accent is the tenant's own value and no fixed
     text grade can follow it. That needs a real answer (derive it, or
     constrain what a tenant may pick) and it is not this batch's. */
  --accent-text: #7A00D4;
  --bg: #F8F6FB;
  --surface: #FFFFFF;
  --surface-raised: #F2EEF8;
  --border: #E4DDEE;
  --card-edge: transparent;
  --text: #12101A;
  --text-secondary: #4E4759;
  /* docs/archive/readability-sweep-spec.md: the same step the app promoted, in
     the customer's stylesheet. A homeowner reading an invoice on a phone
     in daylight is the person with the least reason to squint. 9.47:1 on
     white. */
  --text-secondary-strong: #45454F;
  /* The ink BUTTON, which is not the same thing as the ink COLOUR.
     These pages used background: var(--text) for their primary action,
     which was fine while there was only a light theme and became
     white-on-white the moment dark existed - the fill-vs-text lesson
     the app already records for its brand and danger steps. */
  --ink-fill: #101218;
  --on-ink: #FFFFFF;
  --text-tertiary: #5C5568;
  --success: #096349;
  --danger: #AB2034;
  --danger-bg: #FFE3E7;
  --warning: #7B5000;
  --radius-sm: 4px;
  --radius-md: 6px;
  --radius-lg: 10px;
  /* docs/archive/type-match-and-detail-pages-spec.md Part 1: the same scale as
     the app's, so a customer's invoice reads in the same type as the
     invoice the owner sent it from. Sizes and leading measured off
     ChatGPT's staging branch; see app.css's note for why the weights
     are written as the weight that draws. */
  --text-micro: 0.6875rem;     /* 11 */
  --text-meta: 0.8125rem;      /* 13 */
  --text-body: 0.9375rem;      /* 15 */
  --text-heading: 1.0625rem;   /* 17 */
  --text-title: 1.375rem;      /* 22 */
  --text-display: 1.625rem;    /* 26 */
  --leading-body: 1.46;
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg: #0B0810;
    --surface: #16111D;
    --surface-raised: #211829;
    --border: #332640;
    --text: #F4F1F8;
    --text-secondary: #B5AAC4;
    --text-secondary-strong: #BEBEC9;   /* 9.42:1 on --surface */
    --ink-fill: #F3F4F8;
    --on-ink: #000000;
    --text-tertiary: #A198B0;
    --success: #3DD9A4;
    --danger: #FF8A99;
    --danger-bg: #2C0F16;
    --warning: #FFC061;
  }
}

* { box-sizing: border-box; }
body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: 'Inter', -apple-system, "Segoe UI", Roboto, sans-serif;
  font-size: var(--text-body);
  line-height: var(--leading-body);
}

/* The public panel. Every one of these pages was drawing its own
   white box with its own radius and its own border; this is that box,
   once, on the ladder. */
.card {
  background: var(--surface);
  border: 1px solid var(--card-edge);
  border-radius: var(--radius-lg);
  padding: 18px 16px;
  margin-bottom: 16px;
}

.wordmark { display: flex; align-items: center; justify-content: center; gap: 10px; margin: 0 0 22px; }
.wordmark-initial {
  width: 38px; height: 38px; border-radius: 50%; background: var(--accent); color: #fff;
  display: flex; align-items: center; justify-content: center; font-weight: 700; font-size: var(--text-heading); flex-shrink: 0;
}
.wordmark-name { font-weight: 700; font-size: var(--text-heading); color: var(--text); line-height: 1.2; }
.powered-by { text-align: center; font-size: var(--text-meta); color: var(--text-secondary); margin-top: 8px; }
.powered-by a { color: var(--text-secondary); text-decoration: underline; }

/* Fine-print links take the SAME neutral underlined role the footer
   above already uses (visual audit F04). They were falling through to
   the browser default #0000EE, which on the dark public ground measures
   1.84:1 - unreadable exactly where a prospect is being asked to agree
   to terms. --text-secondary is 5.60:1 on the dark panel and 7.47:1 on
   white, and the underline carries the affordance rather than the hue. */
.fine-print a {
  color: var(--text-secondary);
  text-decoration: underline;
  text-underline-offset: 3px;
}

/* "Back to app" bar, shown only when an operator is previewing one of
   these pages (?preview=1). Customers never receive it - the partial
   renders nothing without the flag, so there is no markup to leak. */
.preview-bar {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 10px 14px;
  margin: -28px -18px 18px;
  background: var(--surface-raised);
  border-bottom: 1px solid var(--border);
  color: var(--text);
  text-decoration: none;
  font-size: var(--text-meta);
  font-weight: 600;
}
.preview-bar svg { width: 18px; height: 18px; flex: none; }
.preview-bar em {
  margin-left: auto;
  font-style: normal;
  font-size: var(--text-micro);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-secondary);
}


/* pwa-checkout-spec.md - the fallback that cannot fail quietly.

   Only ever added by checkout-bridge.js, and only when the standalone
   shell has swallowed BOTH the redirect and the scripted navigation.
   It has to look like the thing it replaces (the pay button) rather
   than like fine print, because at that moment it is the only way
   through. */
.checkout-manual {
  display: block;
  margin-top: 12px;
  padding: 16px;
  border-radius: 10px;
  background: var(--ink-fill);
  color: var(--on-ink);
  text-align: center;
  font-weight: 700;
  font-size: var(--text-input);
  text-decoration: none;
}

/* The thumbnail grid on a customer-facing page - the public invoice
   and the public quote. It used to live in _photo_lightbox.html's own
   <style>, which is where the lightbox was inlined; that partial is
   shared with the app now and carries only the lightbox, so the grid
   these two pages draw belongs with the rest of their stylesheet.
   Byte-for-byte the rules they already had. */
.photo-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(80px, 1fr));
  gap: 8px;
  margin-top: 8px;
}

.photo-grid img {
  width: 100%;
  aspect-ratio: 1;
  object-fit: cover;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  cursor: pointer;
  display: block;
}

/* ===== Buttons v2 on the customer pages ============================
   docs/archive/buttons-v2-spec.md, "all of it, owner + crew + customer pages".

   These rules used to live in each page's own <style> - portal.html
   had one .btn, invoice_public a .btn-pay, quote_public a .btn-approve
   and a bordered .btn-decline - which is four answers to one question
   and exactly how the lightbox drifted. One system here, and the pages
   keep only what is genuinely theirs.

   The PRIMARY's two colours are solved per tenant and arrive as
   --btn-primary-fill / --btn-primary-ink from _public_page_brand.html
   (brand_color.derive_button_fill): the tenant's own hue at a grade
   that steps >= 1.35:1 off the panel and carries a label at >= 4.5:1.
   No fixed pair can follow an arbitrary brand hex, so it is derived
   rather than declared.

   The SECONDARY does not follow the brand - it is the neutral tonal
   block, the same two values the app uses, solved in
   docs/archive/buttons-v2/solve.py:

   Palette 2026 repaints both of these sapphire, and the ink with them:

     light  #D9C8F1, ink #4A1580 | step 1.36 off a white panel
     dark   #452756, ink #EBDCFA | step 1.38 off #12141C
   ================================================================== */
:root {
  --btn-secondary-fill: #D9C8F1;
  --btn-secondary-ink: #4A1580;
}

@media (prefers-color-scheme: dark) {
  :root {
    --btn-secondary-fill: #452756;
    --btn-secondary-ink: #EBDCFA;
  }
}

.btn,
.btn-pay,
.btn-approve,
.btn-decline {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  padding: 0 16px;
  border: none;
  border-radius: 10px;
  font-family: inherit;
  font-size: 0.9375rem;
  font-weight: 600;
  letter-spacing: 0;
  text-decoration: none;
  text-align: center;
  cursor: pointer;
  /* The default level is the block, not the call to action: a portal
     with four brand-filled buttons has no primary at all. */
  background: var(--btn-secondary-fill);
  color: var(--btn-secondary-ink);
}

/* ONE per page (the spec's own rule). Pay and Approve are the page's
   single reason to exist; everything else on it is secondary. */
.btn-primary,
.btn-pay,
.btn-approve {
  background: var(--btn-primary-fill);
  color: var(--btn-primary-ink);
  font-weight: 700;
}

.btn-decline {
  background: var(--btn-secondary-fill);
  color: var(--btn-secondary-ink);
}

.btn-small { min-height: 36px; padding: 0 14px; }
.btn-full { width: 100%; }

.btn:active,
.btn-pay:active,
.btn-approve:active,
.btn-decline:active { transform: scale(0.97); }

/* Keyboard users get the ring; the colour is state, as in the app. */
.btn:focus-visible,
.btn-pay:focus-visible,
.btn-approve:focus-visible,
.btn-decline:focus-visible {
  outline: 2px solid var(--accent-text);
  outline-offset: 2px;
}
