@layer components {
  /* A horizontal timeline above the divider. The events sit newest-first in
     the DOM (broadcasts prepend), hence row-reverse: oldest on the left,
     newest on the right, and new events grow in from the right. */
  /* The one timeline of the page, rendered in the header (events/_timeline).
     A card like the sidebar's sections — it carries their class; on a phone
     it sits among them — the page's wrappers dissolve there (see invoice.css)
     and `order` places it after the sidebar, where a title names the card. */
  @media (width < 768px) {
    .inv-timeline-wrap {
      margin-block-start: 1rem;
      order: 4;
    }
  }

  /* From 768px: to the right of the header, scrolling sideways when the run
     is longer than the room, and needing no title. */
  @media (width >= 768px) {
    .inv-timeline-wrap {
      display: block;
      flex: 0 1 auto;
      margin-block: 0;
      max-inline-size: 100%;
      overflow-x: auto;
      scrollbar-width: none;
    }

    .inv-timeline-wrap__title {
      display: none;
    }
  }

  .inv-timeline-wrap::-webkit-scrollbar {
    display: none;
  }

  .inv-timeline {
    display: flex;
    flex-direction: row-reverse;
    justify-content: flex-end;
    list-style: none;
    margin: 0;
    min-inline-size: min-content;
    padding: 0.25rem 0 0.25rem;
  }

  .inv-timeline__item {
    display: flex;
    flex: 0 0 auto;
    flex-direction: column;
    gap: 0.35rem;
    min-inline-size: 140px;
    padding-block-start: 1.1rem;
    padding-inline-end: 1.75rem;
    position: relative;
  }

  /* The dot */
  .inv-timeline__item::before {
    background: var(--color-brand);
    block-size: 13px;
    border: 2.5px solid var(--color-surface);
    border-radius: 50%;
    box-shadow: 0 0 0 1.5px var(--color-brand);
    content: "";
    inline-size: 13px;
    inset-block-start: 0;
    inset-inline-start: 0;
    position: absolute;
    z-index: 1;
  }

  /* The connector to the neighbouring dot on the right; the first item in the
     DOM is the newest, sits rightmost, and so has none. */
  .inv-timeline__item::after {
    background: var(--color-border);
    block-size: 2px;
    content: "";
    inset-block-start: 5.5px;
    inset-inline: 13px 0;
    position: absolute;
  }

  .inv-timeline__item:first-child::after {
    display: none;
  }

  .inv-timeline__entry {
    color: var(--color-ink);
    display: flex;
    flex-direction: column-reverse;
    gap: 0.1rem;
    line-height: 1.35;
    margin: 0;
  }

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

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

  /* The credit note an invoice's entry is about. */
  .inv-timeline__subject {
    color: var(--color-link);
  }

  .inv-timeline__subject--deleted {
    color: var(--color-ink-muted);
    font-weight: 400;
  }

  /* The question mark on a failed delivery; the bubble with the reason shows
     on hover/focus. */
  .inv-timeline__hint {
    cursor: help;
    display: inline-block;
    margin-inline-start: 0.35em;
    position: relative;
  }

  .inv-timeline__hint-mark {
    background: var(--color-border);
    border-radius: 50%;
    color: var(--color-brand);
    display: inline-block;
    font-size: 0.6875rem;
    font-weight: 700;
    inline-size: 1.2em;
    line-height: 1.2em;
    text-align: center;
  }

  .inv-timeline__hint-bubble {
    background: var(--color-surface-inverted);
    border-radius: var(--radius-sm);
    color: var(--color-ink-inverted);
    display: none;
    font-size: 0.75rem;
    font-weight: 400;
    inline-size: max-content;
    /* `fixed` with automatic insets: the bubble renders at its static position
       (right by the question mark) yet escapes the clipping of the timeline's
       scroll container (.inv-timeline-wrap has overflow), which would cut a
       taller bubble with its explanation off. It opens downward (upward, the
       sticky header would cover it), and the transform aligns its right edge
       to the question mark so it doesn't overflow the screen's right edge. */
    inset: auto;
    line-height: 1.4;
    max-inline-size: 16rem;
    padding: 0.5rem 0.65rem;
    position: fixed;
    text-align: start;
    transform: translate(calc(-100% + 1.5em), 0.4em);
    white-space: normal;
    z-index: 2;
  }

  .inv-timeline__hint:hover .inv-timeline__hint-bubble,
  .inv-timeline__hint:focus-visible .inv-timeline__hint-bubble {
    display: block;
  }

  .inv-timeline__hint-what {
    display: block;
    font-weight: 600;
  }

  .inv-timeline__hint-fix {
    display: block;
    margin-block-start: 0.15rem;
  }

  /* Mailgun's raw technical reason as a small note under the explanation. */
  .inv-timeline__hint-detail {
    display: block;
    font-size: 0.6875rem;
    margin-block-start: 0.35rem;
    opacity: 0.65;
  }

  .inv-timeline__file {
    color: var(--color-brand);
    font-size: 0.8125rem;
    font-weight: 500;
    text-decoration: none;
  }

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

  /* The "Re-process bill" link beside the original's download. */
  .inv-timeline__reprocess {
    color: var(--color-brand);
    cursor: pointer;
    font-size: 0.8125rem;
    font-weight: 500;
    text-decoration: none;
  }

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

  /* Reading a bill again is writing it, and a link is no form control the
     read-only fieldset disables. The entry can arrive by broadcast, rendered
     for no one in particular, so it is hidden here rather than left out. */
  .inv-readonly:disabled .inv-timeline__reprocess {
    display: none;
  }

  /* ── Mobile (<768px): the timeline is a vertical list (time + name on one
     row, a thin vertical rule on the left). ── */
  @media (width < 768px) {
    .inv-timeline {
      flex-direction: column;
      gap: 0.75rem;
      min-inline-size: 0;
      padding: 0;
    }

    .inv-timeline__item {
      border-inline-start: 2px solid var(--color-border);
      flex-direction: row;
      gap: 0;
      min-inline-size: 0;
      padding: 0.05rem 0 0.05rem 0.875rem;
    }

    /* No dots or horizontal connectors in the vertical list. */
    .inv-timeline__item::before,
    .inv-timeline__item::after {
      display: none;
    }

    /* Time + name on one row. */
    .inv-timeline__entry {
      align-items: baseline;
      flex-direction: row;
      flex-wrap: wrap;
      gap: 0.4rem;
    }
  }
}
