/* invoice-generator/styles/tool.css
   Skeleton styles for the free invoice generator tool.
   Polish lands in later tasks. Keep it functional and clean.

   Palette: we re-use the main site's variables (see
   /resources/styles/custom-colors.css) so the tool always tracks brand
   colors and inherits dark-mode overrides automatically. The --invoice-*
   and --tool-* names below are local aliases that the rest of the file
   reads from; templates only need to redefine these aliases. */

@import url('../../resources/styles/custom-colors.css');
@import url('./template-page.css');

:root {
  /* Invoice surface defaults map to main-site variables. */
  --invoice-bg: var(--white);
  --invoice-text: var(--dark-gray);
  --invoice-accent: var(--primary-blue);
  --invoice-header-bg: var(--dark-gray);
  --invoice-header-text: var(--white);
  --invoice-border: var(--gray-border);
  --invoice-muted: var(--gray-placeholder);

  /* Heading ink for the template variants. Deliberately darker than
     --invoice-text and independent of the site palette: this paints the
     customer's invoice, which should not restyle when the brand does. */
  --invoice-heading-ink: #1a1a1a;

  /* Tool chrome (outside the invoice surface). Kept on the same palette
     so template switching does not visually break the toolbar. */
  --tool-bg: var(--light-page-bg);
  --tool-surface: var(--white);
  --tool-text: var(--dark-gray);
  --tool-muted: var(--gray-placeholder);
  --tool-border: var(--gray-input-border);
  --tool-primary: var(--primary-blue);
  --tool-primary-text: var(--white);
  --tool-secondary: var(--gray-bg-light);
  --tool-secondary-text: var(--dark-gray);
  --tool-danger: var(--red-600);
}

/* ============================================================
 * TEMPLATE STYLES
 * Each [data-template="X"] block sets the color palette via
 * variable overrides, then adds template-specific structural
 * rules (font swaps, banners, decorations) below it. The five
 * designs mirror the Argo Books desktop app's invoice templates
 * so the brand feels consistent across the web tool and the app.
 * ============================================================ */

/* --- Classic: clean default. Uses :root values; no overrides. --- */
[data-template="classic"] {
  /* defaults above */
}

/* --- Modern: slate dark left rail, light gray header band,
 *     dark navy table header. --- */
[data-template="modern"] {
  --invoice-bg: var(--white);
  --invoice-text: var(--gray-900);
  --invoice-accent: var(--sky-500);
  --invoice-header-bg: var(--gray-900);
  --invoice-header-text: var(--white);
  --invoice-border: var(--gray-200);
  --invoice-muted: var(--gray-500);
}

[data-template="modern"] .invoice {
  font-family: "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  padding: 0;
  border-left: 10px solid var(--gray-900);
  overflow: hidden;
}

[data-template="modern"] .invoice-header {
  background: var(--gray-100);
  padding: 28px 32px;
  margin: 0 0 24px;
  border-bottom: none;
  align-items: center;
}

[data-template="modern"] input.editable-business-title {
  font-size: var(--text-2xl);
  color: var(--gray-900);
  line-height: 1.4;
}

[data-template="modern"] input.editable-document-title {
  color: var(--gray-900);
  font-weight: 800;
  font-size: var(--text-3xl);
  letter-spacing: -0.01em;
  text-transform: uppercase;
}

[data-template="modern"] .invoice-number-field {
  color: var(--gray-500);
  font-size: var(--text-xs);
}

[data-template="modern"] .invoice-meta {
  padding: 0 32px;
  margin-bottom: 28px;
}

[data-template="modern"] .meta-info {
  background: var(--gray-100);
  padding: 16px 18px;
  border-radius: var(--radius-sm);
}

[data-template="modern"] .invoice-items {
  padding: 0 32px;
  margin-bottom: 24px;
}

[data-template="modern"] .line-items thead th {
  background: var(--gray-900);
  color: var(--white);
  padding: 14px 16px;
  font-size: var(--text-2xs);
  letter-spacing: 0.08em;
}

[data-template="modern"] .invoice-footer {
  padding: 0 32px 32px;
}

[data-template="modern"] .totals-total {
  border-top: 2px solid var(--gray-900);
}

[data-template="modern"] .totals-total .editable-totals-label,
[data-template="modern"] .totals-total .totals-value {
  color: var(--gray-900);
  font-size: var(--text-lg);
  font-weight: 800;
}

/* --- Formal: Georgia serif, navy header band, navy total band.
 *     Mirrors the desktop app's Classic style. --- */
[data-template="formal"] {
  --invoice-bg: var(--white);
  --invoice-text: #1a1a1a;
  --invoice-accent: var(--navy-1e3a5f);
  --invoice-header-bg: var(--navy-1e3a5f);
  --invoice-header-text: var(--white);
  --invoice-border: #c7ccd1;
  --invoice-muted: var(--gray-500);
}

[data-template="formal"] .invoice {
  font-family: Georgia, Cambria, "Times New Roman", Times, serif;
  padding: 0;
}

[data-template="formal"] .invoice-header {
  padding: 32px 32px 12px;
  border-bottom: 2px solid var(--navy-1e3a5f);
  margin-bottom: 0;
}

[data-template="formal"] input.editable-business-title {
  font-family: Georgia, serif;
  font-size: var(--text-2xl);
  font-weight: 700;
  color: var(--invoice-heading-ink);
}

[data-template="formal"] input.editable-document-title {
  font-family: Georgia, serif;
  font-size: var(--text-5xl);
  font-weight: 700;
  color: var(--navy-1e3a5f);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  max-width: none;
}

[data-template="formal"] .invoice-number-field,
[data-template="formal"] .invoice-number-field input,
[data-template="formal"] .invoice-number-prefix {
  font-family: Georgia, serif;
  color: var(--invoice-heading-ink);
  font-weight: 700;
  font-size: var(--text-sm);
}

[data-template="formal"] .invoice-meta {
  background: var(--gray-100);
  padding: 22px 32px;
  margin: 0 0 24px;
  border-bottom: 1px solid var(--gray-200);
}

[data-template="formal"] .invoice-items {
  padding: 0 32px;
  margin-bottom: 16px;
}

[data-template="formal"] .line-items thead th {
  background: var(--navy-1e3a5f);
  color: var(--white);
  padding: 14px 16px;
  font-family: Georgia, serif;
  font-size: var(--text-2xs);
  letter-spacing: 0.06em;
}

[data-template="formal"] .invoice-footer {
  padding: 0 32px 0;
  gap: 24px;
}

[data-template="formal"] .totals-total {
  background: var(--navy-1e3a5f);
  padding: 14px 16px;
  margin: 8px 0 0;
  border-top: none;
  border-radius: var(--radius-xs);
}

[data-template="formal"] .totals-total .editable-totals-label,
[data-template="formal"] .totals-total .totals-value {
  color: var(--white);
  font-size: var(--text-lg);
  font-weight: 700;
  font-family: Georgia, serif;
  background: transparent;
}

[data-template="formal"] .totals-total input.editable-totals-label:hover,
[data-template="formal"] .totals-total input.editable-totals-label:focus {
  border-color: var(--white-alpha-50);
  background: var(--white-alpha-10);
  color: var(--white);
}

/* Navy bottom band, matching the desktop Classic template's "Thank you for
 * your business!" footer strip. Implemented as a thick bottom border so it
 * follows the rounded corners of the surrounding invoice card. */
[data-template="formal"] .invoice {
  border-bottom: 32px solid var(--navy-1e3a5f);
}

/* --- Elegant: Georgia serif, multicolor gradient ribbon at the top,
 *     indigo accent line beside Bill To, and a large indigo Total Due. --- */
[data-template="elegant"] {
  --invoice-bg: var(--white);
  --invoice-text: #1f2937;
  --invoice-accent: var(--indigo-500);
  --invoice-header-bg: transparent;
  --invoice-header-text: #1f2937;
  --invoice-border: var(--gray-border);
  --invoice-muted: var(--gray-500);
}

[data-template="elegant"] .invoice {
  font-family: Georgia, Cambria, "Times New Roman", Times, serif;
  padding: 0;
  position: relative;
  overflow: hidden;
}

[data-template="elegant"] .invoice::before {
  content: "";
  display: block;
  height: 6px;
  background: linear-gradient(90deg,
    var(--purple-500) 0%,
    var(--indigo-500) 30%,
    var(--sky-400) 65%,
    var(--emerald-400) 100%);
}

[data-template="elegant"] .invoice-header {
  padding: 28px 32px 16px;
  border-bottom: none;
  margin-bottom: 12px;
}

[data-template="elegant"] input.editable-business-title {
  font-family: Georgia, serif;
  font-size: var(--text-2xl);
  font-weight: 700;
  color: var(--invoice-heading-ink);
}

