﻿/* ============================================================================
   The printed sales invoice.

   Deliberately outside the application's theme. This is a document, not a
   screen: it is black on white whatever the reader has the rest of the app set
   to.

   Everything is grey. The client prints in black and white, so colour would
   arrive as an unpredictable grey anyway - one chosen by the printer's own
   conversion rather than by anybody who looked at it. Choosing the greys here
   means what is on the page is what was designed.

   This was written expecting a laser printer. It is not one. The client prints
   on two monochrome pigment ink tank printers, an Epson M100 and an M1120, and
   that is a different machine in the way that matters here: one ink and no grey
   ink, so every tone below is a halftone - black dots with white gaps - rather
   than a lighter shade. A laser's toner dot is small and even enough to hold a
   light tint together; a 3 picolitre inkjet dot on plain paper is not. Roughly
   what each token below asks the printer for: --ink 93% coverage, --ink-2 75%,
   --ink-3 56%, --rule 26%, --band 8%, --band-2 3%. The last three are scatter,
   not tint, which is why the hairlines can arrive as dotted lines and the row
   banding may not arrive at all.

   Nothing has been darkened yet. Head alignment and paper weight account for
   most of what a monochrome inkjet gets wrong with small type, and those are
   worth exhausting before changing a design the client likes.

   The sheet is laid out at its real size on screen as well as on paper, so
   what is checked is what comes out.
   ========================================================================= */

.print-page {
  --ink:      #111213;   /* body text                                        */
  --ink-2:    #3d4043;   /* secondary text                                   */
  --ink-3:    #6b6f74;   /* captions and labels                              */
  --rule:     #b9bdc2;   /* hairlines between rows                           */
  --rule-2:   #7e8388;   /* the heavier rules that separate sections         */
  --band:     #e9eaec;   /* table head fill                                  */
  --band-2:   #f6f7f8;   /* alternate row fill                               */
  --solid:    #26282b;   /* the one filled block: the amount payable         */

  /* The only colour on any printed page here, and only on a price agreement.
     See the .inv-save block near the totals for why that one document earns
     an exception to a greyscale sheet. */
  --save:     #00a651;   /* the saving on a price agreement                  */

  --sheet-w:  210mm;

  /* Must stay equal to the side margin in the print block's @page rule, or the
     sheet on screen stops being a preview of the sheet on paper. */
  --sheet-p:  14mm;

  --font-body: "Inter", system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-code: "JetBrains Mono", ui-monospace, "Cascadia Mono", Consolas, monospace;

  /* Which of the two the figures are set in, in one place so the sheet can be
     printed both ways and compared.

     Set to the body font because the client prints on monochrome pigment ink
     tank printers - an Epson M100 and an M1120 - and reported the numbers as
     the unclear part. JetBrains Mono is drawn for code on a screen at 12-14px;
     at the 7 to 8.5pt this sheet sets it, its stems are thin, and a printer
     with one ink reproduces a thin stem as a broken line of dots rather than a
     line. A monospace grid also has to squeeze the wide digits to the width of
     the narrow ones, which costs exactly the counters - the holes in 0, 6, 8 -
     that tell the digits apart when they are small.

     The columns do not depend on this: the sheet asks for tabular figures, so
     every digit is the same width in either font and the decimal points still
     line up. Point this at var(--font-code) to put the old figures back. */
  --font-figures: var(--font-body);

  background: #7e8388;
  min-height: 100vh;
  padding: 24px 16px 64px;
  color: var(--ink);
  font-family: var(--font-body);
}

/* --- the toolbar, which never prints ------------------------------------- */

.print-bar {
  width: min(100%, var(--sheet-w));
  margin: 0 auto 10px;
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
}

/* The toolbar is the one part of this page that is touched rather than printed,
   so its controls carry the same minimum height as the rest of the application:
   the text is small by design and the box around it must not be. */
.print-bar__back {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  min-height: 34px;
  color: #fff;
  text-decoration: none;
  font-size: 13px;
  font-weight: 600;
}

.print-bar__back:hover { text-decoration: underline; }
.print-bar__back svg { width: 15px; height: 15px; }

/* On a page with no copies to choose, Print goes to the far end of the bar, where
   the invoice has it, rather than sitting against the back link. */
.print-bar__back + .btn { margin-left: auto; }

.print-bar__copies {
  display: flex;
  margin-left: auto;
  border: 1px solid rgba(255, 255, 255, .5);
  border-radius: 7px;
  overflow: hidden;
}

.print-bar__copy {
  display: inline-flex;
  align-items: center;
  min-height: 34px;
  padding: 5px 11px;
  font-size: 12px;
  font-weight: 600;
  color: #fff;
  text-decoration: none;
  border-right: 1px solid rgba(255, 255, 255, .35);
}

.print-bar__copy:last-child { border-right: 0; }
.print-bar__copy:hover { background: rgba(255, 255, 255, .16); }

.print-bar__copy.is-chosen {
  background: #fff;
  color: #26282b;
}

.print-hint {
  width: min(100%, var(--sheet-w));
  margin: 0 auto 6px;
  font-size: 12px;
  line-height: 1.5;
  color: rgba(255, 255, 255, .85);
}

.print-hint:last-of-type { margin-bottom: 14px; }
.print-hint strong { color: #fff; font-weight: 600; }

/* A pack that was cut short says so above the sheets, where it is read before
   the printing rather than discovered after it. Amber against the dark bar
   rather than the palette's warning tokens: this strip is its own surface and
   is never themed. */
.print-hint--warn {
  padding: 8px 12px;
  border: 1px solid rgba(245, 190, 90, .5);
  border-radius: 6px;
  background: rgba(245, 190, 90, .12);
  color: #F7D9A0;
}

.print-missing {
  max-width: 460px;
  margin: 15vh auto;
  padding: 28px;
  background: #fff;
  border-radius: 10px;
  text-align: center;
}

.print-missing h1 { font-size: 20px; margin: 0 0 6px; }
.print-missing p { margin: 0 0 18px; color: var(--ink-3); }

/* --- the sheet ----------------------------------------------------------- */

/* A column, so the close can be pushed to the foot of the sheet. On a short
   invoice the totals and the signature would otherwise float up under the last
   line with a hand's width of white below them, which reads as an unfinished
   page rather than a finished document. */
.inv-sheet {
  display: flex;
  flex-direction: column;
  width: var(--sheet-w);
  min-height: 297mm;
  margin: 0 auto 22px;
  padding: var(--sheet-p);
  background: #fff;
  box-shadow: 0 6px 24px rgba(0, 0, 0, .28);
  font-size: 9pt;
  line-height: 1.32;

  /* Scaled down to fit a screen narrower than the paper. Set by the small
     script on the print page, and 1 until it runs, so a browser that never
     runs it falls back to the scrolling container below rather than to
     nothing.

     `zoom` rather than `transform: scale()` because zoom takes part in layout:
     the box really does become smaller, so the page reflows around it and no
     phantom width is left behind for the container to scroll. The factor cannot
     be worked out in CSS - calc() will not divide one length by another - which
     is the whole reason for the script.

     This rule is not inside @media screen, so the print block below sets zoom
     back to 1 explicitly. Without that, a phone-sized window would print a
     half-size invoice. */
  zoom: var(--sheet-fit, 1);

  /* A document, so its figures line up in columns and its dates do not
     re-wrap between one row and the next. */
  font-variant-numeric: tabular-nums;
}

.inv-mono {
  font-family: var(--font-figures);
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
}

/* The small letterspaced capitals that name a block. Set in grey, because a
   label competing with the thing it labels is a label in the way. */
.inv-cap {
  margin: 0 0 4px;
  font-size: 7pt;
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--ink-3);
}

