@layer components {

  /* The main region of a bill's page: the processing placeholder while the
     uploaded document runs through the pipeline, then the invoice page's
     two-column layout — the editor (supplier, line items, totals) on the
     left, the document itself on the right. Transparent — each section
     inside brings its own card styling. */
  .bill-body {
    display: flex;
    flex-direction: column;
  }

  /* On a phone the body dissolves like the layout it wraps (see invoice.css),
     and the processing placeholder takes the main column's place in the
     page's order. */
  @media (width < 768px) {
    .bill-body {
      display: contents;
    }

    .bill-processing {
      margin-block-start: 2rem;
      order: 5;
    }
  }

  /* The supplier card opens the main column here, where the invoice's header
     card would; the layout's own top padding is all the space it needs. */
  .bill-body .inv-parties {
    margin-block-start: 0;
  }

  .bill-processing {
    align-items: center;
    background: var(--color-surface);
    border-radius: var(--radius-md);
    color: var(--color-ink-muted);
    display: flex;
    flex-direction: column;
    font-size: 1.125rem;
    gap: 1.5rem;
    margin-block-start: 2rem;
    padding: 4rem 1.5rem;
    text-align: center;
  }

  .bill-processing__text {
    margin: 0;
  }

  .bill-processing__text--deferred {
    font-size: 0.9375rem;
    max-inline-size: 40ch;
  }

  /* The card's label names what the document is and when it was issued, with
     the inbound-document glyph in front of it. */
  .inv-sidebar__due-label.bill-summary {
    align-items: center;
    display: flex;
    gap: 0.5rem;
  }

  /* The same label as a button, where the kind can be changed by hand: it
     keeps the label's look, with a chevron after it saying it opens. */
  .bill-type {
    position: relative;
  }

  .bill-type__button {
    background: none;
    border: none;
    border-radius: var(--radius-xs);
    cursor: pointer;
    font-family: inherit;
    padding: 0;
    text-align: start;

    &:hover {
      color: var(--color-ink-inverted);
    }

    &:disabled {
      cursor: default;
    }
  }

  .bill-type__menu {
    inset-block-start: calc(100% + 0.25rem);
    inset-inline-start: 0;
    min-inline-size: 14rem;
  }

  /* How the bill was paid, under its title: a pill in the brand's tint, so
     it reads as a fact about the bill rather than as a caption. Unknown is
     the same pill drawn in outline — there, but nothing to call attention
     to; the canvas under the header is already the neutral tint. */
  .page-header__subtitle.bill-payment {
    background: var(--color-brand-tint);
    border-radius: var(--radius-pill);
    color: var(--color-brand-strong);
    font-size: 0.875rem;
    font-weight: 600;
    inline-size: fit-content;
    padding: 0.25rem 0.75rem;
  }

  .page-header__subtitle.bill-payment--unknown {
    background: none;
    border: 1px dashed var(--color-border-strong);
    color: var(--color-ink-muted);
  }

  /* The pill beside the print button in the bill's header, stretched to
     the button's height — over the centring `.inv-head-actions` gives the
     row, which loads after this file. */
  .inv-head-actions.bill-head-actions {
    align-items: stretch;

    .page-header__subtitle.bill-payment {
      align-items: center;
      display: flex;
      margin: 0;
    }

    .bill-payment-method {
      display: flex;
    }
  }

  /* The same pill as a button while the bill can be edited: a chevron after
     it says it opens the menu of ways to have paid. The second class beats
     the list cell's grid `.bill-payment` sets further down. */
  .bill-payment-method {
    position: relative;
  }

  .bill-payment.bill-payment-method__button {
    align-items: center;
    border: none;
    cursor: pointer;
    display: inline-flex;
    font-family: inherit;
    gap: 0.375rem;

    &:hover {
      color: var(--color-brand);
    }

    &:disabled {
      cursor: default;
    }
  }

  .bill-payment-method__menu {
    inset-block-start: calc(100% + 0.25rem);
    inset-inline-start: 0;
    min-inline-size: 14rem;
  }

  /* A bill's amount stays in view while its side column scrolls by. The
     side column, taller than the viewport once it holds the preview, gives
     up the stickiness `invoice.css` gives it, and the amount is pinned at
     the sidebar's top while the payment and the preview scroll up under
     it; the danger zone follows straight after them. */
  @media (width >= 1024px) {
    .inv-layout__side-col:has(.bill-due) {
      position: static;
    }

    .inv-due-wrap.bill-due {
      inset-block-start: calc(var(--nav-height) + 1.5rem);
      position: sticky;
      z-index: var(--z-sticky);
    }
  }

  /* The final document's card in the side column: title, the preview and the
     download under it. Two classes so it beats `.inv-sidebar__section`, which
     `sidebar.css` loads after this file. */
  .inv-sidebar__section.bill-download {
    align-items: stretch;
    gap: 1rem;
  }

  .bill-download__btn {
    margin-block-start: 0.25rem;
  }

  /* On the phone the preview shrinks to a strip beside its title and button,
     so the editor is one thumb-scroll away. */
  @media (width < 768px) {
    .inv-sidebar__section.bill-download {
      align-items: center;
      column-gap: 1rem;
      display: grid;
      grid-template-columns: 6rem minmax(0, 1fr);
      row-gap: 0.75rem;
    }

    .bill-download .inv-sidebar__section-title,
    .bill-download__label,
    .bill-download__btn {
      grid-column: 2;
    }

    .bill-download .inv-sidebar__section-title {
      align-self: start;
    }

    .bill-download__btn {
      align-self: end;
      margin-block-start: 0;
    }

    /* The grid item is the button around the preview, not the frame itself —
       so the button carries the placement, else the frame would fall out of
       its column. */
    .bill-download__zoom {
      align-self: stretch;
      grid-column: 1;
      grid-row: 1 / -1;
    }

    /* A fixed-height strip, whatever the document's proportions: a tall
       receipt is cropped from the top rather than stretching the card. */
    .bill-download__frame {
      aspect-ratio: auto;
      block-size: 8rem;
      inline-size: 6rem;
    }

    /* Two classes: the base `.bill-download__preview` rule comes later in
       this file and would otherwise win the tie. */
    .bill-download__frame .bill-download__preview {
      block-size: 100%;
      max-block-size: none;
      object-fit: cover;
      object-position: top;
    }
  }

  /* The preview is wrapped in a button so it can be enlarged from the
     keyboard too. The button draws nothing and sets no size of its own —
     the preview frame inside carries the dimensions. */
  .bill-download__zoom {
    align-self: center;
    background: none;
    border: none;
    cursor: zoom-in;
    display: block;
    padding: 0;
  }

  /* The preview is stored at up to 1500px a side; on the page it reads as a
     thumbnail of the document, scaled down to a readable glance. The frame
     fits a 20rem × 24rem box and gets the picture's own proportions from
     `bill_preview_tag`, so it holds the picture's place — under a sliding
     shimmer — until the image has loaded and the `image-load` controller
     marks it loaded. */
  .bill-download__frame {
    --bill-preview-inline-size: 20rem;
    --bill-preview-shade: var(--color-border-subtle);
    --bill-preview-highlight: var(--color-surface-tint);

    align-self: center;
    animation: bill-preview-shimmer 1.6s ease-in-out infinite;
    aspect-ratio: var(--bill-preview-aspect-ratio, auto);
    background: linear-gradient(100deg, var(--bill-preview-shade) 40%, var(--bill-preview-highlight) 50%, var(--bill-preview-shade) 60%) 100% 0 / 300% 100%;
    border: 1px solid var(--color-border-subtle);
    border-radius: var(--radius-sm);
    box-shadow: var(--shadow-popover);
    inline-size: var(--bill-preview-inline-size);
    margin: 0;
    max-inline-size: 100%;
    overflow: hidden;

    &.bill-download__frame--loaded {
      animation: none;
      background: var(--color-surface);
    }
  }

  .bill-download__preview {
    block-size: auto;
    display: block;
    inline-size: 100%;
    max-block-size: 24rem;
    object-fit: contain;
    opacity: 0;
    transition: opacity 200ms ease-out;

    .bill-download__frame--loaded & {
      opacity: 1;
    }
  }

  @keyframes bill-preview-shimmer {
    from { background-position: 100% 0; }
    to   { background-position: 0 0; }
  }

  .bill-download__label {
    color: var(--color-ink-secondary);
    font-size: 0.875rem;
    margin: 0;
  }

  /* ─── Received documents list — the processing row ───────

     While the uploaded document is being read, the row has nothing to say:
     a grey sheen sweeps across its background from left to right (the same
     keyframes as the document preview above), and in the cells the reading
     has yet to fill, three dots pulse — one after another, so the row reads
     as work in progress, not as an answer. */

  /* ─── Received documents list ──────────────── */

  /* A bill is listed by who it is from, then the date, the type, the
     payment and the amount. The type is an icon and takes a narrow fixed
     column; the date is twelve characters and fixed to that, for the same
     reason the others are fractions: every row is its own grid, and a column
     sized to its content would start somewhere else in every row. */
  .doc-headers.doc-headers--bills,
  .doc-row.doc-row--bills {
    --doc-columns: minmax(0, 2fr) 7.5rem 4.5rem minmax(0, 1.5fr) minmax(0, 0.9fr);
  }

  .doc-row--bills .doc-col--date,
  .doc-row--bills .doc-col--amount {
    white-space: nowrap;
  }

  .doc-row--bills .doc-cell--client {
    text-align: start;
  }

  /* The supplier's name is the row's link, in the brand as a link is. */
  .doc-row--bills .doc-cell--client a {
    color: var(--color-brand);
    text-decoration: none;

    &:hover {
      text-decoration: underline;
    }
  }

  /* A type or payment icon, centred in its cell, in the ink the type used to
     be printed in, and its name in a bubble beside it on hover. */
  .doc-icon {
    color: var(--color-ink-secondary);
    cursor: help;
    display: inline-flex;
    position: relative;
    vertical-align: middle;
  }

  /* To the icon's left and level with it: a row is taller than the bubble,
     and the cells to the left of both icon columns are wide enough for it,
     so the table's `overflow: hidden` — which would cut off a bubble opening
     above the first row or below the last — never reaches it. */
  .doc-icon__bubble {
    background: var(--color-surface-inverted);
    border-radius: var(--radius-sm);
    color: var(--color-ink-inverted);
    display: none;
    font-size: 0.75rem;
    font-weight: 600;
    inline-size: max-content;
    inset-block-start: 50%;
    inset-inline-end: calc(100% + 0.5rem);
    line-height: 1.4;
    padding: 0.3rem 0.6rem;
    pointer-events: none;
    position: absolute;
    transform: translateY(-50%);
    z-index: var(--z-popover);
  }

  .doc-icon:hover .doc-icon__bubble {
    display: block;
  }

  .doc-row--processing {
    --doc-processing-shade: var(--color-surface-tint);

    animation: bill-preview-shimmer 2.4s ease-in-out infinite;
    background: linear-gradient(90deg, var(--color-surface) 35%, var(--doc-processing-shade) 50%, var(--color-surface) 65%) 100% 0 / 300% 100%;
  }

  .doc-dots {
    --doc-dot-size: 0.4em;

    align-items: center;
    display: inline-flex;
    gap: calc(var(--doc-dot-size) * 0.75);
    vertical-align: middle;
  }

  .doc-dots__dot {
    animation: doc-dot-pulse 1.2s ease-in-out infinite;
    background: var(--color-ink-faint);
    block-size: var(--doc-dot-size);
    border-radius: 50%;
    display: block;
    inline-size: var(--doc-dot-size);

    &:nth-child(2) {
      animation-delay: 0.2s;
    }

    &:nth-child(3) {
      animation-delay: 0.4s;
    }
  }

  @keyframes doc-dot-pulse {
    0%, 60%, 100% { transform: scale(0.65); opacity: 0.55; }
    30%           { transform: scale(1);    opacity: 1; }
  }

  /* ─── Received documents list — narrower ─────

     On a tablet the row keeps its columns, narrower. On a phone the date is
     gone (`documents.css`) and the row becomes a card of two lines: who it is
     from and what it comes to, then the type's icon and where the payment
     stands, under the name. The amount's column is sized to the amount, so
     the name has the rest of the row's width. */

  @media (768px <= width < 1024px) {
    .doc-headers.doc-headers--bills,
    .doc-row.doc-row--bills {
      --doc-columns: minmax(0, 1fr) 7.5rem 4.5rem minmax(0, 0.9fr) minmax(0, 0.6fr);
    }
  }

  @media (width < 768px) {
    .doc-headers.doc-headers--bills,
    .doc-row.doc-row--bills {
      --doc-columns: 2rem minmax(0, 1fr) auto;
    }

    .doc-row.doc-row--bills {
      row-gap: 0.375rem;
    }

    /* Over a card of two lines only the supplier and the amount have a
       column to head. */
    .doc-headers--bills .doc-col--type,
    .doc-headers--bills .doc-col--payment {
      display: none;
    }

    .doc-headers--bills .doc-col--supplier,
    .doc-row--bills .doc-cell--client {
      grid-column: 2 / 4;
      grid-row: 1;
    }

    .doc-headers--bills .doc-col--amount,
    .doc-row--bills .doc-col--amount {
      grid-column: 4;
      grid-row: 1;
      padding-inline-start: 0.75rem;
    }

    .doc-row--bills .doc-col--amount {
      font-size: 0.9375rem;
    }

    .doc-row--bills .doc-col--type {
      grid-column: 2;
      grid-row: 2;
      text-align: start;
    }

    /* The payment's state beside the type, without the detail a wider row
       has room for. */
    .doc-row--bills .doc-col--payment {
      grid-column: 3 / -1;
      grid-row: 2;
      justify-self: start;
      text-align: start;
    }

    .doc-row--bills .bill-payment__detail {
      display: none;
    }
  }

  /* ─── Where the payment stands ──────────── */

  /* The list's payment cell: the state on top, in the colour that says
     whether anything is to be done, the detail under it. */
  .bill-payment {
    display: grid;
    font-size: 0.875rem;
    line-height: 1.3;
    text-align: start;
  }

  .bill-payment__state {
    font-weight: 600;
  }

  .bill-payment__detail {
    color: var(--color-ink-muted);
    font-size: 0.8125rem;
    overflow: hidden;
    text-overflow: ellipsis;
  }

  .bill-payment--paid .bill-payment__state,
  .bill-payment--paid_otherwise .bill-payment__state {
    color: var(--color-positive);
  }

  .bill-payment--proposed .bill-payment__state,
  .bill-payment--partly_paid .bill-payment__state,
  .bill-payment--unpaid .bill-payment__state,
  .bill-payment--warning {
    color: var(--color-warning);
  }

  .bill-payment--awaiting_statement .bill-payment__state,
  .bill-payment--due .bill-payment__state,
  .bill-payment--cash .bill-payment__state {
    color: var(--color-ink-secondary);
    font-weight: 400;
  }

  /* The bill page's account of its payment. */
  .bill-settlements {
    display: grid;
    gap: 0.75rem;
  }

  .bill-settlements__state {
    margin: 0;
  }

  .bill-settlement {
    align-items: center;
    display: flex;
    flex-wrap: wrap;
    font-size: 0.875rem;
    gap: 0.25rem 0.75rem;
    justify-content: space-between;
  }

  .bill-settlement__note {
    color: var(--color-ink-muted);
    flex-basis: 100%;
  }

  .bill-settlement__remove {
    background: none;
    border: none;
    color: var(--color-link);
    cursor: pointer;
    font-size: 0.8125rem;
    padding: 0;
  }

  /* ─── Paying the bill ───────────────────── */

  .bill-pay {
    display: grid;
    gap: 0.75rem;
    justify-items: center;
    margin-block-start: 1rem;
  }

  .bill-pay__label {
    justify-self: start;
  }

  .bill-pay__qr {
    background: var(--color-code-surface);
    block-size: 10rem;
    border-radius: var(--radius-sm);
    inline-size: 10rem;
    padding: 0.5rem;
  }
}