[data-template="elegant"] input.editable-document-title {
  font-size: var(--text-2xs);
  letter-spacing: 0.2em;
  color: var(--indigo-500);
  text-transform: uppercase;
  font-weight: 700;
  font-family: "Segoe UI", Arial, sans-serif;
}

[data-template="elegant"] .invoice-number-field,
[data-template="elegant"] .invoice-number-field input,
[data-template="elegant"] .invoice-number-prefix {
  font-family: Georgia, serif;
  font-size: var(--text-2xl);
  font-weight: 700;
  color: var(--invoice-heading-ink);
}

[data-template="elegant"] .invoice-meta {
  padding: 0 32px;
  margin-bottom: 28px;
}

[data-template="elegant"] .meta-billto {
  border-left: 3px solid var(--indigo-500);
  padding-left: 14px;
}

[data-template="elegant"] .invoice-items {
  padding: 0 32px;
  margin-bottom: 24px;
}

[data-template="elegant"] .line-items thead th {
  background: transparent;
  color: var(--gray-500);
  border-top: 1px solid var(--gray-300);
  border-bottom: 1px solid var(--gray-300);
  font-size: var(--text-2xs);
  letter-spacing: 0.12em;
  font-family: "Segoe UI", Arial, sans-serif;
  padding: 12px;
}

[data-template="elegant"] .line-items thead th .editable-th {
  color: var(--gray-500);
}

[data-template="elegant"] .invoice-footer {
  padding: 0 32px 28px;
}

[data-template="elegant"] .totals-total {
  border-top: none;
  padding-top: 12px;
}

[data-template="elegant"] .totals-total .editable-totals-label {
  color: var(--gray-500);
  font-size: var(--text-2xs);
  letter-spacing: 0.12em;
  font-weight: 700;
  text-transform: uppercase;
  font-family: "Segoe UI", Arial, sans-serif;
}

[data-template="elegant"] .totals-total .totals-value {
  color: var(--indigo-500);
  font-family: Georgia, serif;
  font-size: var(--text-2xl);
  font-weight: 700;
}

/* --- Ribbon: watercolor wave decoration on the left side, Open Sans body,
 *     navy uppercase headings. The wave SVG is rendered as a real DOM element
 *     in _fragment.php; here we just position and reveal it. --- */
[data-template="ribbon"] {
  --invoice-bg: var(--white);
  --invoice-text: #2c3e50;
  --invoice-accent: var(--navy-1a365d);
  --invoice-header-bg: transparent;
  --invoice-header-text: var(--navy-1a365d);
  --invoice-border: #e0e0e0;
  --invoice-muted: var(--gray-500);
}

[data-template="ribbon"] .invoice {
  font-family: "Open Sans", "Segoe UI", Arial, sans-serif;
  padding: 0;
  position: relative;
  overflow: hidden;
  min-height: 720px;
}

[data-template="ribbon"] .invoice-ribbon-deco {
  display: block;
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 220px;
  pointer-events: none;
  z-index: 0;
}

[data-template="ribbon"] .invoice-ribbon-deco svg {
  display: block;
  width: 100%;
  height: 100%;
}

[data-template="ribbon"] .invoice > section {
  position: relative;
  z-index: 1;
}

[data-template="ribbon"] .invoice-header,
[data-template="ribbon"] .invoice-meta,
[data-template="ribbon"] .invoice-items,
[data-template="ribbon"] .invoice-footer {
  padding-left: 130px;
  padding-right: 32px;
  position: relative;
  z-index: 1;
}

[data-template="ribbon"] .invoice-footer {
  padding-bottom: 40px;
}

[data-template="ribbon"] .invoice-header {
  padding-top: 32px;
  padding-bottom: 16px;
  border-bottom: none;
  margin-bottom: 16px;
  flex-direction: column;
  align-items: stretch;
  gap: 14px;
}

[data-template="ribbon"] .invoice-header-left,
[data-template="ribbon"] .invoice-header-right {
  align-items: flex-start;
  text-align: left;
}

[data-template="ribbon"] .invoice-header-right {
  order: -1;
  flex-direction: row;
  align-items: baseline;
  gap: 18px;
}

[data-template="ribbon"] input.editable-document-title {
  font-family: "Open Sans", "Segoe UI", Arial, sans-serif;
  font-size: var(--text-6xl);
  font-weight: 800;
  letter-spacing: 0.04em;
  color: var(--navy-1a365d);
  text-transform: uppercase;
  text-align: left;
  max-width: none;
  width: auto;
}

[data-template="ribbon"] input.editable-business-title {
  font-size: var(--text-md);
  font-weight: 700;
  color: var(--navy-1a365d);
}

[data-template="ribbon"] .invoice-number-field,
[data-template="ribbon"] .invoice-number-field input,
[data-template="ribbon"] .invoice-number-prefix {
  color: var(--navy-1a365d);
  font-size: var(--text-lg);
  font-weight: 700;
}

[data-template="ribbon"] input.editable-label {
  color: var(--navy-1a365d);
  font-size: var(--text-2xs);
  letter-spacing: 0.08em;
  font-weight: 700;
}

[data-template="ribbon"] .line-items thead {
  border-top: 2px solid var(--navy-1a365d);
  border-bottom: 1px solid var(--sky-400);
}

[data-template="ribbon"] .line-items thead th {
  background: transparent;
  color: var(--navy-1a365d);
  font-size: var(--text-2xs);
  letter-spacing: 0.06em;
  font-weight: 700;
  padding: 14px 12px;
}

[data-template="ribbon"] .line-items thead th .editable-th {
  color: var(--navy-1a365d);
}

[data-template="ribbon"] .totals-total {
  border-top: 2px solid var(--navy-1a365d);
  padding-top: 12px;
  margin-top: 8px;
}

[data-template="ribbon"] .totals-total .editable-totals-label,
[data-template="ribbon"] .totals-total .totals-value {
  color: var(--navy-1a365d);
  font-size: var(--text-lg);
  font-weight: 800;
}

/* Hide the ribbon decoration for every template that is not "ribbon"
 * so the SVG element in _fragment.php stays invisible elsewhere. */
.invoice-ribbon-deco {
  display: none;
}

* {
  box-sizing: border-box;
}

html, body {
  margin: 0;
  padding: 0;
}

body {
  font-family: Arial, Helvetica, "Segoe UI", sans-serif;
  font-size: var(--text-sm);
  line-height: 1.45;
  color: var(--tool-text);
  background: var(--tool-bg);
}

/* ---------- App shell ---------- */

.invoice-app {
  max-width: 1100px;
  margin: 0 auto;
  padding: 24px 20px 96px;
}

/* Niche pages embed the generator inside an <article class="niche-page">.
   Constrain that wrapper to the same 1100px so the surrounding intro,
   FAQs, and related-links sit at the same width as the embedded tool. */
.niche-page {
  max-width: 1100px;
  margin: 0 auto;
  padding: 24px 20px 96px;
}

.niche-page .invoice-app {
  padding-left: 0;
  padding-right: 0;
}

/* ---------- Niche page: sample line items table ---------- */
/* Renders the data file's `sample_line_items` array as a clean
   four-column table (Item | Rate | Qty | Amount). The Item cell uses
   <th scope="row"> so screen readers announce it as the row header,
   and it visually doubles as a bold label for scanability. */

.niche-samples-table {
  width: 100%;
  border-collapse: collapse;
  margin-top: 12px;
  font-size: var(--text-sm);
}

.niche-samples-table th,
.niche-samples-table td {
  padding: 10px 12px;
  text-align: left;
  border-bottom: 1px solid var(--gray-border);
  color: var(--dark-gray);
}

.niche-samples-table thead th {
  font-size: var(--text-2xs);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--gray-placeholder);
  font-weight: 600;
  border-bottom-color: var(--dark-gray);
  padding-bottom: 8px;
}

.niche-samples-table tbody th {
  font-weight: 600;
  color: var(--dark-gray);
}

