@layer components {
  /* Title on the left, the "i" help on the right — the row carries the margin,
     not the title itself. */
  .inv-items__header {
    align-items: center;
    display: flex;
    gap: 0.5rem;
    justify-content: space-between;
    margin-block-end: 1rem;
    position: relative;
  }

  .inv-items__title {
    color: var(--color-ink);
    font-size: 0.9375rem;
    font-weight: 700;
    margin: 0;
  }

  .inv-help {
    display: flex;
  }

  .inv-help__btn {
    align-items: center;
    background: none;
    border: none;
    border-radius: 50%;
    color: var(--color-ink-faint);
    cursor: pointer;
    display: flex;
    justify-content: center;
    padding: 0.125rem;
    transition: color 0.15s;
  }

  .inv-help__btn:hover,
  .inv-help__btn[aria-expanded="true"] {
    color: var(--color-brand);
  }

  /* The panel is anchored to the whole header row, not the icon itself: `left`
     and `right` at 0 give it exactly the card's inner width, `max-width` pulls
     it in on a large display and `margin-left: auto` pushes it right, under
     the icon. No need to reckon with the viewport width — on a phone it simply
     fits inside the card. */
  .inv-help__panel {
    inset-block-start: calc(100% + 0.5rem);
    inset-inline-end: 0;
    inset-inline-start: 0;
    margin-inline-start: auto;
    max-inline-size: 22rem;
    padding: 0.875rem 1rem;
  }

  /* On a phone the panel is the only thing on screen — the type steps up a
     size so it reads without squinting. */
  .inv-help__title {
    color: var(--color-ink);
    font-size: 0.8125rem;
    font-weight: 700;
    margin: 0 0 0.75rem;

    @media (width < 480px) {
      font-size: 0.9375rem;
    }
  }

  /* Rate and its scope side by side — the percentage keeps a narrow column,
     the text takes the rest. */
  .inv-help__rates {
    display: grid;
    gap: 0.5rem 0.75rem;
    grid-template-columns: auto 1fr;
    margin: 0;
  }

  .inv-help__rate {
    color: var(--color-brand);
    font-family: var(--font-mono);
    font-size: 0.8125rem;
    font-weight: 700;
    white-space: nowrap;

    @media (width < 480px) {
      font-size: 0.9375rem;
    }
  }

  .inv-help__scope {
    color: var(--color-ink-secondary);
    font-size: 0.75rem;
    line-height: 1.45;
    margin: 0;

    @media (width < 480px) {
      font-size: 0.875rem;
    }
  }

  .inv-help__link {
    border-block-start: 1px solid var(--color-border-subtle);
    color: var(--color-brand);
    display: block;
    font-size: 0.6875rem;
    font-weight: 600;
    margin-block-start: 0.75rem;
    padding-block-start: 0.625rem;
    text-decoration: none;

    @media (width < 480px) {
      font-size: 0.8125rem;
    }
  }

  .inv-help__link:hover {
    text-decoration: underline;
  }

  .inv-items-table {
    display: flex;
    flex-direction: column;
  }

  .inv-item-wrap {
    border-block-start: 1px solid var(--color-border-subtle);
  }

  /* Flex row — wraps when content is too wide; each col carries its own label.
     Extra inline-start padding leaves a gutter for the absolutely-positioned
     drag handle so it never consumes a flex item or grid track. */
  .inv-item-row {
    align-items: flex-end;
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem 0.75rem;
    padding: 0.75rem 0.5rem 0.75rem 1.75rem;
    position: relative;
  }

  /* Drag handle — sits in the row's left gutter, out of flow so it works across
     the row's flex and grid breakpoints alike. Aligned vertically with the row
     of fields (an `--inv-input-height` box at the row's bottom edge), like the
     "⋯" trigger on the right. */
  .inv-item-drag {
    -webkit-touch-callout: none;
    -webkit-user-select: none;
    align-items: center;
    block-size: var(--inv-input-height);
    color: var(--color-ink-faint);
    cursor: grab;
    display: flex;
    inset-block-end: 0.75rem;
    inset-inline-start: 0.25rem;
    justify-content: center;
    padding: 0.25rem;
    position: absolute;
    touch-action: none; /* the handle never scrolls the page while dragging */
    transition: color 0.15s;
    user-select: none;
  }

  .inv-item-drag:active { cursor: grabbing; }

  /* Floating card while dragging — the real row lifted out (position: fixed,
     JS moves it via `top`), with only the card look and elevation added. */
  .inv-item-wrap.is-dragging {
    background: var(--color-surface);
    border-block-start-color: transparent;
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-lifted);
    opacity: 0.97;
    transform: scale(1.02);
    transition: box-shadow 200ms ease, transform 200ms ease;
  }

  /* The gap the lifted row leaves — holds its exact height so the layout
     doesn't jump. */
  .inv-item-placeholder {
    background: var(--color-surface-tint);
    border-radius: var(--radius-md);
  }

  /* Each column: label on top, input below */
  .inv-item-col {
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
  }

  .inv-item-col__label {
    white-space: nowrap;
  }

  /* Description — fills remaining horizontal space; input scrolls for long text.
     position: relative anchors the saved-templates suggestions dropdown. */
  .inv-item-col--name {
    flex: 1 1 200px;
    min-inline-size: 0;
    position: relative;
  }

  .inv-item-col--name .inv-item-input {
    inline-size: 100%;
  }

  /* Total + "⋯" menu — a shared wrapper, always at the right edge, the two
     aligned with each other */
  .inv-item-group--right {
    align-items: flex-start;
    display: flex;
    gap: 0.5rem;
    margin-inline-start: auto;
  }

  .inv-item-input {
    font-size: 0.9375rem;
    min-block-size: var(--inv-input-height);
    padding: 0.5rem 0.625rem;
  }

  /* Locked field — a sibling error disables the rest of the line item */
  .inv-item-input:disabled,
  .inv-joined__input:disabled,
  .inv-joined__select:disabled,
  .inv-item-discount__input:disabled {
    cursor: not-allowed;
    opacity: 0.5;
  }

  /* Per-line-item validation messages — full-width row below the inputs,
     hidden entirely while no field is in error */
  .inv-item-errors {
    display: flex;
    flex-wrap: wrap;
    gap: 0 0.75rem;
    padding: 0 0.5rem;
  }

  .inv-item-errors:not(:has(.inv-field__error:not(:empty))) {
    display: none;
  }

  /* ── Joined input — price + volume + VAT as one visual input with
     separately editable parts (à la Stripe's card element).
     Subgrid keeps the labels above the box aligned with the parts inside it. ── */
  .inv-item-col--joined {
    display: grid;
    grid-template-columns: minmax(72px, auto) minmax(64px, auto) minmax(88px, auto);
    row-gap: 0.25rem;
  }

  .inv-joined__labels {
    display: grid;
    grid-column: 1 / -1;
    grid-template-columns: subgrid;
  }

  .inv-joined__labels .inv-item-col__label {
    padding-inline-start: 0.625rem;
  }

  /* The single visual box the three parts live in */
  .inv-joined {
    background: var(--color-surface);
    border: 1.5px solid var(--color-border);
    border-radius: var(--radius-sm);
    display: grid;
    grid-column: 1 / -1;
    grid-template-columns: subgrid;
    min-block-size: var(--inv-input-height);
    transition: border-color 0.15s, box-shadow 0.15s;
  }

  .inv-joined:focus-within {
    border-color: var(--color-brand);
    box-shadow: var(--shadow-focus);
  }

  .inv-joined__part {
    align-items: center;
    border-radius: var(--radius-sm);
    cursor: text;
    display: flex;
    gap: 0.25rem;
    min-inline-size: 0; /* a part may shrink below its content when the track is cramped (tablet/phone) */
    padding: 0.25rem 0.625rem;
  }

  /* Editing feedback — the active part gets a soft highlight */
  .inv-joined__part:focus-within {
    background: var(--color-surface-tint);
  }

  /* Dividers between parts */
  .inv-joined__part + .inv-joined__part {
    border-inline-start: 1px solid var(--color-border-subtle);
    border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
  }

  .inv-joined__input {
    background: transparent;
    border: none;
    color: var(--color-ink);
    /* Sized by what is typed into it — a price, a quantity, a unit — within
       its part. */
    field-sizing: content;
    font-size: 0.9375rem;
    max-inline-size: 100%;
    min-inline-size: 2ch;
    outline: none;
    padding: 0.125rem 0;
  }

  /* Empty price invites the first click — dashed hint under the placeholder */
  .inv-joined__part--price .inv-joined__input:placeholder-shown {
    border-block-end: 1px dashed var(--color-border-strong);
  }

  /* Unwrapped volume/VAT fields — dashed boxes so the number is
     distinguishable from the unit while both are editable */
  .inv-joined__part--volume .inv-joined__input,
  .inv-joined__part--vat .inv-joined__input {
    border: 1px dashed var(--color-border-strong);
    border-radius: var(--radius-xs);
    padding: 0.125rem 0.25rem;
  }

  .inv-joined__part--volume .inv-joined__input:focus,
  .inv-joined__part--vat .inv-joined__input:focus {
    border-color: var(--color-brand);
    border-style: solid;
  }

  /* Anchor for the unit options menu */
  .inv-joined__part--volume {
    position: relative;
  }

  /* Unit suggestions — a static menu below the volume part; deliberately NOT
     filtered by the field's value, the full list stays visible while editing.
     Styled after the native datalist popup — a plain gray bubble. */
  .inv-joined__options {
    background: var(--color-surface-tint);
    border-color: var(--color-border);
    inset-block-start: calc(100% + 4px);
    inset-inline-start: 0;
    max-block-size: 220px;
    min-inline-size: 100%;
    overflow-y: auto;
    padding: 0;
  }

  .inv-joined__option {
    border-radius: 0;
    display: block;
    font-size: 0.8125rem;
    padding: 0.3rem 0.75rem;
  }

  .inv-joined__option:hover,
  .inv-joined__option[aria-selected="true"] {
    background: var(--color-brand-tint);
  }

  .inv-joined__input.input-error {
    border: 1px solid var(--color-negative);
  }

  /* Collapsed text of a part — a button so it sits in the tab order */
  .inv-joined__display {
    background: none;
    border: none;
    color: var(--color-ink);
    cursor: text;
    font-size: 0.9375rem;
    min-inline-size: 0;
    overflow: hidden;
    padding: 0.125rem 0;
    text-align: start;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  /* Empty state — muted example value with a dashed hint that it's editable */
  .inv-joined__display--empty {
    border-block-end: 1px dashed var(--color-border-strong);
    color: var(--color-ink-faint);
  }

  /* Compact VAT settings select shown while the VAT part is unwrapped */
  .inv-joined__select {
    appearance: none;
    background: var(--color-surface);
    background-image: var(--icon-chevron-brand);
    background-position: right 0.375rem center;
    background-repeat: no-repeat;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    color: var(--color-ink);
    cursor: pointer;
    font-size: 0.8125rem;
    max-inline-size: 100%;
    min-inline-size: 0;
    padding: 0.125rem 1.375rem 0.125rem 0.375rem;
  }

  .inv-joined__select:focus {
    border-color: var(--color-brand);
    outline: none;
  }

  .inv-joined__suffix {
    color: var(--color-ink-muted);
    font-size: 0.8125rem;
    font-weight: 600;
  }

  /* ── Desktop (≥1024px): the description fills the rest of the row, the
     joined input and Total size to their content. ── */
  @media (width >= 1024px) {
    .inv-item-row {
      align-items: end;
      column-gap: 0.75rem;
      display: grid;
      grid-template-columns: minmax(120px, 1fr) auto auto;
      row-gap: 0;
    }
  }

  /* Total column — stacked: original (struck) on top, final bold below */
  .inv-item-row__total {
    align-items: flex-end;
    display: flex;
    flex-direction: column;
    gap: 1px;
    justify-content: center;
    min-block-size: var(--inv-input-height);
    padding-inline-end: 0.25rem;
  }

  .inv-item-row__total-original {
    color: var(--color-ink-faint);
    font-family: var(--font-mono);
    font-size: 0.75rem;
    text-decoration: line-through;
  }

  .inv-item-row__total-final {
    color: var(--color-ink-secondary);
    font-family: var(--font-mono);
    font-size: 0.875rem;
    font-weight: 700;
  }

  /* ⋯ menu — the column stretches to the group's height, the trigger sits at
     the bottom, level with the fields */
  .inv-item-col--menu {
    align-self: stretch;
    justify-content: flex-end;
    position: relative;
  }

  /* The "⋯" trigger — level with the row of fields */
  .inv-item-row__more {
    align-items: center;
    background: none;
    border: none;
    border-radius: var(--radius-sm);
    color: var(--color-ink-faint);
    cursor: pointer;
    display: flex;
    justify-content: center;
    min-block-size: var(--inv-input-height);
    padding: 0 0.25rem;
    transition: background 0.15s, color 0.15s;
  }

  .inv-item-row__more:hover {
    background: var(--color-surface-tint);
    color: var(--color-ink-muted);
  }

  /* Dropdown card with the line item's actions */
  .inv-item-menu {
    inset-block-start: calc(100% + 0.35rem);
    inset-inline-end: 0;
    list-style: none;
    margin: 0;
    min-inline-size: 220px;
  }

  /* Saved state — brand colour, with a filled bookmark */
  .inv-item-menu__item--saved {
    color: var(--color-brand);
  }

  /* Discount row — column: label on top, fields below */
  .inv-item-discount {
    background: var(--color-surface-tint);
    border-block-start: 1px dashed var(--color-border-subtle);
    display: flex;
    flex-direction: column;
    gap: 0.375rem;
    padding: 0.5rem 0.625rem 0.625rem;
    position: relative;
  }

  .inv-item-discount__label {
    color: var(--color-ink-secondary);
    font-weight: 700;
    margin: 0;
  }

  /* Fields + × on one horizontal line */
  .inv-item-discount__row {
    align-items: center;
    display: flex;
    gap: 0.625rem;
  }

  /* Each field (input + unit label) side by side; a field is a form of its
     own (`line_items/_discount_percentage`, `_discount_total`). */
  .inv-disc-field {
    align-items: center;
    display: flex;
    gap: 0.3rem;
  }

  .inv-disc-field__unit {
    color: var(--color-ink-muted);
    font-size: 0.8125rem;
    font-weight: 600;
  }

  .inv-item-discount__input {
    inline-size: 72px;
    padding: 0.3rem 0.5rem;
  }

  /* Remove discount × — absolutely centred in the whole discount block */
  .inv-disc-remove {
    background: none;
    border: none;
    color: var(--color-ink-faint);
    cursor: pointer;
    font-size: 1.125rem;
    inset-block-start: 50%;
    inset-inline-end: 0.375rem;
    line-height: 1;
    padding: 0.25rem 0.5rem;
    position: absolute;
    transform: translateY(-50%);
    transition: color 0.12s;
  }

  .inv-disc-remove:hover { color: var(--color-negative); }

  /* "% Discount" button that appears below each line item row */
  .inv-item-add-discount-btn {
    background: none;
    border: none;
    color: var(--color-ink-faint);
    cursor: pointer;
    font-size: 0.75rem;
    font-weight: 600;
    letter-spacing: 0.03em;
    padding: 0.2rem 0.625rem 0.4rem;
    transition: color 0.12s;
  }

  .inv-item-add-discount-btn:hover { color: var(--color-brand); }

  .inv-items-actions {
    border-block-start: 1px solid var(--color-border-subtle);
    display: flex;
    gap: 0.75rem;
    margin-block-start: 0.25rem;
    padding-block-start: 0.875rem;
  }

  .inv-add-btn {
    align-items: center;
    background: var(--color-surface-tint);
    border: 1.5px dashed var(--color-border-strong);
    border-radius: var(--radius-sm);
    color: var(--color-brand);
    cursor: pointer;
    display: inline-flex;
    font-size: 0.8125rem;
    font-weight: 600;
    gap: 0.4rem;
    padding: 0.5rem 0.875rem;
    text-decoration: none;
    transition: background 0.15s, border-color 0.15s;
  }

  .inv-add-btn:hover {
    background: var(--color-brand-tint);
    border-color: var(--color-brand);
  }

  .inv-add-btn:disabled {
    background: var(--color-surface-tint);
    border-color: var(--color-border-strong);
    color: var(--color-ink-faint);
    cursor: default;
  }

  @media (width < 480px) {
    /* ── Items — the description takes the whole row, the joined input goes
       under it at full width, Total gets a row of its own. The drag handle
       (⠿, left) and the ⋯ menu (right) are absolute side rails centred
       vertically on the whole item; the right gutter (a mirror of the left)
       keeps the content clear of ⋯. ── */
    .inv-item-row {
      padding-inline-end: 1.75rem;
      row-gap: 0.5rem;
    }

    /* Dots centred in the gutter (midway between the edge and the start of
       the field) — the rail is the gutter's width and centres its content
       both ways. */
    .inv-item-drag {
      block-size: auto;
      inline-size: 1.75rem;
      inset-block: 0;
      inset-inline-start: 0;
    }

    .inv-item-col--menu {
      align-items: center;
      inline-size: 1.75rem;
      inset-block-start: 50%;
      inset-inline-end: 0;
      position: absolute;
      transform: translateY(-50%);
    }

    .inv-item-col--name,
    .inv-item-col--joined {
      flex-basis: 100%;
      min-inline-size: 0;
    }

    /* On a phone ALL three columns must be shrinkable (minmax(0, …)), or a
       long value (say "1 000,00 €") or a long VAT text ("By item",
       "23% (transferred)") stretches the box past the screen's width. VAT gets
       a little more room since it carries the longest text. The parts' and
       displays' shrinkability (min-width:0, clipping) lives in the base rules
       — it applies at every breakpoint. */
    .inv-item-col--joined {
      grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) minmax(0, 1.1fr);
    }

    /* Compact padding on small screens (the min-height stays the editor's) */
    .inv-item-input {
      padding: 0.375rem 0.5rem;
    }

    /* Smaller total text */
    .inv-item-row__total-final {
      font-size: 0.8125rem;
    }

    /* Compact discount inputs */
    .inv-item-discount__input {
      inline-size: 60px;
    }
  }
}