/* --- masthead ------------------------------------------------------------ */

.inv-top {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 3mm 12mm;
  padding-bottom: 3mm;
  border-bottom: 1.6pt solid var(--ink);
}

/* The mark beside the name, not above it. Stacked, the masthead cost over
   half a centimetre of height for nothing, and height here is lines lost from
   the page below. */
.inv-top__brand {
  display: flex;
  align-items: flex-start;
  gap: 5mm;
}

.inv-top__logo {
  flex: none;
  width: 34mm;
  height: auto;

  /* The supplied mark is already black and white. Forced to greyscale anyway
     so a colour logo dropped in later cannot arrive as a muddy halftone. */
  filter: grayscale(100%);
}

.inv-top__name {
  margin: 0 0 1mm;
  font-family: "Plus Jakarta Sans", "Inter", sans-serif;
  font-size: 13pt;
  font-weight: 800;
  letter-spacing: -.01em;
}

.inv-top__addr {
  margin: 0;
  color: var(--ink-2);
  max-width: 72mm;
}

/* The company's own registration, under the address. Only the GST working
   prints it in the masthead: on a tax invoice the number belongs in the band
   of registration numbers below, with the PAN beside it. */
.inv-top__gst {
  margin: .8mm 0 0;
  font-weight: 700;
}

/* The registration numbers, along the foot of the masthead. */
.inv-ids {
  grid-column: 1 / -1;
  display: flex;
  flex-wrap: wrap;
  gap: 1mm 6mm;
  margin: 0;
  font-size: 8.5pt;
}

.inv-ids__item {
  display: inline-flex;
  align-items: baseline;
  gap: 1.6mm;
}

.inv-ids__key { color: var(--ink-3); }
.inv-ids__strong { font-weight: 700; }

.inv-top__doc { text-align: right; }

.inv-doctype {
  margin: 0;
  font-family: "Plus Jakarta Sans", "Inter", sans-serif;
  font-size: 15.5pt;
  font-weight: 800;
  letter-spacing: .16em;
  text-transform: uppercase;
  line-height: 1.1;
}

/* Rule 48(1) wants this on the face of the copy, so it is given a border of
   its own rather than being set as one more line of small print. */
/* The half millimetre on the right is not spacing, it is clearance. This is the
   only thing on the sheet with a vertical border sitting in a right-aligned
   column, so its border box lands exactly on the edge of the page box - and a
   line exactly on a clip boundary loses its outer half pixel to rounding, which
   prints as a rectangle with three and a half sides. The rules above and below
   the table reach the same edge and lose nothing, because the end of a
   horizontal line has nothing to show. */
.inv-copytag {
  display: inline-block;
  margin: 1.2mm .5mm 2.2mm 0;
  padding: 1.1mm 3mm;
  border: .8pt solid var(--rule-2);
  border-radius: 1.2mm;
  font-size: 7.5pt;
  font-weight: 700;
  letter-spacing: .07em;
  text-transform: uppercase;
  color: var(--ink-2);
}

/* A description list set as two columns, which is what most of this document
   is: a name and the thing it names. */
.inv-idlist,
.inv-facts {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: .5mm 4mm;
  margin: 0;
  font-size: 8.5pt;
}

.inv-idlist dt,
.inv-facts dt {
  color: var(--ink-3);
  white-space: nowrap;
}

.inv-idlist dd,
.inv-facts dd {
  margin: 0;
  color: var(--ink);
}

.inv-facts {
  justify-content: end;
  text-align: right;
  font-size: 8pt;
}

.inv-facts__strong { font-weight: 700; }

.inv-idlist--wide { grid-template-columns: 26mm 1fr; }

/* --- who, and where it went ---------------------------------------------- */

.inv-parties {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8mm;
  padding: 3mm 0 3.5mm;
  border-bottom: .8pt solid var(--rule-2);
}

.inv-party__cap {
  margin: 0 0 1mm;
  font-size: 7pt;
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--ink-3);
}

.inv-party__name {
  margin: 0 0 0.6mm;
  font-size: 10.5pt;
  font-weight: 700;
}

.inv-party__code {
  margin-left: 2mm;
  font-size: 8pt;
  font-weight: 500;
  color: var(--ink-3);
}

.inv-party__addr {
  margin: 0 0 2mm;
  font-size: 8.5pt;
  color: var(--ink-2);
}

.inv-party__pos { font-weight: 700; }

/* Free text about the consignment, across the foot of the parties row. Its own
   line rather than a column, because it is a sentence and the columns beside it
   hold addresses. */
.inv-remarks {
  grid-column: 1 / -1;
  display: flex;
  align-items: baseline;
  gap: 2mm;
  margin: 0;
  font-size: 8.5pt;
  color: var(--ink-2);
}

/* Across the foot of the parties block: the heading is long, and a third column
   would squeeze the two that carry addresses. */
.inv-transport {
  grid-column: 1 / -1;
  padding-top: 2.5mm;
  border-top: .4pt solid var(--rule);
}

/* Unless there is no delivery address, in which case the second column is empty
   and this belongs in it. */
.inv-transport--beside {
  grid-column: 2;
  grid-row: 1;
  padding-top: 0;
  border-top: 0;
}

.inv-transport__row {
  display: flex;
  flex-wrap: wrap;
  gap: 1mm 7mm;
  margin: 0;
  font-size: 8.5pt;
}

.inv-transport__item {
  display: inline-flex;
  align-items: baseline;
  gap: 1.6mm;
}

/* --- the lines ----------------------------------------------------------- */

.inv-lines {
  width: 100%;
  margin-top: 4mm;
  border-collapse: collapse;
  font-size: 8.5pt;
}

.inv-lines thead th {
  padding: 1.6mm 2mm;
  background: var(--band);
  border-top: .9pt solid var(--ink);
  border-bottom: .9pt solid var(--ink);
  font-size: 7.5pt;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  text-align: left;
  color: var(--ink);
}

.inv-lines tbody td {
  padding: 1.3mm 2mm;
  border-bottom: .5pt solid var(--rule);
  vertical-align: top;
}

/* Faint banding. On a long list it is the thing that keeps the eye on one row
   as it crosses eight columns, and at this weight it costs almost no toner. */
.inv-lines tbody tr:nth-child(even) td { background: var(--band-2); }

/* The strip that names the invoice over the columns. It repeats with the rest
   of the head, so on a long invoice every sheet says what it is part of. Light
   enough to read as a caption for the table rather than a heading of its own,
   and it borrows the band's top rule instead of drawing a second one. */