.niche-samples-table .num {
  text-align: right;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.niche-samples-table .niche-sample-amount {
  font-weight: 600;
}

.niche-samples-table tbody tr:last-child th,
.niche-samples-table tbody tr:last-child td {
  border-bottom: none;
}

@media (max-width: 540px) {
  .niche-samples-table th,
  .niche-samples-table td {
    padding: 8px 6px;
    font-size: var(--text-xs);
  }
  .niche-samples-table thead th {
    font-size: var(--text-2xs);
  }
}

/* Match the main site's .link color for every anchor on a niche page,
   including author-embedded <a> tags in intro/terms/tax copy, related
   guides, related templates, and the CTA. Tool pages are intentionally
   isolated from /resources/styles/link.css, so we restate the color here
   using the same brand variable the main site reads from. */
/* Prose links only. Exclude .btn so anchors styled as buttons (e.g. the
   post-download modal CTA) keep their button text color instead of being
   recolored to var(--primary-blue), which matches the button background
   and renders the label invisible. */
.niche-page a:not(.btn) {
  color: var(--primary-blue);
}

.niche-page a:not(.btn):hover {
  text-decoration: underline;
}

/* ---------- Article pages ---------- */
/* Long-form informational articles at root-level URLs (e.g.
   /how-to-invoice-clients/). Shares the .faq-* and .page-banner
   components with niche pages; only article-specific layout lives here. */

.article-page {
  max-width: 760px;
  margin: 0 auto;
  padding: 32px 20px 80px;
  font-size: var(--text-sm);
  line-height: 1.65;
  color: var(--dark-gray);
}

/* Headings render pure black for stronger hierarchy against the dark-gray body. */
.article-head h1,
.article-section h2,
.article-section h3,
.article-faqs h2,
.article-related-niches h2,
.article-related-articles h2,
.faq-question h3 {
  color: var(--black);
}

/* Every heading except the article title (and the interactive FAQ questions)
   is horizontally centered. */
.article-section h2,
.article-section h3,
.article-faqs h2,
.article-related-niches h2,
.article-related-articles h2 {
  text-align: center;
}

/* Extra breathing room above the closing "Try it free" banner. Scoped to
   articles so the invoice-template pages' top banner isn't pushed down. */
.article-page .page-banner {
  margin-top: 48px;
}

.article-breadcrumb {
  margin: 0 0 24px;
  font-size: var(--text-xs);
}

.article-breadcrumb-link {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  color: var(--gray-500);
  text-decoration: none;
  font-weight: 500;
  transition: color 0.2s ease;
}

.article-breadcrumb-link:hover {
  color: var(--primary-blue);
}

.article-head h1 {
  font-size: var(--text-5xl);
  line-height: 1.2;
  margin: 0 0 8px;
}

.article-meta {
  color: var(--gray-500);
  font-size: var(--text-xs);
  margin: 0 0 14px;
}

.article-byline {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 0 0 28px;
}

.article-byline-avatar {
  width: 44px;
  height: 44px;
  border-radius: var(--radius-round);
  object-fit: cover;
  flex-shrink: 0;
}

.article-byline-text {
  font-size: var(--text-xs);
  line-height: 1.35;
  color: var(--gray-500);
}

.article-byline-name {
  font-weight: 600;
  color: inherit;
  text-decoration: none;
}

.article-byline-name:hover {
  text-decoration: underline;
}

.article-byline-role {
  display: block;
}

.article-meta .article-updated + .article-reading-time::before {
  content: ' \00b7 ';
  margin: 0 6px;
}

/* Optional headline statistic (data field `hero_stat`), for articles that
   exist to answer one numeric question. Sits between the byline and the
   intro. Deliberately loud: this is the answer the reader came for. */
.article-hero-stat {
  margin: 0 0 28px;
  padding: 22px 26px;
  border: 1px solid var(--gray-border);
  border-left: 4px solid var(--primary-blue);
  border-radius: var(--radius-sm);
  background: var(--gray-50);
}

.article-hero-stat-label {
  margin: 0 0 6px;
  font-size: var(--text-2xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  color: var(--gray-500);
}

.article-hero-stat-value {
  margin: 0;
  font-size: var(--text-5xl);
  line-height: 1.1;
  font-weight: 700;
  letter-spacing: -0.02em;
  color: var(--black);
}

.article-hero-stat-unit {
  display: block;
  margin-top: 4px;
  font-size: var(--text-sm);
  font-weight: 600;
  letter-spacing: 0;
  color: var(--gray-600);
}

.article-hero-stat-footnote {
  margin: 12px 0 0;
  font-size: var(--text-xs);
  line-height: 1.5;
  color: var(--gray-600);
}

.article-intro p:first-child {
  font-size: var(--text-md);
  line-height: 1.55;
}

/* Two-column guide layout. Below the breakpoint .article-layout is a plain
   block, so the contents list stays inline between the intro and the first
   section exactly as before. Above it, the list moves to a sticky right rail.
   Both columns are grid items in a single row, so the rail's grid area is as
   tall as the article, which is what gives position:sticky room to travel. */
/* Three columns so the body stays centred in the page rather than being
   pushed left to make room. The left column is empty and exists only to
   balance the rail on the right. */
@media (min-width: 1280px) {
  .article-page {
    max-width: 1440px;
  }

  /* The body column is fluid rather than fixed, so it widens with the window
     instead of leaving the extra space in the empty spacer column. Two explicit rows so the rail can span both with grid-row: 1 / -1. With
     only implicit rows, -1 resolves to the end of the explicit grid, which
     would leave the rail one row tall and give sticky nowhere to travel. */
  .article-layout {
    display: grid;
    grid-template-columns: 220px minmax(0, 1fr) 220px;
    grid-template-rows: auto 1fr;
    column-gap: 40px;
    justify-content: center;
  }

  /* Header and body share the middle column, so they align structurally and
     need no width arithmetic to keep them in step. */
  .article-intro-block {
    grid-column: 2;
    grid-row: 1;
    min-width: 0;
  }

  .article-main {
    grid-column: 2;
    grid-row: 2;
    min-width: 0;
  }

  .article-toc-rail {
    grid-column: 3;
    grid-row: 1 / -1;
    /* Drop past the breadcrumb so the rail starts level with the headline
       rather than with the “All guides” link. 14px link at 1.45 line-height
       plus its 24px bottom margin. */
    margin-top: 44px;
    /* No height here on purpose. A grid item stretches to the row by default,
       which is already the full column height the sticky child needs. Setting
       height:100% instead makes the item depend on the row while the row is
       still being sized from the item, and browsers resolve that circularity
       differently, which showed up as the rail juddering in Edge. */
  }

  .article-layout .article-toc {
    position: sticky;
    top: 56px;
    margin: 0;
    padding: 0 0 0 18px;
    border: 0;
    border-left: 2px solid var(--gray-200);
    border-radius: 0;
    background: none;
    /* Deliberately no max-height and no inner scroll container. A sticky box
       that scrolls internally resizes as its scrollbar appears and disappears,
       and at close to viewport height that flips on every scroll frame, which
       reads as the rail vibrating. The list below is sized to fit instead. */
  }

  .article-layout .article-toc .article-toc-title {
    margin-bottom: 14px;
  }

  .article-layout .article-toc .article-toc-list {
    padding-left: 0;
    list-style: none;
    counter-reset: toc;
  }

  .article-layout .article-toc .article-toc-list li {
    counter-increment: toc;
    margin: 0;
  }

  .article-layout .article-toc .article-toc-list a {
    display: block;
    padding: 5px 0;
    color: var(--gray-700);
    font-size: var(--text-2xs);
    line-height: 1.45;
  }

  .article-layout .article-toc .article-toc-list a::before {
    content: counter(toc);
    display: inline-block;
    width: 18px;
    color: var(--gray-400);
    font-variant-numeric: tabular-nums;
  }

  .article-layout .article-toc .article-toc-list a:hover {
    color: var(--primary-blue);
    text-decoration: none;
  }

  /* The section currently on screen. The spine segment beside it is filled in
     rather than adding a background, so the rail stays a rule rather than
     becoming a box again. Drawn as a positioned pseudo-element stretched top to
     bottom: a box-shadow with negative spread scales with the element, so it
     vanished on one-line entries and stubbed on two-line ones. */
  .article-layout .article-toc .article-toc-list a {
    position: relative;
  }

  .article-layout .article-toc .article-toc-list a.is-active {
    color: var(--primary-blue);
    font-weight: 600;
  }

  .article-layout .article-toc .article-toc-list a.is-active::after {
    content: "";
    position: absolute;
    /* 18px of nav padding plus its 2px rule. */
    left: -20px;
    top: 0;
    bottom: 0;
    width: 2px;
    background: var(--primary-blue);
  }

  .article-layout .article-toc .article-toc-list a.is-active::before {
    color: var(--primary-blue);
  }
}

.article-toc {
  margin: 28px 0;
  padding: 18px 22px;
  border: 1px solid var(--gray-border);
  border-radius: var(--radius-sm);
  background: var(--white);
}

.article-toc-title {
  margin: 0 0 10px;
  font-size: var(--text-2xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--gray-500);
}

.article-toc-list {
  margin: 0;
  padding-left: 20px;
}

.article-toc-list li {
  margin: 6px 0;
}

.article-toc-list a {
  color: var(--primary-blue);
  text-decoration: none;
}

.article-toc-list a:hover {
  text-decoration: underline;
}

.article-section {
  margin-top: 32px;
  /* Breathing room when a TOC link jumps to the heading. */
  scroll-margin-top: 24px;
}

.article-section h2 {
  font-size: var(--text-2xl);
  line-height: 1.3;
  margin: 0 0 12px;
}

.article-section h3 {
  font-size: var(--text-lg);
  line-height: 1.4;
  margin: 24px 0 8px;
}

.article-section ul,
.article-section ol {
  padding-left: 22px;
  margin: 12px 0;
}

.article-section li {
  margin: 6px 0;
}

.article-section table {
  width: 100%;
  border-collapse: collapse;
  margin: 16px 0;
  font-size: var(--text-xs);
}

.article-section th,
.article-section td {
  border: 1px solid var(--gray-border);
  padding: 8px 12px;
  text-align: left;
  vertical-align: top;
}

.article-section thead th {
  background: var(--gray-bg-light);
  font-weight: 600;
}

.article-section tbody tr:nth-child(even) td {
  background: var(--gray-50);
}

/* Reusable substantial SVG illustrations dropped between sections via the
   {{illustration:name}} token. Line color comes from `color` (currentColor);
   accents and soft fills are tagged in the SVG markup. */
.article-illustration {
  margin: 32px 0;
  color: var(--gray-600);
  display: flex;
  justify-content: center;
}

.article-illustration svg {
  width: 100%;
  height: auto;
}

.article-illustration--band svg {
  max-width: 560px;
}

.article-illustration--spot svg {
  max-width: 230px;
}

.article-illustration .ai-accent {
  stroke: var(--primary-blue);
}

.article-illustration .ai-accent-fill {
  fill: var(--primary-blue);
  stroke: none;
}

.article-illustration .ai-soft {
  fill: var(--blue-100);
}

/* In-article images (screenshots, photos) with an optional caption. */
.article-figure {
  margin: 32px 0;
  text-align: center;
}

.article-figure img {
  max-width: 100%;
  height: auto;
  display: block;
  margin: 0 auto;
  border-radius: var(--radius-md);
  border: 1px solid var(--gray-border);
}

.article-figure figcaption {
  margin-top: 10px;
  font-size: var(--text-xs);
  color: var(--gray-500);
}

/* Downloadable asset (e.g. the cash flow forecast template). */
.article-download {
  margin: 24px 0;
  padding: 20px 22px;
  border: 1px solid var(--gray-border);
  border-radius: var(--radius-sm);
  background: var(--gray-50);
  text-align: center;
}

.article-download-btn {
  display: inline-block;
  padding: 12px 24px;
  background: var(--primary-blue);
  color: var(--white);
  font-weight: 600;
  border-radius: var(--radius-sm);
  text-decoration: none;
}

.article-download-btn:hover {
  filter: brightness(0.94);
}

.article-download-note {
  display: block;
  margin-top: 9px;
  font-size: var(--text-2xs);
  color: var(--gray-500);
}

/* Email/quote examples authored as <pre>. Wrap long lines (default <pre> is
   no-wrap, which overflows) while keeping the author's intentional blank lines,
   and render in the body font as a tidy quoted block. */
.article-section pre {
  position: relative;
  white-space: pre-wrap;
  overflow-wrap: break-word;
  word-break: break-word;
  margin: 16px 0;
  padding: 16px;
  background: var(--gray-50);
  border: 1px solid var(--gray-border);
  border-radius: var(--radius-sm);
  font-family: inherit;
  font-size: var(--text-xs);
  line-height: 1.55;
  color: var(--dark-gray);
}

/* Inline code only. The <pre> above inherits the body font on purpose, since it
   renders email examples a reader retypes. */
.article-section :not(pre) > code {
  font-family: var(--font-mono);
  font-size: 0.9em;
  background: var(--gray-100);
  border: 1px solid var(--gray-border);
  border-radius: var(--radius-xs);
  padding: 1px 5px;
  color: var(--dark-gray);
  word-break: break-word;
}

.pre-copy-btn {
  position: absolute;
  top: 8px;
  right: 8px;
  display: inline-flex;
  align-items: center;
  padding: 5px 11px;
  font-family: inherit;
  font-size: var(--text-2xs);
  font-weight: 600;
  line-height: 1.2;
  color: var(--primary-blue);
  background: var(--white);
  border: 1px solid var(--gray-border);
  border-radius: var(--radius-sm);
  cursor: pointer;
}

.pre-copy-btn:hover {
  background: var(--gray-bg-light);
}

.pre-copy-btn.copied {
  color: var(--green-600);
  border-color: var(--green-600);
}

/* Email example card: groups the "Subject:" line and the <pre> body, with the
   copy button (added by JS) overlaying the top-right corner. */
.email-example {
  position: relative;
  margin: 16px 0;
  padding: 16px;
  background: var(--gray-50);
  border: 1px solid var(--gray-border);
  border-radius: var(--radius-sm);
}

.email-example .email-subject {
  margin: 0 0 10px;
  padding: 0 70px 10px 0;
  border-bottom: 1px solid var(--gray-border);
  font-size: var(--text-xs);
  color: var(--dark-gray);
}

/* Inside the card the <pre> is just the wrapping text, not its own box. */
.email-example pre {
  margin: 0;
  padding: 0;
  background: none;
  border: none;
  border-radius: 0;
}

/* In-content tool callout. Subtle: bordered card with an accent stripe.
   Reads as a friendly nudge between sections, not an advertisement. */
.tool-callout {
  margin: 28px 0;
  padding: 18px 22px;
  border: 1px solid var(--gray-border);
  border-left: 4px solid var(--primary-blue);
  background: var(--white);
  display: flex;
  flex-direction: column;
  gap: 8px;
}

@media (min-width: 640px) {
  .tool-callout {
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
    gap: 18px;
  }
}

.tool-callout-text {
  margin: 0;
  font-size: var(--text-sm);
  color: var(--dark-gray);
}

.tool-callout-link {
  display: inline-block;
  font-weight: 600;
  color: var(--primary-blue);
  text-decoration: none;
  white-space: nowrap;
}

.tool-callout-link:hover {
  text-decoration: underline;
}

.article-related-niches,
.article-related-articles {
  margin-top: 40px;
}

.article-faqs h2,
.article-related-niches h2,
.article-related-articles h2 {
  font-size: var(--text-2xl);
  margin: 0 0 12px;
}

.article-related-list {
  list-style: none;
  padding-left: 0;
  margin: 0;
  text-align: center;
}

.article-related-list li {
  margin: 6px 0;
}

.article-related-list a {
  color: var(--primary-blue);
  text-decoration: none;
}

.article-related-list a:hover {
  text-decoration: underline;
}

.article-faqs {
  margin-top: 40px;
}

@media (max-width: 560px) {
  .article-page {
    font-size: var(--text-sm);
    padding: 24px 16px 64px;
  }
  .article-head h1 {
    font-size: var(--text-3xl);
  }
  .article-section h2 {
    font-size: var(--text-xl);
  }
  .article-hero-stat {
    padding: 18px 18px;
  }
  .article-hero-stat-value {
    font-size: var(--text-3xl);
  }
  /* Wide pricing tables scroll inside the article column rather than
     forcing the page body to scroll sideways. */
  .article-section table {
    display: block;
    overflow-x: auto;
    white-space: nowrap;
  }
}

/* ---------- Niche page: collapsible FAQ component ---------- */
/* Visual match for the main-site .faq-item pattern (resources/styles/faq.css).
   The outer section keeps the niche-page rhythm; only the inner
   .faq-grid / .faq-item / .faq-question / .faq-answer markup mirrors
   the main site. JS handler lives inline in niches/niche-page.php. */

.faq-grid {
  max-width: 820px;
  margin: 0 auto;
}

.faq-item {
  border: 1px solid var(--gray-border);
  border-radius: var(--radius-lg);
  margin-bottom: 16px;
  overflow: hidden;
  background: var(--white);
  transition: border-color 0.3s ease, box-shadow 0.3s ease;
}

.faq-item:hover {
  border-color: var(--primary-blue);
}

.faq-item.active {
  border-color: var(--primary-blue);
}

.faq-question {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  padding: 18px 22px;
  cursor: pointer;
  background: transparent;
  border: none;
  text-align: left;
  font: inherit;
  color: inherit;
  transition: background 0.2s ease;
}

.faq-question:hover {
  background: rgba(0, 0, 0, 0.02);
}

.faq-question h3 {
  font-size: var(--text-sm);
  font-weight: 600;
  margin: 0;
  padding-right: 16px;
  color: var(--dark-gray);
}

.faq-icon {
  width: 28px;
  height: 28px;
  border-radius: var(--radius-round);
  background: rgba(0, 0, 0, 0.05);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  color: var(--dark-gray);
  transition: background 0.3s ease, color 0.3s ease;
}

.faq-icon svg {
  transition: transform 0.3s ease;
}

.faq-item.active .faq-icon {
  background: var(--primary-blue);
  color: var(--white);
}

.faq-item.active .faq-icon svg {
  transform: rotate(180deg);
}

.faq-answer {
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.35s ease;
}

.faq-item.active .faq-answer {
  max-height: 600px;
}

.faq-answer-content {
  padding: 0 22px 20px;
  line-height: 1.65;
  color: var(--dark-gray);
}

.faq-answer-content p {
  margin: 0;
}

@media (max-width: 600px) {
  .faq-question {
    padding: 16px 18px;
  }
  .faq-question h3 {
    font-size: var(--text-sm);
  }
  .faq-answer-content {
    padding: 0 18px 16px;
  }
}

/* ---------- Top site header ---------- */
/* Full-width branding strip that sits OUTSIDE the .invoice-app container,
   so the background and bottom border span the entire viewport. The
   .site-header-inner holds the brand + CTA within a centered max-width so
   they line up with the invoice surface below. */
.site-header {
  width: 100%;
  background: var(--tool-surface);
  border-bottom: 1px solid var(--tool-border);
}

.site-header-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  max-width: 1100px;
  margin: 0 auto;
  padding: 14px 20px;
}

.site-brand {
  display: inline-flex;
  align-items: center;
  text-decoration: none;
  color: var(--tool-text);
  flex: 0 0 auto;
}

/* Back-link to the /tools/ hub, in its own row below the header, aligned to
   the content's max-width. */
.tool-breadcrumb {
  max-width: 1100px;
  margin: 0 auto;
  padding: 12px 20px 0;
}

.site-back {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  text-decoration: none;
  color: var(--tool-muted);
  font-size: var(--text-xs);
  font-weight: 500;
  flex: 0 0 auto;
}

.site-back:hover,
.site-back:focus {
  color: var(--tool-primary);
}

.site-back-arrow {
  font-size: var(--text-sm);
  line-height: 1;
}

.site-brand img {
  display: block;
  height: 28px;
  width: auto;
  max-width: 180px;
}

/* Editorial section nav on guide pages. Content links only (no pricing/CTA)
   so the header reads as a blog section, not a sales funnel. */
.site-header-nav {
  display: flex;
  align-items: center;
  gap: 24px;
  flex: 0 0 auto;
}

.site-header-nav a {
  text-decoration: none;
  color: var(--tool-text);
  font-size: var(--text-xs);
  font-weight: 600;
}

.site-header-nav a:hover,
.site-header-nav a:focus {
  color: var(--tool-primary);
}

/* Scoped through .site-header and qualified with img so these land at (0,3,1)
   and outrank the [data-theme] logo rules in theme-dark.css (0,3,0). Matching
   on class alone would tie on order and bring the wordmark back in dark. */
.site-header .site-brand img.site-logo-mark {
  display: none;
}

@media (max-width: 540px) {
  .site-header-inner {
    padding: 12px 16px;
    gap: 12px;
  }

  /* The wordmark plus the section nav plus the theme switch do not fit across a
     phone, so the brand drops to the mark alone and saves 126px. */
  .site-header .site-brand img.site-logo-light,
  .site-header .site-brand img.site-logo-dark {
    display: none;
  }

  .site-header .site-brand img.site-logo-mark {
    display: block;
  }

  .site-header-nav {
    gap: 16px;
  }

  .site-header-nav a {
    font-size: var(--text-xs);
  }

  .tool-breadcrumb {
    padding-left: 16px;
    padding-right: 16px;
  }
}

/* ---------- Conversion-pitch banner above the invoice ---------- */

.page-banner {
  margin: 40px 0 20px;
  padding: 10px 16px;
  background: var(--tool-secondary);
  border: 1px solid var(--tool-border);
  border-radius: var(--radius-sm);
  text-align: center;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: center;
  gap: 10px;
  font-size: var(--text-xs);
  line-height: 1.4;
}

.page-banner-text {
  color: var(--invoice-text);
}

.page-banner-link {
  color: var(--tool-primary);
  text-decoration: underline;
  text-underline-offset: 2px;
  font-weight: 600;
  white-space: nowrap;
}

.page-banner-link:hover,
.page-banner-link:focus {
  text-decoration-thickness: 2px;
}

/* ---------- Hero (only on standalone tool page) ---------- */

.site-hero {
  text-align: center;
  padding: 16px 0 28px;
}

.site-hero-title {
  margin: 0 0 8px;
  font-size: var(--text-4xl);
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--tool-text);
}

