/*
 * THE REGISTER. Every measurement the fit math also reads arrives as a custom
 * property the component writes, because a second copy of one here is how the
 * header band and the rows under it stop lining up.
 *
 * The register draws ONE line, the band capping the columns: a rule between two
 * rows divides like from like, which the space between them already says.
 *
 * The `RowFocusEntry` spans the row and hit-tests above in-flow content, so every
 * box holding a control of its own is lifted back over it on the in-page rung
 * `--lotics-z-row-content`. The ordinal takes no rung: it is text rather than a
 * control, so it belongs UNDER the door.
 */
@layer theme, base, lotics, components, utilities;
@layer lotics.tokens, lotics.reset, lotics.components;

@layer lotics.components {
  /* FILLS WHAT IT IS GIVEN: sized to its content a register stops short of its
     container's right edge. `min-width: 0` says the columns, not the container,
     absorb a squeeze. */
  .lotics-table {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    flex-shrink: 0;
    width: 100%;
    min-width: 0;
  }

  /* Measure-then-reveal: invisible until the container width is known, so the
     first visible frame is already register OR stacked — never a reshuffle. */
  .lotics-table[data-unmeasured] {
    opacity: 0;
  }

  /* NO padding (GAP-85): a Table is borderless, so its container ALWAYS owns the
     top spacing and a band padding would double-gap the column header. */
  .lotics-table__header {
    display: flex;
    flex-direction: row;
    align-items: center;
    gap: var(--lotics-table-column-gap);
    flex-shrink: 0;
    min-width: 0;
    padding-inline: var(--lotics-table-gutter);
    border: 0 solid var(--border);
    border-bottom-width: 1px;
  }

  /* The literal neutral, not the accent wash: this band is a LID on the columns,
     never a "you are here". It bleeds to the row wash's width so its edges line
     up with a hovered row beneath it. */
  .lotics-table__header[data-filled] {
    background-color: var(--lotics-wash-selected);
    margin-inline: calc(var(--lotics-row-wash-bleed) * -1);
    padding-inline: calc(var(--lotics-table-gutter) + var(--lotics-row-wash-bleed));
    border-top-left-radius: calc(var(--lotics-radius-control) - var(--lotics-space-2));
    border-top-right-radius: calc(var(--lotics-radius-control) - var(--lotics-space-2));
  }

  /* ONE column box, used by the heading and by every cell under it — which is
     what keeps a right-aligned heading over its own digits. */
  .lotics-table__column,
  .lotics-table__cell {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    min-width: 0;
  }

  /* THE BASIS IS THE FIT'S OWN BUDGET (`columnBasis`), never zero: from zero the
     whole container is split by `flex` share alone, so two flexible columns
     needing different widths get the same one. Every column is seated at its own
     content before `flex` share divides what is left.
     `--lotics-table-col-floor` is where shrinking stops — the width the fit
     reserved, which the sheet may not lay out under. */
  .lotics-table__column,
  .lotics-table__cell:not([data-stacked]) {
    flex: var(--lotics-table-col-flex) 1 var(--lotics-table-col-basis, 0%);
    min-width: var(--lotics-table-col-floor, 0);
  }

  .lotics-table__column[data-fixed],
  .lotics-table__cell[data-fixed] {
    flex: none;
    width: var(--lotics-table-col-width);
  }

  /* NOBODY ASKED FOR THE SLACK — every column states a width, so the widths
     become floors and the columns grow together, which keeps a right-aligned
     column's digits on the register's own right edge. */
  .lotics-table[data-slack] .lotics-table__column[data-fixed],
  .lotics-table[data-slack] .lotics-table__cell[data-fixed] {
    flex: 1 0 var(--lotics-table-col-width);
    width: auto;
  }

  .lotics-table__column[data-align="right"],
  .lotics-table__cell[data-align="right"] {
    align-items: flex-end;
  }

  /* THE COLUMN'S LINE BUDGET, HELD OPEN ON EVERY ROW (`TableColumn.lines`):
     without it a column whose caption is written on half its rows lands its
     first line at two heights down the page. The band is the register's own line
     rung twice and the content sits at the TOP of it, which puts every row's
     first line on one edge. */
  .lotics-table__cell[data-lines="2"]:not([data-stacked]) {
    min-height: calc(var(--lotics-register-line) * 2);
  }

  /* A stacked cell that keeps its column's own header over its value: the pair
     is one reading, so the gap closes them up. */
  .lotics-table__cell[data-headed] {
    gap: var(--lotics-space-2);
  }

  /* The header's own reservation for the row's trailing gutter, so the last
     heading stops where the last value does. */
  .lotics-table__trailing-spacer {
    flex: none;
    width: var(--lotics-table-trailing-width);
  }

  /* RIGHT-aligned so 9 and 100 share an edge. */
  .lotics-table__ordinal {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    flex: none;
    width: var(--lotics-table-ordinal-width);
  }

  .lotics-table__lead {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    flex: none;
    width: var(--lotics-table-leading-width);
    position: relative;
    z-index: var(--lotics-z-row-content);
  }

  /* THE BULK-SELECT AND ITS WORDS as ONE press target. It takes the slack so
     the band reads as one line from the gutter rightwards; the gutter keeps its
     own width, which holds the mark over the rows' boxes. STACKED ONLY: side by
     side the column headings hold this space. */
  .lotics-table__select-all {
    display: flex;
    flex-direction: row;
    align-items: center;
    gap: var(--lotics-table-column-gap);
    flex: 1;
    min-width: 0;
  }

  .lotics-table__select-all-label {
    min-width: 0;
  }

  /* A small gap: the row's own height carries the airiness, and this only has to
     stop two washes touching. Shared with a group's band of rows. */
  .lotics-table__body,
  .lotics-table__group-body {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    flex-shrink: 0;
    min-width: 0;
    gap: var(--lotics-space-4);
  }

  /* The register's column gutter, stated at two classes deep so it beats the
     row surface's own gap whichever sheet a bundler emits first. */
  .lotics-table .lotics-table__row {
    gap: var(--lotics-table-column-gap);
  }

  /* A read-only row: the register row's gutter and layout so its cells still
     align with the header, minus the hover/press surface. */
  .lotics-table__row[data-static] {
    display: flex;
    flex-direction: row;
    align-items: center;
    flex-shrink: 0;
    min-width: 0;
    padding-inline: var(--lotics-table-gutter);
  }

  /* The pile fills the width and sizes its own height. */
  .lotics-table__row[data-static][data-stacked] {
    align-items: stretch;
  }

  .lotics-table__cells {
    display: flex;
    flex-direction: row;
    align-items: center;
    flex: 1;
    gap: var(--lotics-table-column-gap);
    min-height: var(--lotics-table-row-height);
    min-width: 0;
    position: relative;
    z-index: var(--lotics-z-row-content);
  }

  /* The register's trailing gutter composes [action, overflow] on one row. */
  .lotics-table__trailing {
    display: flex;
    flex-direction: row;
    align-items: center;
    justify-content: flex-end;
    gap: var(--lotics-space-8);
    flex: none;
    width: var(--lotics-table-trailing-width);
    position: relative;
    z-index: var(--lotics-z-row-content);
  }

  /* On the stacked top line the overflow is a plain slot: the gutter it would
     reserve belongs to a register that no longer has columns. */
  .lotics-table__trailing[data-stacked] {
    flex-direction: column;
    align-items: stretch;
    justify-content: flex-start;
    width: auto;
  }

  /* TOP ALIGNMENT puts every cell and both gutters on one top edge, and pays for
     it in PADDING so a one-line row is pixel-identical to the centred default.
     Measured from the register's BEAT rather than this row's own floor, so a row
     that asked for density does not also shift its content up. */
  .lotics-table[data-align="top"] .lotics-table__row,
  .lotics-table[data-align="top"] .lotics-table__cells,
  .lotics-table[data-align="top"] .lotics-table__trailing:not([data-stacked]) {
    align-items: flex-start;
  }

  /* Paid ONCE, on the boxes that hold the content: a read-only row renders the
     same `cells` box a pressable one does, so charging the ROW as well would
     stack the padding twice. */
  .lotics-table[data-align="top"] .lotics-table__cells,
  .lotics-table[data-align="top"] .lotics-table__trailing:not([data-stacked]) {
    padding-block: calc((var(--lotics-table-beat) - var(--lotics-control-height)) / 2);
  }

  /* The row and the detail it opened, as one block. */
  .lotics-table__block {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    flex-shrink: 0;
    min-width: 0;
  }

  /* The expanded detail, indented to the identity column's text edge so it reads
     as belonging to the row above. Vertical padding is measured from the row's
     WASH, not its text: an expanded row wears the `selected` highlight, so the
     band's edge is the hard line the eye reads. */
  .lotics-table__detail {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    flex-shrink: 0;
    min-width: 0;
    padding-inline: var(--lotics-table-gutter);
    padding-block: var(--lotics-space-16);
  }

  /* HELD, THEN FADED: a wash that begins mid-fade reads as a rendering artefact
     rather than as something arriving. Both halves ride the motion scale. */
  .lotics-table__arrival {
    position: absolute;
    inset: 0;
    border-radius: var(--lotics-radius-control);
    background-color: var(--lotics-accent-wash);
    pointer-events: none;
    animation-name: lotics-table-arrival;
    animation-duration: calc(var(--lotics-duration-slow) * 3);
    animation-delay: calc(var(--lotics-duration-slow) * 4);
    animation-timing-function: var(--lotics-ease-exit);
    animation-fill-mode: both;
  }

  @keyframes lotics-table-arrival {
    from {
      opacity: 1;
    }
    to {
      opacity: 0;
    }
  }

  /* STACKED: the top line keeps the leading/trailing slots beside the first
     cell, the rest become label-over-value blocks. Vertical padding replaces the
     register's centring. */
  .lotics-table__stack {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    flex: 1;
    min-width: 0;
    gap: var(--lotics-space-10);
    padding-block: var(--lotics-space-12);
    position: relative;
    z-index: var(--lotics-z-row-content);
  }

  .lotics-table__stack-top {
    display: flex;
    flex-direction: row;
    align-items: center;
    flex-shrink: 0;
    min-width: 0;
    gap: var(--lotics-table-column-gap);
    min-height: var(--lotics-control-height);
  }

  .lotics-table__stack-fields {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    flex-shrink: 0;
    min-width: 0;
    gap: var(--lotics-space-8);
  }

  .lotics-table__stack-fields[data-indented] {
    padding-left: calc(
      var(--lotics-table-leading-width) + var(--lotics-table-ordinal-width) +
        var(--lotics-table-column-gap)
    );
  }

  /* The CTA closes the content, right-aligned — content scale, not row chrome
     (the overflow stays on the top line). */
  .lotics-table__stack-action {
    display: flex;
    flex-direction: row;
    align-items: stretch;
    flex-shrink: 0;
    min-width: 0;
    justify-content: flex-end;
  }

  /* The identity cell IS the top line's flexible box — it heads the pile rather
     than becoming one of its labelled field lines. */
  .lotics-table__cell[data-stacked][data-primary] {
    flex: 1;
    min-width: 0;
  }

  /* A label-less cell in stacked mode: no label to spread against, so the
     content pins right on the `DetailRow` line rhythm. */
  .lotics-table__cell[data-bare] {
    flex-direction: row;
    align-items: center;
    justify-content: flex-end;
    min-height: var(--lotics-control-content-height);
  }

  /* AIR, not a rule: a line here would be a second rule competing with the
     column band's. The air is the band's own margin, OUTSIDE the heading —
     inside its padding it would be drawn on by the wash. */
  .lotics-table__group {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    flex-shrink: 0;
    min-width: 0;
    margin-top: var(--lotics-space-16);
  }

  .lotics-table__group-heading {
    display: flex;
    flex-direction: row;
    align-items: center;
    flex-shrink: 0;
    min-width: 0;
    gap: var(--lotics-space-8);
    min-height: var(--lotics-register-row);
    padding-inline: var(--lotics-table-gutter);
    border: 0 solid var(--border);
    border-radius: calc(var(--lotics-radius-control) - var(--lotics-space-2));
    background-color: transparent;
    background-image: none;
    font-family: var(--font-sans);
    font-size: var(--lotics-text-sm);
    line-height: var(--lotics-leading-sm);
    letter-spacing: var(--lotics-tracking-sm);
    color: var(--lotics-ink-default);
    appearance: none;
    cursor: auto;
    text-align: start;
    touch-action: manipulation;
    user-select: none;
    transition: background-color var(--lotics-duration-fast) var(--lotics-ease-standard);
  }

  .lotics-table__group-heading[data-pressable]:hover {
    background-color: var(--lotics-wash-hover);
  }

  .lotics-table__group-heading:focus-visible {
    outline: var(--lotics-ring-width) solid var(--ring);
    outline-offset: 0;
  }

  /* ONE slot for the band's leading mark, whatever it holds. Fixed width so the
     label starts at the same x on every band. */
  .lotics-table__group-mark {
    display: flex;
    align-items: center;
    justify-content: center;
    flex: none;
    width: 16px;
  }

  .lotics-table__group-dot {
    flex: none;
    width: 6px;
    height: 6px;
    border-radius: var(--lotics-radius-full);
    background-color: var(--lotics-table-group-dot);
  }
}