.inv-lines thead tr.inv-lines__mark th {
  padding: 1mm 2mm .8mm;
  background: none;
  border-top: 0;
  border-bottom: 0;
  font-size: 6.5pt;
  font-weight: 500;
  letter-spacing: .09em;
  color: var(--ink-3);
}

.inv-lines__mark th span:first-child {
  font-family: var(--font-figures);
  letter-spacing: .02em;
}

/* Right of the strip, without leaving the cell a flex container: a table cell
   that is told to be flex stops being a cell, and the row grows an anonymous
   one around it. */
.inv-lines__mark th span:last-child { float: right; }

/* A heading sits over the same end of the column as the figures under it.
   Without this the two-class rules above win on specificity and every number
   column is labelled from the wrong side. */
.inv-lines thead th.inv-lines__no,
.inv-lines thead th.inv-lines__num,
.inv-lines thead th.inv-lines__pct,
.inv-hsn__table th.inv-lines__num { text-align: right; }

/* These are minimums, not fixed widths: the table lays out automatically, so a
   figure wider than its column takes the room it needs and the description
   gives it up. They were cut when the taxable and total columns arrived, which
   put four money columns on the row and five on an invoice carrying a discount.
   At the old 24mm and 13mm a discounted line left the description 20mm and six
   wrapped lines. Sized so a lakh-scale figure - "23,68,750.00" - still sits on
   one line without borrowing. */
.inv-lines__no  { width: 8mm;  text-align: right; color: var(--ink-3); }
.inv-lines__hsn { width: 16mm; }
.inv-lines__num { width: 21mm; text-align: right; white-space: nowrap; }
.inv-lines__pct { width: 11mm; text-align: right; white-space: nowrap; }
.inv-lines__desc { font-weight: 500; }

.inv-uom {
  margin-left: 1.2mm;
  font-size: 7.5pt;
  color: var(--ink-3);
}

/* What the quantity comes to in the product's other unit, in brackets after the
   description: "Coconut Oil 2 LTR Bottle (160 ltr)". Smaller and lighter than
   the description, because it explains what was sold rather than naming it, and
   there should be no doubt which of the two figures the customer was billed for.

   It was a second line in the quantity column. Read there it competed with the
   billed quantity - two figures in one cell, one above the other, both in the
   figure font - and the column had to be wide enough for the longer of them.
   Beside the description it reads as part of the goods, and the quantity column
   is left showing a single number.

   Not bold: the description carries font-weight 500 and this would inherit it.

   The brackets are in the markup rather than generated, and the space before
   them is a real space in the markup rather than only this margin, so the line
   survives being copied out of the PDF as "Coconut Oil 2 LTR Bottle (160 ltr)"
   rather than running the two together. The margin is what opens that space to
   something you can see; the space is what makes it text. It sits outside the
   span so a long description can still break the line before the bracket. */
.inv-lines__convert {
  margin-left: .6mm;
  font-size: 6.5pt;
  font-weight: 400;
  color: var(--ink-3);
  white-space: nowrap;
}

/* --- the close: totals, words, bank, signature --------------------------- */

/* Pushed to the foot of the sheet when there is room, which is what pins the
   signature to the bottom of a short invoice. On an invoice that fills the
   page there is no free space to take, so this resolves to nothing and the
   close follows the last line as before. */
.inv-close {
  margin-top: auto;
  padding-top: 3mm;
}

.inv-close__cols {
  display: grid;
  grid-template-columns: 1fr 78mm;
  gap: 8mm;
  align-items: start;
}

/* Pinned to the second column rather than left to fall into the first. Nothing
   occupies the first any more, and a single grid child takes the first track it
   is offered: without this the totals would stretch across the wide side and sit
   under the lines rather than to the right of them. */
.inv-totals { grid-column: 2; }

.inv-hsn__table {
  width: 100%;
  border-collapse: collapse;
  font-size: 8pt;
}

.inv-hsn__table th {
  padding: 1.4mm 1.6mm;
  border-bottom: .7pt solid var(--rule-2);
  font-size: 7pt;
  font-weight: 700;
  letter-spacing: .05em;
  text-transform: uppercase;
  text-align: left;
  color: var(--ink-3);
}

.inv-hsn__table td {
  padding: 1.4mm 1.6mm;
  border-bottom: .4pt solid var(--rule);
}

.inv-hsn__table tfoot td {
  border-top: .7pt solid var(--rule-2);
  border-bottom: 0;
  font-weight: 700;
}

/* The rate sits with its amount rather than in a column of its own: eighteen
   per cent of something is one fact, not two. */
.inv-rate {
  margin-right: 2mm;
  font-size: 7pt;
  color: var(--ink-3);
}

.inv-totals__list {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 0.9mm 6mm;
  margin: 0;
  font-size: 9pt;
}

.inv-totals__list dt { color: var(--ink-2); }
.inv-totals__list dd { margin: 0; text-align: right; }

.inv-totals__rule {
  padding-top: 1.6mm;
  border-top: .5pt solid var(--rule);
  font-weight: 700;
  color: var(--ink);
}

.inv-grand {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 4mm;
  margin: 2.4mm 0 0;
  padding: 2.2mm 3mm;
  background: var(--solid);
  color: #fff;
}

.inv-grand__cap {
  font-size: 7.5pt;
  font-weight: 700;
  letter-spacing: .09em;
  text-transform: uppercase;
}

.inv-grand__sum {
  font-size: 12pt;
  font-weight: 700;
}

/* What came off the goods, under the total rather than in it. Outlined instead
   of filled: it belongs to the same block as the amount payable but is not part
   of arriving at it, and the one solid bar on the page should stay the one
   figure the customer has to act on. */
.inv-saved {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 4mm;
  margin: 1.2mm 0 0;
  padding: 1.6mm 3mm;
  border: .8pt solid var(--rule-2);
  color: var(--ink-2);
}

.inv-saved__cap {
  font-size: 7.5pt;
  font-weight: 700;
  letter-spacing: .09em;
  text-transform: uppercase;
}

.inv-saved__sum {
  font-size: 9.5pt;
  font-weight: 700;
  color: var(--ink);
}

/* ---- The saving on a price agreement --------------------------------------
   Every other document on this stylesheet is greyscale, because the client's
   office printer is and because a tax document should read the same however it
   is reproduced. A price agreement is the one that is almost always sent as a
   PDF and read on a screen, and the figure it exists to communicate is what the
   customer is saving. So that figure is green.

   It is bold and a size larger as well, which is what carries it when the sheet
   does go through a mono printer: the colour is the bonus, never the only
   signal. A reader who prints in black and white loses nothing but the green.
   -------------------------------------------------------------------------- */

.inv-grand.inv-save { background: var(--save); }

/* The per-line column, where the figure is too small to fill and a coloured
   number is enough. */
.inv-save__cell {
  color: var(--save);
  font-weight: 700;
}

.inv-save__pct {
  display: block;
  font-size: 6.5pt;
  font-weight: 600;
  color: var(--save);
}

/* The headline per cent in the facts block at the top right, so the saving is
   visible before the page is read at all. */
.inv-save__figure { color: var(--save); }

.inv-save__note {
  margin: 1.4mm 0 0;
  font-size: 7.5pt;
  color: var(--ink-2);
  text-align: right;
}