.site-hero-tagline {
  margin: 0;
  font-size: var(--text-sm);
  color: var(--invoice-text);
  max-width: 580px;
  margin-left: auto;
  margin-right: auto;
}

@media (max-width: 540px) {
  .site-hero-title {
    font-size: var(--text-2xl);
  }
}

/* ---------- Toolbar ---------- */

.toolbar {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
  align-items: flex-end;
  justify-content: space-between;
  padding: 16px;
  background: var(--tool-surface);
  border: 1px solid var(--tool-border);
  border-radius: var(--radius-sm);
  margin-bottom: 16px;
}

.toolbar-controls {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
}

.toolbar-field {
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-width: 140px;
}

.toolbar-label {
  font-size: var(--text-2xs);
  color: var(--invoice-text);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.toolbar-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

/* ---------- Buttons ---------- */

.btn,
.btn-icon {
  font: inherit;
  cursor: pointer;
  border-radius: var(--radius-sm);
  border: 1px solid transparent;
  padding: 10px 16px;
  min-height: 40px;
  background: var(--tool-secondary);
  color: var(--tool-secondary-text);
}

.btn-primary {
  background: var(--tool-primary);
  color: var(--tool-primary-text);
  border-color: var(--tool-primary);
}

.btn-secondary {
  background: var(--tool-secondary);
  color: var(--tool-secondary-text);
  border-color: var(--tool-border);
}

.btn-add {
  background: transparent;
  color: var(--tool-primary);
  border: 1px dashed var(--tool-border);
}

.btn-icon {
  background: transparent;
  color: var(--tool-muted);
  border: 1px solid transparent;
  padding: 6px 10px;
  min-height: 36px;
  font-size: var(--text-lg);
  line-height: 1;
}

.btn-icon:hover,
.btn-icon:focus {
  color: var(--tool-danger);
  border-color: var(--tool-border);
}

#logo-slot {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 80px;
  min-width: 180px;
  padding: 12px 20px;
  background: transparent;
  border: 2px dashed var(--invoice-border);
  border-radius: var(--radius-sm);
  color: var(--invoice-muted);
  cursor: pointer;
  font: inherit;
}