.inv-words {
  display: flex;
  align-items: baseline;
  gap: 4mm;
  margin: 4mm 0 0;
  padding: 1.8mm 0;
  border-top: .8pt solid var(--rule-2);
  border-bottom: .8pt solid var(--rule-2);
}

.inv-words .inv-cap {
  margin: 0;
  flex: none;
  white-space: nowrap;
}

.inv-words__text {
  font-weight: 600;
  font-size: 9pt;
}

/* --- the receipt ---------------------------------------------------------
   Shares the invoice's paper, type and page rules; these are the few parts a
   receipt has and an invoice does not. */

/* What the document is for, under its title. Not the invoice's copy tag: that is
   a short pill sized for "Original for Recipient", and a sentence set in it
   forces the whole right-hand column wide enough to hold one line, which pushes
   the company's name into three. Given a width of its own it wraps instead. */
.rcp-subtitle {
  max-width: 62mm;
  margin: 1.2mm 0 0 auto;
  font-size: 7.5pt;
  line-height: 1.4;
  color: var(--ink-3);
}

/* The sum received, said once and large. An invoice earns its total at the foot
   of a column of figures; a receipt has one number and it belongs at the top,
   where somebody checking the document looks first. */
.rcp-sum {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 4mm;
  margin: 5mm 0 0;
  padding: 3mm 4mm;
  background: var(--solid);
  color: #fff;
}

.rcp-sum__cap {
  font-size: 8pt;
  font-weight: 700;
  letter-spacing: .09em;
  text-transform: uppercase;
}

.rcp-sum__value {
  font-size: 15pt;
  font-weight: 700;
}

/* Where a cheque has got to: subject to realisation until the bank pays it.
   Set as a line of its own under the words, bold, because it qualifies the
   sum above it and a customer filing this as proof of payment should see it. */
.rcp-cheque {
  margin: 2.5mm 0 0;
  font-size: 8.5pt;
  font-weight: 700;
  color: var(--ink);
}

/* The particulars Rule 49 asks for on money taken before the supply. Boxed
   because it applies to part of the document rather than all of it: the rest
   may be settling invoices that were taxed when they were raised. */
.rcp-advance {
  margin-top: 4mm;
  padding: 3mm 3.5mm;
  border: .8pt solid var(--rule-2);
  border-radius: 1mm;
}

.rcp-advance .inv-cap { margin: 0 0 2mm; }

.rcp-advance__note {
  margin: 2.5mm 0 0;
  font-size: 7.5pt;
  line-height: 1.5;
  color: var(--ink-2);
}

/* Bank, terms, signature: side by side. The signature column is fixed so it
   keeps its rule the same length whether or not there are bank details, and
   the other two share what is left. */
.inv-foot {
  display: grid;
  grid-template-columns: auto 1fr 58mm;
  gap: 7mm;
  padding-top: 3.5mm;
}

.inv-foot__sign { grid-column: 3; }

.inv-terms ul {
  margin: 0;
  padding-left: 4mm;
  font-size: 8pt;
  color: var(--ink-2);
}

.inv-decl {
  margin: 0 0 5mm;
  font-size: 7.5pt;
  line-height: 1.5;
  color: var(--ink-2);
}

.inv-foot__sign { text-align: right; }

.inv-sign__for {
  margin: 0 0 11mm;
  font-size: 8.5pt;
  font-weight: 700;
}

/* Room left above the rule for a hand. A signature block with nowhere to sign
   is the commonest fault in a printed invoice. */
.inv-sign__line {
  margin: 0;
  padding-top: 1.6mm;
  border-top: .6pt solid var(--rule-2);
  font-size: 7.5pt;
  color: var(--ink-3);
}

.inv-tail {
  display: flex;
  justify-content: space-between;
  gap: 6mm;
  margin: 3mm 0 0;
  padding-top: 2mm;
  border-top: .5pt solid var(--rule);
  font-size: 7pt;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--ink-3);
}

/* --- the stock on hand sheet ---------------------------------------------
   A list for the office rather than a document that leaves the company. It
   shares the invoice's paper, masthead and table; these are the parts a list
   of stock has and an invoice does not. */

/* How much is on the list, before the list. One outlined strip rather than a
   row of filled blocks: a large fill is the likeliest thing on the page to band
   on the client's inkjets, and it would spend more ink than the table. */
.soh-summary {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: 1fr;
  margin: 4mm 0 0;
  border: .8pt solid var(--rule-2);
  border-radius: 1.2mm;
}

.soh-stat {
  display: flex;
  flex-direction: column;
  gap: .8mm;
  margin: 0;
  padding: 2.2mm 4mm 2.4mm;
  border-left: .5pt solid var(--rule);
}

.soh-stat:first-child { border-left: 0; }

.soh-stat__label {
  font-size: 7pt;
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--ink-3);
}

.soh-stat__value {
  font-size: 15pt;
  font-weight: 700;
  line-height: 1.05;
  color: var(--ink);
}

/* Below zero is the one figure on the strip that asks for something to be
   done, and it only appears when it is not nought. Given the head band's fill
   and its label in full ink, so it is found before it is read. */
.soh-stat--alert { background: var(--band); }
.soh-stat--alert .soh-stat__label { color: var(--ink); }

.soh-lines { margin-top: 5mm; }

/* On the baseline, not the top. The unit is set smaller than the quantity
   beside it, and top-aligned it floated above the figure it belongs to. */
.soh-lines tbody td {
  padding-top: .9mm;
  padding-bottom: .9mm;
  border-bottom: 0;
  vertical-align: baseline;
}

/* A product's places are one thing, so the rules fall between products and not
   between the places inside one. The rule is the row group's rather than the
   last row's cells': the number and the name span every row of the product, so
   they are not in the last row, and a rule drawn by its cells stopped short of
   both columns. */
.soh-lines tbody { border-bottom: .5pt solid var(--rule); }

.soh-lines tbody tr:first-child td { padding-top: 1.8mm; }
.soh-lines tbody tr:last-child td { padding-bottom: 1.8mm; }

/* Banded product by product for the same reason. The invoice's row-by-row
   banding is switched off first, or the second place of a product would be
   shaded and the first not. */
.soh-lines tbody tr:nth-child(even) td { background: none; }
.soh-lines tbody:nth-of-type(even) tr:nth-child(n) td { background: var(--band-2); }

.soh-product__name {
  display: block;
  font-weight: 600;
}

.soh-product__code {
  display: block;
  margin-top: .3mm;
  font-size: 7pt;
  letter-spacing: .02em;
  color: var(--ink-3);
}

/* Minimums under the table's automatic layout, like the invoice's columns: the
   product takes what is left, and a long warehouse name borrows from it rather
   than wrapping. Sized so "1,20,000.5" sits on one line. */
.soh-lines__place { width: 38mm; }
.soh-lines__area  { width: 28mm; }
.soh-lines__qty   { width: 24mm; }

.soh-lines__unit {
  width: 14mm;
  font-size: 7.5pt;
  color: var(--ink-3);
}

/* The unit reads with the quantity before it, "120.5 ltr", so the gap between
   the two columns is closed up. */
.soh-lines thead th.soh-lines__unit,
.soh-lines tbody td.soh-lines__unit { padding-left: .6mm; }

.soh-lines thead th.soh-lines__qty,
.soh-lines tbody td.soh-lines__qty { padding-right: .6mm; }

/* The ledger should never let a shelf go below zero. When one has, the figure
   is set heavy so it is found on a page of ordinary ones. */
.soh-neg { font-weight: 700; }

.soh-total td { padding-top: .6mm; }

.soh-total__cap {
  text-align: right;
  font-size: 6.5pt;
  font-weight: 700;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--ink-3);
}

/* The rule sits over the figure it totals and no wider, which is how a sum is
   drawn by hand. */
.soh-total td.soh-lines__qty {
  font-weight: 700;
  border-top: .6pt solid var(--rule-2);
}

.soh-total td.soh-lines__unit { color: var(--ink-2); }

.soh-empty {
  margin: 6mm 0 0;
  padding: 8mm 6mm;
  border: .8pt dashed var(--rule-2);
  border-radius: 1.2mm;
  text-align: center;
  font-size: 9pt;
  color: var(--ink-2);
}

/* Pushed to the foot of a one-sheet list, as the invoice's close is. */
.soh-close {
  margin-top: auto;
  padding-top: 4mm;
}

.soh-note {
  margin: 0;
  font-size: 7.5pt;
  color: var(--ink-3);
}

/* ============================================================================
   Paper.
   ========================================================================= */

@media print {
  /* A short top and bottom margin, and that is what keeps the browser's own
     date, tab title, page address and page count off the paper.

     A site cannot switch those off - that is deliberate, so nobody can hide
     where a printout came from - but the browser only draws them if the page
     margin leaves it room. Measured: at 10mm all four appear, at 8mm and below
     none of them do. 8mm keeps a 2mm cushion under that line and still clears
     the unprintable border of an ordinary office printer.

     The sides are free of that rule because nothing is ever drawn there, so
     they are set for the printer instead: 14mm.

     The client reported a very narrow strip trimmed off the right edge. It is
     not the layout - measured at the print geometry, the document fits the
     186mm the old 12mm margins left with nothing whatever past the edge, so
     the loss happens between the browser and the paper: feed skew, carriage
     registration, or a driver placing the sheet a shade off. None of those are
     addressable in CSS and all of them are absorbed by a wider margin. 14mm is
     the most the layout takes without the columns starting to strain, measured
     by reflowing it at 186, 184, 182 and 180mm; 182mm is the last width with
     nothing over the edge at all.

     Keep this equal to --sheet-p, which is the same margin drawn on screen.

     There is no page number, by request. The strip above the column headings
     names the invoice on every sheet instead, which is what a loose page needs.
     A page number would have to live in a margin box here, and a margin box is
     the browser's own footer slot - the thing being kept off the page. */
  @page {
    size: A4 portrait;
    margin: 8mm 14mm;
  }

  /* The document is black on white whatever the reader has the application set
     to. Without this the browser paints its own surfaces to match a dark
     theme, and the page margin prints as a solid black band round the sheet.

     `:root` twice is deliberate. The dark theme is switched on by
     `:root[data-theme="dark"]`, or `:root:not([data-theme="light"])` when it
     follows the computer, and both outrank a bare `:root` - so this rule, written
     as a bare `:root`, lost to both and every printout from a dark theme came
     out banded in black. Repeating it matches their weight, and this sheet is
     loaded after tokens.css, so on equal weight it wins. */
  :root:root { color-scheme: light; }

  /* The application's own background, off. The body carries a fixed gradient
     for the screen, and a fixed background in paged media is painted onto
     every sheet: it came out as a grey wash across the foot of the last page.
     This sheet is loaded after base.css, so ordinary order wins and no
     !important is needed. */
  html,
  body {
    background: #fff;
    background-image: none;
    min-height: 0;
  }

  .print-page {
    background: #fff;
    padding: 0;
    min-height: 0;
  }

  .print-bar,
  .print-hint { display: none; }

  /* The page box supplies the margin, so the sheet is only its contents. It has
     to be the page box and not padding here: padding is drawn once at the top
     of the first fragment and once at the foot of the last, so a second page
     would start hard against the edge of the paper.

     One page tall at least, so a short invoice still has free space for the
     close to be pushed into and the signature lands at the foot of the sheet
     rather than under the last line. Measured in vh rather than millimetres:
     in paged media that is the page area, already less the margins, so it
     fills the page exactly instead of spilling a blank second one. */
  .inv-sheet {
    width: auto;
    min-height: 100vh;
    margin: 0;
    padding: 0;
    box-shadow: none;

    /* Undoes the fit-to-screen scaling. It is set as an inline custom property
       by the script on the page and would otherwise still be in force here:
       printing from a narrow window would put a half-size invoice on a full
       sheet of paper. */
    zoom: 1;
  }

  /* Each copy starts its own sheet, and the last one does not push out a
     blank page after it. */
  .inv-sheet { break-after: page; }
  .inv-sheet:last-child { break-after: auto; }

  /* --- what happens when the lines run over a page --------------------- */

  /* The column names are repeated at the top of every sheet. Without this a
     second page is eight unlabelled columns of figures. */
  .inv-lines thead { display: table-header-group; }

  /* No row is split across the break. Half a description at the foot of one
     page and half at the head of the next is how a quantity gets read
     against the wrong product. */
  .inv-lines tr { break-inside: avoid; }

  /* The totals, the words that check them, the bank details and the
     signature move to the next sheet together or not at all. */
  .inv-close { break-inside: avoid; }

  .inv-parties,
  .inv-top { break-inside: avoid; }

  /* The category totals move to the next sheet together, so their head is
     never left at the foot of one page naming rows at the top of the next. */
  .pack-cats { break-inside: avoid; }

  /* A product's places move to the next sheet together, so its total is never
     read at the head of a page away from the lines it adds up. A product held
     in more places than a sheet has lines still breaks, because it has to. */
  .soh-group,
  .soh-summary,
  .soh-close { break-inside: avoid; }

  /* The masthead is not repeated, so the strip under the totals carries the
     invoice number and which copy it is. On a loose page it is the only thing
     that says what the sheet belongs to. */

  /* Backgrounds are the design, not decoration: the head band, the row
     banding and the filled total all have to survive the print. */
  .inv-lines thead th,
  .inv-lines tbody tr:nth-child(even) td,
  .soh-lines tbody:nth-of-type(even) tr:nth-child(n) td,
  .soh-stat--alert,
  .inv-grand {
    -webkit-print-color-adjust: exact;
    print-color-adjust: exact;
  }

  /* The saving keeps its green on the way to paper or to a PDF. Without this
     the browser is free to drop it, and on a price agreement the colour is
     carrying the one thing the customer was sent the page to see. */
  .inv-save,
  .inv-save__cell,
  .inv-save__pct,
  .inv-save__figure {
    -webkit-print-color-adjust: exact;
    print-color-adjust: exact;
  }
}