#logo-slot:hover,
#logo-slot:focus {
  border-color: var(--invoice-accent);
  color: var(--invoice-accent);
}

/* Rendered logo with hover-only remove button */
.logo-rendered {
  position: relative;
  display: inline-block;
}

.logo-rendered .logo-image {
  display: block;
  max-width: 200px;
  max-height: 80px;
  width: auto;
  height: auto;
  object-fit: contain;
}

.logo-remove {
  position: absolute;
  top: -10px;
  right: -10px;
  width: 28px;
  height: 28px;
  padding: 0;
  border-radius: var(--radius-round);
  background: var(--invoice-bg);
  color: var(--invoice-text);
  border: 1px solid var(--invoice-border);
  font: inherit;
  font-size: var(--text-md);
  line-height: 1;
  cursor: pointer;
  box-shadow: var(--elevation-xs);
  opacity: 0;
  transition: opacity 120ms ease;
}

.logo-rendered:hover .logo-remove,
.logo-rendered:focus-within .logo-remove,
.logo-remove:focus {
  opacity: 1;
}

.logo-remove:hover,
.logo-remove:focus {
  border-color: var(--invoice-accent);
  color: var(--invoice-accent);
}

/* ---------- Invoice surface ---------- */

.invoice {
  background: var(--invoice-bg);
  color: var(--invoice-text);
  border: 1px solid var(--invoice-border);
  border-radius: var(--radius-sm);
  padding: 32px;
  box-shadow: var(--elevation-xs);
}

.invoice-header {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 24px;
  padding-bottom: 24px;
  border-bottom: 1px solid var(--invoice-border);
  margin-bottom: 24px;
}

.invoice-header-left {
  display: flex;
  align-items: center;
  gap: 16px;
  flex: 1 1 auto;
  min-width: 0;
}