/* On a phone or a tablet the sheet is wider than the screen. It is **scaled**
   to fit, never reflowed: this is a preview of a fixed-width document, and a
   preview that rearranged itself to fit would stop being one, but one running
   off the side of the screen is no better. Scaling keeps every proportion and
   is what a PDF viewer does. See the zoom on .inv-sheet.

   It used to scroll instead, and at 375px that left 431px of a 794px page - more
   than half of it - off the screen with only a sideways scroll to find it. The
   toolbar fitted perfectly the whole time, which is what made it look deliberate.

   overflow-x is kept as the fallback for a browser that did not run the script.
   With the script running there is nothing left to scroll. */
@media screen and (max-width: 234mm) {
  .print-page {
    padding-left: 12px;
    padding-right: 12px;
    overflow-x: auto;
  }

  .print-bar,
  .print-hint { width: 100%; }

  /* Two rows rather than three: where it came from and what to do with it on
     the first, which copies underneath. Left to wrap on its own, the copies
     took a row of their own and pushed Print onto a third. */
  .print-bar {
    display: grid;
    grid-template-columns: 1fr auto;
    align-items: center;
    gap: 10px;
  }

  .print-bar__copies {
    grid-column: 1 / -1;
    grid-row: 2;
    margin-left: 0;
  }

  .print-bar__copy {
    flex: 1;
    text-align: center;
  }

  .inv-sheet { margin-inline: 0; }
}

/* Stock a sales order has spoken for, on the stock on hand sheet. Set lighter
   than the shelf figure beside it: it is a claim on that figure rather than a
   second quantity, and reading the two as one column of stock would double the
   sheet. */
.soh-held { color: var(--ink-2); }

/* The rate under the tax figure on a price agreement, so one column carries
   both what is charged and what it was worked out at. Set as a caption rather
   than a second figure: the amount is what is being checked. */
.inv-lines__at {
  display: block;
  font-size: 6.5pt;
  color: var(--ink-3);
}

/* --------------------------------------------------------------------------
   Reports on paper
   Every report prints through this: the same sheet, the same greys, the same
   margins as the documents, so a figure read off a report and a figure read
   off an invoice look like they came from one company.
   -------------------------------------------------------------------------- */

.rep-sheet .inv-lines { font-size: 8pt; }

/* The company keeps its side of the masthead whatever the report is called.

   The masthead gives the title whatever it asks for and the company the rest.
   An invoice's title is two words. "Slow and Non-moving Stock" asked for most
   of the sheet, and the company's name was set on three lines with its
   address on five beside a title that could perfectly well have wrapped.

   86mm is the logo, the gap, and enough beside them for the address to sit
   on its own three lines. It is a floor and not a share: a title of two
   words still leaves the company everything else, and a title of eighteen
   letters still fits on one line beside it, as it did before. Only a title
   too long for what is left goes onto a second line, which is what a title
   does. Tried at 94mm first, which kept the company's name on one line and
   broke "Cash and Bank Book" in two instead. */
.rep-sheet .inv-top { grid-template-columns: minmax(86mm, 1fr) auto; }

/* A report carries more figure columns than an invoice does: an ageing has
   eight of them. At the invoice's 21mm and 8pt that is 168mm of a 180mm page,
   and every customer's name wraps onto three lines.

   So the whole table is set smaller and tighter here. A width below what the
   figures actually need is ignored by the table, which is why the type and the
   padding have to come down with it rather than instead of it: at 7.5pt
   "2,64,600.00" fits 17mm and the names get the 40mm they need. */
.rep-lines { font-size: 7.5pt; }

.rep-lines thead th,
.rep-lines tbody td { padding-left: 1.2mm; padding-right: 1.2mm; }

.rep-lines .inv-lines__num { width: 17mm; }

/* The column being read down the page, so it gets what is left. */
.rep-lines .inv-lines__desc { width: 40mm; }

/* The handful of figures the sheet exists for, above the names. */
.rep-head {
  display: flex;
  flex-wrap: wrap;
  gap: 3mm 10mm;
  margin: 4mm 0 0;
  padding: 3mm 4mm;
  border: .8pt solid var(--rule);
  border-radius: 1.2mm;
}

.rep-head__stat { display: flex; flex-direction: column; gap: .4mm; }

.rep-head__label {
  font-size: 6.5pt;
  font-weight: 700;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--ink-3);
}

.rep-head__value { font-size: 12pt; font-weight: 700; }
.rep-head__note { font-size: 6.5pt; color: var(--ink-3); }

/* The customer's code under their name, quieter than it. */
.rep-lines__code {
  margin-left: 1.2mm;
  font-size: 6.5pt;
  font-weight: 400;
  color: var(--ink-3);
  white-space: nowrap;
}

.rep-lines__total { font-weight: 700; }

/* A warehouse or a category, with its own total, over the rows it gathers. */
.rep-group td {
  padding-top: 2mm;
  background: var(--band-2);
  font-weight: 700;
  border-top: .5pt solid var(--rule);
}

/* An area of the warehouse above it: the band one step quieter, unfilled and
   set in, so the warehouse still heads its areas. */
.rep-group--area td {
  background: none;
  border-top: .3pt solid var(--rule);
}

.rep-group--area td:first-child { padding-left: 4mm; }

/* The whole book, ruled off under the rows it adds up. */
.rep-total td {
  padding-top: 1.6mm;
  border-top: .8pt solid var(--ink);
  font-weight: 700;
}

.inv-lines tbody tr.rep-total td { background: none; }

.rep-total__cap {
  text-align: right;
  font-size: 6.5pt;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--ink-3);
}

/* A second table under the first, where a report carries an exception list as
   well as its figures. Ruled off by the gap rather than by a heading: the
   banner row inside it already says what it is. */
.rep-lines--next { margin-top: 7mm; }

/* A sheet that is nearly all figures: the stock movement, with ten of them
   beside the product. Narrower columns than a money table needs, because a
   quantity is five characters where an amount is eleven, and the room goes to
   the name. The last column is the one that is money. */
.rep-lines--figures .inv-lines__num { width: 14mm; }
.rep-lines--figures .inv-lines__num:last-child { width: 21mm; }
.rep-lines--figures .inv-lines__desc { width: auto; }

/* A register: a date, a number, a name and six figures. The date and the
   number are fixed and short, so they are told to be, and the name takes
   what is left. */
.rep-lines--register { font-size: 7pt; }
.rep-lines--register .inv-lines__num { width: 15.5mm; }
.rep-lines--register .inv-lines__desc { width: auto; }
.rep-lines--register td:first-child,
.rep-lines--register th:first-child { width: 15mm; white-space: nowrap; }

/* The number, and only the number. Counted from the left in a row of the
   foot, the second cell is not the number at all: the caption spans the
   first three and the second is the taxable total, which was being held to
   the width of a document number. */
.rep-lines--register tr:not(.rep-total) > td:nth-child(2),
.rep-lines--register th:nth-child(2) { width: 30mm; }

/* On its side there is room for what sits under a number, "credit note,"
   and the invoice it is against, to stay on one line. */
.print-page--wide .rep-lines--register tr:not(.rep-total) > td:nth-child(2),
.print-page--wide .rep-lines--register th:nth-child(2) { width: 38mm; }

/* A place of supply: a code and a state, kept on one line so a column sized
   by the figures beside it does not break it between the two. */
.rep-lines__place { white-space: nowrap; }

/* The open order book: a product and five quantities, an order to a band.

   The product takes whatever the figures leave. An order and its lines are
   kept on one page where they fit: a band left at the foot of a sheet with
   its lines over the page reads as an order with nothing on it. */
.rep-lines--orders .inv-lines__desc { width: auto; }
.rep-order__customer { margin-left: 1.6mm; }

/* What is held sometimes carries a line under it, "1,380 still to make",
   which at the width of a bare quantity folded onto three. The column is
   given room for it on one. */
.rep-lines--orders tr:not(.rep-group):not(.rep-total):not(.inv-lines__mark) > td:nth-child(5),
.rep-lines--orders tr:not(.inv-lines__mark) > th:nth-child(5) { width: 27mm; }

.rep-lines--orders .rep-lines__code--under { white-space: nowrap; }

@media print {
  .rep-order { break-inside: avoid; }
}

/* What a customer was sold, on a sheet turned on its side: an item, how much
   of it, what it went out in, and the money.

   The item takes whatever the rest leave. The packing is the one column of
   words among the figures, so it is given a width that holds "40 Cartons of
   12 nos (2 part filled)" on a line and is allowed to wrap past that, and the
   quantity is wider than a bare figure because it carries its unit. Invoice by
   invoice there are two more figure columns, and the packing gives up some of
   its room to pay for them. */
.rep-lines--sold .inv-lines__desc { width: auto; }
.rep-lines--sold .inv-lines__num { width: 24mm; }
.rep-lines--sold .rep-lines__pack { width: 62mm; text-align: left; }
.rep-lines--sold-lines .inv-lines__num { width: 21mm; }
.rep-lines--sold-lines .rep-lines__pack { width: 54mm; }

/* One way an item went out, or one unit of a total, on a line of its own. */
.rep-lines__way { display: block; }

/* What came back, under the quantity it came off. Kept whole: the widths
   above are minimums, so the column gives it the room, and "5,511 sold, 20"
   over "returned" read as two figures. */
.rep-lines--sold .inv-lines__num .rep-lines__code--under { white-space: nowrap; }

/* Slow stock: a product, how much and what it cost, and three things about
   when. The two date columns hold a date and sometimes a line of words under
   it, so they are given room for the words and the product takes the rest. */
.rep-lines--slow .inv-lines__desc { width: auto; }
.rep-lines--slow .rep-lines__when { width: 34mm; }

/* Production cost and yield, on a sheet turned on its side.

   The runs: a date, what was made, and eight figures. The date column holds
   the run's reference and warehouse under it, so it is given room for them;
   the product takes what is left. Figures are set a little wider than a
   register's, because a cost for one unit runs to four places.

   What each run took: an input and six figures, with the product taking the
   rest of a sheet that has room to spare. */
.rep-lines--runs .inv-lines__num { width: 22mm; }
.rep-lines--runs .inv-lines__desc { width: auto; }
.rep-lines--runs td:first-child,
.rep-lines--runs th:first-child { width: 34mm; }

.rep-lines--took .inv-lines__num { width: 26mm; }
.rep-lines--took .inv-lines__desc { width: auto; }

/* A book of entries: a date, who and how, our own number, and three figures.

   The date and the number are set to what they need and no more, and never
   wrap: a receipt number broken over two lines cannot be read down a column.
   Everything they leave goes to the particulars, which is the one column whose
   length is not the company's to decide. */
.rep-lines--book td:first-child,
.rep-lines--book th:first-child { width: 19mm; white-space: nowrap; }

.rep-lines--book .inv-lines__desc { width: auto; }

/* The same width for the three figures on every account's page, wide enough
   for a balance in tens of crores. Left to size themselves, a quiet account
   set narrow columns and a busy one wide, and the figures of one page did not
   stand under the figures of the page above it. */
.rep-lines--book .inv-lines__num { width: 25mm; }

.rep-lines--book tr:not(.rep-total):not(.inv-lines__mark) > td:nth-child(3),
.rep-lines--book tr:not(.inv-lines__mark) > th:nth-child(3) { width: 30mm; white-space: nowrap; }

/* A second line under a number or a name: what the row is, or whose GSTIN.
   On its own line rather than beside it, so a long one cannot push the
   figures. */
.rep-lines__code--under { display: block; margin-left: 0; white-space: normal; }

/* A second and third total under the first: the notes, then the net. Only
   the first is ruled off from the rows; these belong with it. */
.rep-total--more td { border-top: 0; padding-top: .6mm; }

/* What a sheet is not, before any of its figures. The trading summary is not
   a profit and loss account, and says so first, where it would be taken for one. */
.rep-not { margin: 3mm 0 0; font-weight: 700; color: var(--ink); }

/* An expense head, stood in under the line it adds up to. */
.inv-lines td.rep-lines__indent { padding-left: 6mm; }

/* A month with nothing in it, said once across the row. */
.inv-lines td.rep-lines__quiet { color: var(--ink-3); font-style: italic; }

/* --- a sheet that is wider than it is long --------------------------------

   The two registers, the stock movement and the two ageing sheets: six, seven
   and eight columns of figures beside a name. Upright, A4 holds them for a
   small month and for no other. With a year's figures in crores the last
   column went over the edge of the paper, where a PDF simply cuts it off, and
   the name beside the figures was squeezed to a word a line.

   Turned on its side the same sheet has 269mm between its margins instead of
   182, and the purchase register has room to split its tax by head the way
   its screen does.

   Named, so that only these turn. Every other document here is a letter, and
   an invoice that came out sideways because a report did would be a worse
   bug than the one this fixes. The margins are the ones every other sheet
   prints with, for the reasons given at the page rule below. */
.print-page--wide { --sheet-w: 297mm; }
.print-page--wide .inv-sheet { min-height: 210mm; }

@media print {
  @page wide {
    size: A4 landscape;
    margin: 8mm 14mm;
  }

  .print-page--wide { page: wide; }

  /* And the document it is in, not only the sheet.

     The router leaves an element after every page's content, the one that
     moves focus to the heading after navigation. It is empty and it is
     outside the sheet, so on a sheet turned by name it belonged to the
     default page instead, which is upright. A change of page name forces a
     break, and what the break led to was that one empty element: a blank
     portrait page at the end of every report printed on its side.

     Naming the page on the body puts everything in the document on the same
     page, so there is no change of name and nothing to break for. Found by
     printing the application's own markup and counting three pages for a
     report of two. */
  body:has(.print-page--wide) { page: wide; }

  /* Not a page tall at least, the way an upright sheet is. That floor is
     written in vh, and on paper vh is measured off the page the document
     starts from by default, which is the upright one: 281mm of floor on a
     page 194mm tall, so a register of three lines printed its closing words
     alone on a second sheet. Measured by printing it. Without a floor the
     words simply follow the table, which is where a report wants them. */
  .print-page--wide .inv-sheet { min-height: 0; }
}