.invoice-header-right {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 4px;
  text-align: right;
}

.invoice-title {
  margin: 0 0 8px;
  font-size: var(--text-4xl);
  letter-spacing: 0.08em;
  color: var(--invoice-accent);
}

.invoice-number-field {
  display: inline-flex;
  align-items: baseline;
  gap: 4px;
  color: var(--invoice-muted);
  font-size: var(--text-sm);
  line-height: 1;
}

.invoice-number-prefix {
  font-size: var(--text-sm);
  line-height: 1;
}

.invoice-number-field input {
  width: 140px;
  text-align: right;
}

/* ---------- Meta row (Parties on the left, info on the right) ---------- */
/* Two-column outer split. The parties column stacks FROM on top with a
   side-by-side BILL TO / SHIP TO sub-row below. The info column packs the
   date / terms / due date / PO into compact horizontal label-input rows. */
.invoice-meta {
  display: grid;
  grid-template-columns: 1.4fr 1fr;
  gap: 32px;
  margin-bottom: 32px;
  align-items: start;
}

.meta-parties {
  display: flex;
  flex-direction: column;
  gap: 16px;
  min-width: 0;
}

.meta-bill-ship {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px;
  align-items: start;
}

.meta-block {
  display: flex;
  flex-direction: column;
  gap: 6px;
  min-width: 0;
  max-width: 100%;
  overflow-wrap: break-word;
}

.meta-block textarea,
.meta-block input {
  width: 100%;
}

.meta-shipto-toggle {
  margin-top: 4px;
}

/* The SHIP TO column has no real label when collapsed, but BILL TO does.
   This invisible placeholder takes the same vertical space as a label so
   the "+ Ship To" button lines up with the BILL TO textarea. Hidden once
   the SHIP TO row is expanded (it brings its own label). */
.meta-label-spacer {
  visibility: hidden;
  pointer-events: none;
  user-select: none;
}

.meta-shipto-col:has(#field-shipTo-wrap:not([hidden])) .meta-label-spacer {
  display: none;
}

/* SHIP TO content: the textarea takes the full column width (matching the
   BILL TO textarea so their right edges align with the FROM textarea
   above). The remove "x" sits absolutely in the bottom-right corner of
   the textarea, where the browser's resize handle would otherwise live;
   we disable native resize so they do not collide. */
.meta-shipto {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.meta-shipto textarea {
  resize: none;
}

.meta-shipto > .invgen-section-remove {
  position: absolute;
  right: 4px;
  bottom: 4px;
}

/* Right-side info: each row is "label | input" so the section reads compact. */
.meta-info {
  display: flex;
  flex-direction: column;
  gap: 8px;
  min-width: 0;
}

.meta-field-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.4fr);
  align-items: center;
  gap: 10px;
}

.meta-field-row input.editable-label {
  margin: 0;
}

.meta-field-row > input:not(.editable-label),
.meta-field-row > input[type="date"],
.meta-field-row > input[type="text"]:not(.editable-label) {
  width: 100%;
}

@media (max-width: 720px) {
  .invoice-meta {
    grid-template-columns: 1fr;
  }
  .meta-bill-ship {
    grid-template-columns: 1fr;
  }
}

/* ---------- Line items ---------- */

.invoice-items {
  margin-bottom: 32px;
}

.line-items {
  width: 100%;
  border-collapse: collapse;
}

.line-items thead th {
  text-align: left;
  font-size: var(--text-2xs);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--invoice-header-text);
  background: var(--invoice-header-bg);
  padding: 10px 12px;
}

.line-items tbody td {
  padding: 10px 12px;
  border-bottom: 1px solid var(--invoice-border);
  vertical-align: middle;
}

.col-quantity,
.col-rate,
.col-amount {
  width: 120px;
  text-align: right;
}

.col-delete {
  width: 48px;
  text-align: center;
}

.line-items input[type="text"],
.line-items input[type="number"] {
  width: 100%;
}

.line-items .col-quantity input,
.line-items .col-rate input {
  text-align: right;
}

.line-items output {
  display: inline-block;
  width: 100%;
  text-align: right;
}

.line-items-actions {
  margin-top: 12px;
}

/* ---------- Footer (notes + totals) ---------- */

.invoice-footer {
  display: grid;
  grid-template-columns: 1fr 360px;
  gap: 32px;
}

.invoice-notes {
  display: flex;
  flex-direction: column;
  gap: 16px;
  max-width: 100%;
  overflow-wrap: break-word;
}

.notes-block {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.notes-block label {
  font-size: var(--text-2xs);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--invoice-text);
  font-weight: 600;
}

.notes-block textarea {
  width: 100%;
}

/* Optional acceptance / signature block. Toggled on like Ship To; the user
   prints the document and signs above each line. Lines are plain ruled
   borders so they print cleanly and capture into the PDF. */
.invoice-signature {
  margin-top: 28px;
}

.signature-block {
  position: relative;
}

.signature-heading {
  display: block;
  font-size: var(--text-xs);
  font-weight: 600;
  color: var(--invoice-text);
  margin-bottom: 24px;
}

.signature-row {
  display: flex;
  gap: 40px;
  flex-wrap: wrap;
}

.signature-field {
  display: flex;
  flex-direction: column;
  flex: 1 1 240px;
  min-width: 0;
}

.signature-field-date {
  flex: 0 1 200px;
}

.signature-line {
  display: block;
  height: 28px;
  border-bottom: 1px solid var(--invoice-text);
}

.signature-caption {
  margin-top: 6px;
  font-size: var(--text-2xs);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--invoice-muted);
  font-weight: 600;
}

.signature-toggle-row {
  margin-top: 12px;
}

.signature-block > .invgen-section-remove {
  position: absolute;
  top: 0;
  right: 0;
}

.invoice-totals {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 8px 0;
}

/* Three-column row: label (auto-sized, no wrap), input-or-amount (right-
   aligned with a sensible cap), and the remove "x" if present. The label
   column hugs its content so multi-word labels like "Amount Paid" never
   wrap. The middle column sizes to the input group, which itself has a
   cap so it never bullies the label out of its lane. */
.totals-row {
  display: grid;
  grid-template-columns: auto 1fr 32px;
  align-items: center;
  column-gap: 10px;
}

.totals-row .editable-totals-label {
  grid-column: 1;
  text-align: left;
  white-space: nowrap;
}

.totals-row .totals-input-group {
  grid-column: 2;
  justify-self: end;
  width: 100%;
  max-width: 180px;
}

.totals-row .totals-value {
  grid-column: 2;
  justify-self: end;
}

.totals-row .invgen-section-remove {
  grid-column: 3;
}

.editable-totals-label {
  color: var(--invoice-text);
  font-size: var(--text-xs);
  font-weight: 600;
}

.totals-value {
  font-variant-numeric: tabular-nums;
  font-weight: 600;
  text-align: right;
}

.totals-total {
  border-top: 1px solid var(--invoice-border);
  padding-top: 10px;
  margin-top: 4px;
}

.totals-total .editable-totals-label,
.totals-total .totals-value {
  font-weight: 700;
  color: var(--invoice-text);
  font-size: var(--text-sm);
}

.totals-balance {
  border-top: 1px solid var(--invoice-border);
  padding-top: 10px;
  margin-top: 4px;
}

.totals-balance .editable-totals-label,
.totals-balance .totals-value {
  font-weight: 700;
  color: var(--invoice-accent);
  font-size: var(--text-sm);
}

/* "+ Shipping" / "+ Discount" toggle group. Both buttons live in one row
   below the editable totals. Each button hides itself when its row is
   expanded; the row collapses when all buttons are hidden. */
.totals-toggle-row {
  display: flex;
  gap: 18px;
  padding: 2px 0;
}

.totals-toggle-row:not(:has(.totals-toggle:not([hidden]))) {
  display: none;
}

.totals-toggle {
  background: transparent;
  border: none;
  color: var(--tool-primary);
  font-size: var(--text-2xs);
  font-weight: 600;
  padding: 0;
  cursor: pointer;
  text-align: left;
  min-height: 0;
}

.totals-toggle:hover,
.totals-toggle:focus {
  text-decoration: underline;
  background: transparent;
}

/* Combined input control used in Tax / Shipping / Discount / Amount Paid.
   One bordered rectangle that holds an optional prefix ($), the number
   input, an optional suffix (%), and an optional swap button. The whole
   group reads as one input field, matching invoice-generator.com. */
.totals-input-group {
  display: flex;
  align-items: stretch;
  border: 1px solid var(--gray-input-border, var(--invoice-border));
  border-radius: var(--radius-sm);
  background: var(--invoice-bg);
  overflow: hidden;
  height: 36px;
}

.totals-input-group:focus-within {
  border-color: var(--invoice-accent);
}

.totals-input-affix {
  display: flex;
  align-items: center;
  padding: 0 8px;
  font-size: var(--text-xs);
  color: var(--invoice-muted);
  background: transparent;
  flex: 0 0 auto;
}

.totals-input-affix-right {
  border-left: 1px solid transparent;
}

.totals-input-group input[type="number"] {
  border: none;
  background: transparent;
  text-align: right;
  flex: 1 1 auto;
  min-width: 0;
  padding: 0 6px;
  font-size: var(--text-xs);
  height: 100%;
}

.totals-input-group input[type="number"]:focus {
  outline: none;
  box-shadow: none;
}

.totals-input-swap {
  background: transparent;
  border: none;
  border-left: 1px solid var(--gray-input-border, var(--invoice-border));
  color: var(--invoice-muted);
  cursor: pointer;
  font-size: var(--text-xs);
  line-height: 1;
  padding: 0 8px;
  flex: 0 0 auto;
  min-height: 0;
}

.totals-input-swap:hover,
.totals-input-swap:focus {
  color: var(--invoice-text);
  background: var(--tool-secondary);
}

/* ---------- Inputs / selects / textareas ---------- */

input[type="text"],
input[type="number"],
input[type="date"],
input[type="email"],
select,
textarea {
  font: inherit;
  font-size: var(--text-sm); /* prevent iOS Safari auto-zoom on focus */
  color: var(--invoice-text);
  background: var(--invoice-bg);
  border: 1px solid var(--invoice-border);
  border-radius: var(--radius-sm);
  padding: 8px 10px;
  width: 100%;
  max-width: 100%;
}

textarea {
  resize: vertical;
  min-height: 90px;
  overflow-wrap: break-word;
}

input:focus,
select:focus,
textarea:focus {
  outline: 2px solid var(--invoice-accent);
  outline-offset: 1px;
}

/* ---------- Utility ---------- */

.visually-hidden {
  position: absolute !important;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

[hidden] {
  display: none !important;
}

/* ---------- Toast ---------- */

.invgen-toast {
  position: fixed;
  bottom: 24px;
  left: 50%;
  transform: translateX(-50%) translateY(8px);
  z-index: 50;
  max-width: min(90vw, 420px);
  padding: 10px 16px;
  background: rgba(26, 26, 26, 0.92);
  color: var(--white);
  border-radius: var(--radius-sm);
  font-size: var(--text-xs);
  line-height: 1.4;
  box-shadow: var(--elevation-sm);
  opacity: 0;
  pointer-events: none;
  transition: opacity 200ms ease, transform 200ms ease;
}

.invgen-toast.is-visible {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
}

/* "x" remove control inside discount / shipping / shipTo sections. Hidden
   until the user hovers (or keyboard-focuses inside) the row, then turns
   red on direct hover. */
.invgen-section-remove {
  width: 32px;
  height: 32px;
  min-width: 0;
  min-height: 0;
  padding: 0;
  border: none;
  background: transparent;
  color: var(--invoice-muted);
  font-size: var(--text-xl);
  line-height: 1;
  cursor: pointer;
  border-radius: var(--radius-xs);
  opacity: 0;
  transition: opacity 120ms ease, color 120ms ease;
}

.totals-row:hover .invgen-section-remove,
.totals-row:focus-within .invgen-section-remove,
.meta-shipto:hover .invgen-section-remove,
.meta-shipto:focus-within .invgen-section-remove,
.invgen-section-remove:focus {
  opacity: 1;
}

.invgen-section-remove:hover,
.invgen-section-remove:focus {
  color: var(--tool-danger);
  background: var(--tool-secondary);
}

/* ---------- Post-download conversion modal ---------- */

.invgen-modal {
  border: 1px solid var(--tool-border);
  border-radius: var(--radius-sm);
  background: var(--tool-surface);
  color: var(--tool-text);
  padding: 24px;
  max-width: 420px;
  width: calc(100% - 32px);
  box-shadow: var(--elevation-md);
}

.invgen-modal::backdrop {
  background: rgba(0, 0, 0, 0.5);
}

.invgen-modal h2 {
  margin: 0 0 8px;
  font-size: var(--text-lg);
  color: var(--tool-text);
}

.invgen-modal p {
  margin: 0 0 20px;
  font-size: var(--text-xs);
  line-height: 1.45;
}

.invgen-modal-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  justify-content: flex-end;
}

.invgen-modal-actions .btn {
  text-decoration: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

/* ---------- Mobile: <= 720px ---------- */

@media (max-width: 720px) {
  .invoice-app {
    padding: 16px 12px 96px;
  }

  .invoice {
    padding: 16px;
  }

  /* Stack toolbar */
  .toolbar {
    flex-direction: column;
    align-items: stretch;
    gap: 12px;
  }

  .toolbar-controls,
  .toolbar-actions {
    width: 100%;
  }

  .toolbar-field {
    width: 100%;
  }

  /* Stack invoice header */
  .invoice-header {
    flex-direction: column;
    align-items: stretch;
    text-align: left;
  }

  .invoice-header-right {
    text-align: left;
  }

  .invoice-number-field input {
    width: 100%;
  }

  /* Stack the meta row */
  .invoice-meta {
    grid-template-columns: 1fr;
    gap: 16px;
  }

  /* Stack notes + totals */
  .invoice-footer {
    grid-template-columns: 1fr;
    gap: 24px;
  }

  /* Line items become stacked cards */
  .line-items,
  .line-items thead,
  .line-items tbody,
  .line-items tr,
  .line-items td,
  .line-items th {
    display: block;
    width: 100%;
  }

  .line-items thead {
    /* Hide the header row visually but keep it for assistive tech */
    position: absolute;
    left: -9999px;
    top: -9999px;
  }

  .line-items tbody tr.line-item {
    border: 1px solid var(--invoice-border);
    border-radius: var(--radius-sm);
    padding: 12px;
    margin-bottom: 12px;
    background: var(--invoice-bg);
  }

  .line-items tbody td {
    border-bottom: none;
    padding: 6px 0;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    text-align: left;
  }

  .line-items tbody td::before {
    content: attr(data-label);
    font-size: var(--text-2xs);
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--invoice-muted);
    flex: 0 0 auto;
  }

  .line-items tbody td.col-delete::before {
    content: "";
  }

  .line-items tbody td.col-delete {
    justify-content: flex-end;
  }

  .line-items input,
  .line-items output {
    flex: 1 1 auto;
    width: auto;
    text-align: right;
  }

  /* Tap targets at least 44px */
  .btn,
  .btn-icon,
  button,
  select,
  input[type="date"] {
    min-height: 44px;
  }

  .btn-icon {
    min-width: 44px;
    font-size: var(--text-lg);
  }

  #logo-slot {
    width: 100%;
    min-height: 80px;
  }

  /* Sticky download bar at the bottom of the viewport on mobile */
  .toolbar-actions {
    position: sticky;
    bottom: 0;
    left: 0;
    right: 0;
    padding: 10px 12px;
    margin: 0 -12px -12px;
    background: var(--tool-surface);
    border-top: 1px solid var(--tool-border);
    box-shadow: var(--elevation-sm);
    z-index: 5;
  }

  .toolbar-actions .btn {
    flex: 1 1 0;
  }

  #download-pdf {
    width: 100%;
  }

  /* Template-specific mobile resets. The custom templates use a full-bleed
   * layout with padding pushed onto inner sections; on small screens we
   * collapse those paddings so the content does not get squeezed. The
   * Ribbon SVG is hidden entirely on mobile, where there is not enough
   * room for a decorative left rail. */
  [data-template="modern"] .invoice-header,
  [data-template="modern"] .invoice-meta,
  [data-template="modern"] .invoice-items,
  [data-template="modern"] .invoice-footer,
  [data-template="formal"] .invoice-header,
  [data-template="formal"] .invoice-meta,
  [data-template="formal"] .invoice-items,
  [data-template="formal"] .invoice-footer,
  [data-template="elegant"] .invoice-header,
  [data-template="elegant"] .invoice-meta,
  [data-template="elegant"] .invoice-items,
  [data-template="elegant"] .invoice-footer,
  [data-template="ribbon"] .invoice-header,
  [data-template="ribbon"] .invoice-meta,
  [data-template="ribbon"] .invoice-items,
  [data-template="ribbon"] .invoice-footer {
    padding-left: 16px;
    padding-right: 16px;
  }

  [data-template="modern"] .invoice {
    border-left-width: 6px;
  }

  [data-template="ribbon"] .invoice-ribbon-deco {
    display: none;
  }

  [data-template="ribbon"] .invoice-header-right {
    flex-direction: column;
    align-items: flex-start;
    gap: 4px;
  }
}