/* Unless it turns out to be the first one after all. A sheet of several
   tables prints only the ones that have rows, so which of them comes first is
   not known when the markup is written; the one that lands straight under the
   figures takes the ordinary gap instead of the wide one. */
.rep-head + .rep-lines--next { margin-top: 4mm; }

@media print {
  /* A header with no rows under it is worse than a short page, so the banner
     and the first rows travel together. The table itself is allowed to break:
     an exception list can be longer than a page and still has to print. */
  .rep-lines--next thead { break-after: avoid; }
}

/* --------------------------------------------------------------------------
   The packing sheet
   Not a tax document: no rule shapes it, and the only reader is standing at a
   bench with a box in one hand. So the type is larger than the invoice's and
   the figures are larger still, at the cost of fitting less on the page.
   -------------------------------------------------------------------------- */

.pack-sheet .inv-lines { font-size: 9pt; }

.pack-sheet .pack-lines__qty {
  font-size: 11pt;
  font-weight: 700;
}

/* What the line comes to in the other unit, where the box used to be named.
   Set quieter than the quantity beside it on purpose: the packer counts
   bottles, and this figure is for whoever is loading the lorry or squaring the
   paperwork against it. Wider than a plain figure column because it carries its
   unit as well. */
.pack-lines__comes {
  width: 24mm;
  font-size: 9pt;
  font-weight: 500;
  color: var(--ink-2);
}

.pack-lines__how { line-height: 1.45; }

/* Each half of the instruction, so "166 cartons of 12" and "and 8 loose" wrap
   as units rather than breaking after a figure. The space between them is a
   real one in the markup rather than a margin here, so the line survives being
   copied out of the PDF. */
.pack-lines__part { display: inline-block; }
.pack-lines__how strong { font-size: 10.5pt; }

/* What the whole document comes to, under the lines.

   Modelled on the total row of the stock sheet: a rule across the figures, a
   small caption where the description would be, and the figures themselves
   larger than the lines above them, because this is the row somebody checks
   the finished job against.

   Every cell can hold more than one line. A sheet with bottles in numbers and
   oil in kilograms has two quantity totals, and one packed into cartons and
   barrels has two packing totals, so each group is a block of its own rather
   than a list run together with commas. */
.pack-total td {
  padding-top: 1.6mm;
  border-top: .8pt solid var(--rule);
  vertical-align: top;
}

/* Never banded. The row is already set apart by its rule, and the stripe would
   read as one more line of goods. */
.inv-lines tbody tr.pack-total td { background: none; }

.pack-total__cap {
  text-align: right;
  font-size: 6.5pt;
  font-weight: 700;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--ink-3);
}

.pack-total__group { display: block; }
.pack-total__group + .pack-total__group { margin-top: .8mm; }

.pack-total__packs { font-size: 9pt; }
.pack-total__packs strong { font-size: 11pt; }

.pack-total__figures { font-size: 10pt; font-weight: 700; }

/* Why nine cartons when the line above says eight: the part filled one. Kept
   on the same line as the count, because a sheet packed into three kinds of box
   would otherwise give six lines of total row to a parenthesis. */
.pack-total__note {
  font-size: 6.5pt;
  font-weight: 400;
  color: var(--ink-3);
  white-space: nowrap;
}

/* The totals again, by product category, at the foot of the sheet.

   Pushed down rather than left under the lines. The auto margin takes whatever
   the page has left over, so on an ordinary sheet there is a clear band of
   white between the goods and this, and it cannot be mistaken for more lines.
   The padding is the floor: on a sheet full of goods, where there is no free
   space to take, that is the gap it still gets. Printing adds the rest, by
   moving the whole block to the next page sooner than squeeze it in.

   A table of its own, in a box of its own, so it can be moved. The box is what
   carries the gap: a table with collapsed borders ignores its own padding, so
   the floor measured zero when the page was full. Its figure columns carry the
   same classes as the ones above, which are set in millimetres, so the right
   hand edge still lines up down the page. */
.pack-cats {
  margin-top: auto;
  padding-top: 12mm;
}

/* The table's own top margin would be added to the gap above it. */
.pack-cats .inv-lines { margin-top: 0; }

/* The close follows the categories rather than being pushed down itself. Two
   auto margins would share the free space between them and leave a gap in the
   middle of the foot. Its own padding opens enough air for the note to read as
   a different thing from the row of figures above it. */
.pack-sheet .inv-close {
  margin-top: 0;
  padding-top: 7mm;
}

.pack-cats__head th.inv-lines__num { text-align: right; }

/* Not banded. These are a handful of rows read one at a time, and the stripe
   belongs to the long list of goods above. */
.pack-cats tbody td { background: none; }

/* Wide enough to hold a category and its count on one line, and no wider: what
   is worth reading in this block is the figures. */
.pack-cats__name {
  width: 52mm;
  font-weight: 600;
}

/* How many products the row is the total of, so a figure that looks large can
   be seen to be several lines rather than one. */
.pack-cats__count {
  font-size: 6.5pt;
  font-weight: 400;
  color: var(--ink-3);
  white-space: nowrap;
}

/* Between the lines and the total in weight: a share of the total, so it
   should not be read as either. */
.pack-cats__figures { font-size: 9.5pt; font-weight: 600; }

.pack-cats .pack-total__packs strong { font-size: 10pt; }

/* Nothing to say in this cell: no packing set out, or nothing that converts.
   Light, so an empty cell is not read as a figure in the weight of the ones
   beside it. */
.pack-cats__none {
  font-weight: 400;
  color: var(--ink-3);
}

/* A line the plan says nothing about. Not an error and not hidden: the packer
   has to see it and ask, so it is set apart rather than played down. */
.pack-lines__ask {
  font-weight: 700;
  text-transform: uppercase;
  font-size: 7.5pt;
  letter-spacing: .06em;
}

/* What to collect before starting. At the top because it is the first thing
   done, and the only part of the sheet read while walking. */
.pack-fetch {
  margin: 3mm 0 0;
  padding: 2.6mm 3mm;
  border: .8pt solid var(--rule-2);
}

.pack-fetch__cap {
  margin: 0 0 1.6mm;
  font-size: 7.5pt;
  font-weight: 700;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--ink-3);
}

.pack-fetch__list {
  display: flex;
  flex-wrap: wrap;
  gap: 2mm 8mm;
  margin: 0;
  padding: 0;
  list-style: none;
}

.pack-fetch__item {
  display: flex;
  align-items: baseline;
  gap: 2mm;
}

.pack-fetch__count {
  font-size: 13pt;
  font-weight: 700;
}

.pack-fetch__name { font-size: 9pt; }

.pack-fetch__part {
  display: block;
  font-size: 7pt;
  color: var(--ink-3);
}

/* Three ruled lines at the foot. A packing sheet is signed by whoever packed
   it and whoever checked it, which is the whole reason it is printed rather
   than read off a screen. */
.pack-sign {
  display: flex;
  gap: 8mm;
  margin-top: 8mm;
}

.pack-sign__line {
  flex: 1;
  margin: 0;
  padding-top: 8mm;
  border-bottom: .8pt solid var(--ink-2);
}

.pack-sign__line span {
  font-size: 7.5pt;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--ink-3);
}