/* ---------- Hide delete on the only line item (CSS-only) ---------- */
/* When there's just one row left, the delete button is a no-op (main.js
   keeps at least one row), so we hide it to remove the misleading affordance.
   When the user adds more rows, the delete button reappears on every row. */
[data-line-items-body] .line-item:only-child .btn-icon[data-action="delete-line-item"] {
  display: none;
}

/* ---------- Hide native number-input spinners ---------- */
/* The up/down arrows browsers add to <input type="number"> clutter the
   compact totals inputs and our right-aligned numbers. Hide them; the
   inputmode="decimal"/"numeric" attributes still give the right mobile
   keyboard. */
input[type="number"]::-webkit-inner-spin-button,
input[type="number"]::-webkit-outer-spin-button {
  -webkit-appearance: none;
  appearance: none;
  margin: 0;
}
input[type="number"] {
  -moz-appearance: textfield;
  appearance: textfield;
}

/* ---------- Line items: align numeric columns ---------- */
/* Quantity, Rate, and Amount are numeric. Right-align both the header
   cell and the value cell so the column reads as a vertical column of
   numbers instead of misaligned text and digits. */
.line-items thead th.col-quantity,
.line-items thead th.col-rate,
.line-items tbody td.col-quantity,
.line-items tbody td.col-rate {
  text-align: left;
}
.line-items thead th.col-amount,
.line-items tbody td.col-amount {
  text-align: right;
}
.line-items tbody td.col-quantity input,
.line-items tbody td.col-rate input {
  text-align: right;
}

/* ---------- Editable text labels ---------- */
/* Inputs styled to look like plain text. No border or background by
   default, so they blend into the invoice. On hover or focus a blue
   border appears. The selectors below all start with `input` to bump
   specificity above the global `input[type="text"]` rule, which would
   otherwise re-apply the form-input border + white background. */
input.editable-text,
textarea.editable-text {
  border: 1px solid transparent;
  background: transparent;
  font: inherit;
  color: inherit;
  padding: 4px 6px;
  border-radius: var(--radius-sm);
  width: 100%;
  text-align: inherit;
  font-size: inherit;
  box-shadow: none;
}

input.editable-text::placeholder,
textarea.editable-text::placeholder {
  color: var(--invoice-muted);
  opacity: 1;
}

input.editable-text:hover,
textarea.editable-text:hover {
  border-color: var(--invoice-accent);
  background: transparent;
}

input.editable-text:focus,
textarea.editable-text:focus {
  border-color: var(--invoice-accent);
  outline: none;
  background: transparent;
}

/* Small uppercase label variant: matches the old <label> styling for
   FROM / BILL TO / DATE / NOTES / TERMS etc. */
input.editable-label {
  font-size: var(--text-2xs);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  font-weight: 600;
  color: var(--invoice-text);
  display: block;
}

/* Table header variant: same background as the surrounding <th> (dark
   strip on the classic template, transparent on modern/formal), white
   text on the dark backgrounds. Specificity is bumped so the global
   input rule cannot reset the background back to white. */
.line-items thead th .editable-th {
  font-size: var(--text-2xs);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  font-weight: 600;
  color: var(--invoice-header-text);
  background: transparent;
  padding: 4px 6px;
}

.line-items thead th .editable-th::placeholder {
  color: var(--invoice-header-text);
  opacity: 0.7;
}

.line-items thead th .editable-th:hover,
.line-items thead th .editable-th:focus {
  border-color: var(--invoice-accent);
  background: transparent;
  color: var(--invoice-header-text);
}

/* Right-align the numeric column headers so the editable input matches the
   right-aligned values below. */
.line-items thead th.col-quantity .editable-th,
.line-items thead th.col-rate .editable-th,
.line-items thead th.col-amount .editable-th {
  text-align: right;
}

/* Totals labels are sized to a uniform comfortable width so every row's
   hover border looks the same. Wider than the longest label text
   ("Balance Due" in bold) so there is breathing room, but narrower than
   the browser's ~200px text-input default that the global rule would
   otherwise apply. */
input.editable-totals-label {
  width: 140px;
  max-width: 100%;
}

/* Business title sits to the right of the logo on the same horizontal row.
   This is the dominant visual element of the header, so it gets the big
   type weight; the document title shrinks to make room. */
input.editable-business-title {
  font-size: var(--text-3xl);
  font-weight: 700;
  color: var(--invoice-text);
  text-align: left;
  flex: 1 1 auto;
  min-width: 0;
  line-height: 1.15;
}

/* Document title (default "INVOICE") sits where the old hard-coded title
   lived. Kept slim so the business title dominates. */
input.editable-document-title {
  font-size: var(--text-4xl);
  font-weight: 600;
  letter-spacing: 0.08em;
  color: var(--invoice-accent);
  text-align: right;
  margin-bottom: 4px;
  /* Keep the text big but constrain the input's footprint so it does not
     fight the business title for header width. */
  width: auto;
  max-width: 220px;
}

/* ---------- PDF capture mode ---------- */
/* When pdf.js is rendering the invoice into a PDF via html2canvas, it adds
   .invgen-capturing to the .invoice element. We use that flag to strip
   UI-only affordances (toggle buttons, remove "x" controls, the delete
   column on line items, the date picker indicator) so the captured image
   matches what a finished invoice should look like. */
.invgen-capturing .totals-input-swap,
.invgen-capturing .totals-toggle-row,
.invgen-capturing .meta-shipto-toggle,
.invgen-capturing .invgen-section-remove,
.invgen-capturing .logo-remove,
.invgen-capturing [data-action="delete-line-item"],
.invgen-capturing .col-delete,
.invgen-capturing .meta-label-spacer,
.invgen-capturing .line-items-actions,
.invgen-capturing .signature-toggle-row,
.invgen-capturing #logo-slot {
  display: none !important;
}

/* Force editable fields to render flat with no border, matching the visual
   the user sees when they are not hovering. */
.invgen-capturing input,
.invgen-capturing textarea,
.invgen-capturing select {
  border-color: transparent !important;
  outline: none !important;
  box-shadow: none !important;
  background: transparent !important;
}

/* In the live editor the totals-input-group is one bordered rectangle that
   holds the currency / percent prefix, the number, and the optional swap
   button. In the captured PDF we strip the wrapper border + background so
   the finished invoice reads as a flat "$1,234.00" row instead of a form
   field. The affixes ($/%) match the body text color, sit flush against
   the number, and inherit the parent row's font-size so the symbol and
   the number render at the same scale.

   The explicit height (36px) on the live group is removed during capture
   so the group height collapses to its inline content. Without that, the
   group's stretched flex items render at 36px tall and the small affix
   text floats at the top, making "$" look superscript-sized next to the
   number. */
.invgen-capturing .totals-input-group {
  border-color: transparent !important;
  background: transparent !important;
  justify-content: flex-end !important;
  align-items: baseline !important;
  height: auto !important;
  font-size: inherit !important;
}

.invgen-capturing .totals-input-affix {
  color: var(--invoice-text) !important;
  padding: 0 !important;
  font-size: inherit !important;
  line-height: inherit !important;
}

/* pdf.js replaces every <input>/<textarea> in the cloned DOM with a <span>
   carrying the live value (html2canvas does not render dirty input values
   reliably). The replacement copies computed styles from the live input,
   including its fixed pixel width and 14px font-size, which leaves a gap
   between the affix and the number and renders the number larger than the
   symbol. Override both so the replacement sizes to its content, inherits
   the parent row's font-size, and sits flush against the $ / % symbol.
   .totals-input-affix lets us distinguish replacements (no class) from
   affix spans. */
.invgen-capturing .totals-input-group > span:not(.totals-input-affix) {
  width: auto !important;
  min-width: 0 !important;
  max-width: none !important;
  flex: 0 0 auto !important;
  padding: 0 !important;
  color: var(--invoice-text) !important;
  font-size: inherit !important;
  line-height: inherit !important;
}

/* Hide native date-picker indicator entirely during capture so it does not
   leave a faint stripe in the snapshot. */
.invgen-capturing input[type="date"]::-webkit-calendar-picker-indicator {
  display: none !important;
}

/* ---------- Date inputs ---------- */
/* Hide the browser's built-in calendar icon on <input type="date">. The whole
   input becomes the click target via showPicker() wired in main.js. */
input[type="date"]::-webkit-calendar-picker-indicator {
  opacity: 0;
  width: 100%;
  height: 100%;
  position: absolute;
  top: 0;
  left: 0;
  cursor: pointer;
  background: transparent;
}

input[type="date"] {
  position: relative;
  cursor: pointer;
}
