@layer components {
  /* Stacked list rows separated by hairlines — data separation only. No frame
     around a row: the hairline between two rows is the whole separation. */
  .rows > li + li {
    border-block-start: var(--border);
  }

  /* The whole row is the target, so it carries no underline; the 1px underline
     belongs to links sitting inside running text. */
  .row {
    display: flex;
    flex-direction: column;
    gap: var(--block-space-half);
    padding-block: var(--block-space);
    color: var(--color-ink);
    text-decoration: none;
  }

  /* A row led by the kind of thing it is — Basecamp's bookmark row: the
     glyph in its own column, the words beside it. Ink, not a coloured disc. */
  .row--led {
    display: grid;
    grid-template-columns: auto 1fr;
    column-gap: var(--inline-space-double);
    align-items: start;
  }

  /* The row's heading, and the whole of its hover: a link in HANSHI is ink
     plus a 1px underline, so hovering a row simply draws the underline its
     title does without.

     Named rather than matched on `strong`, because the byline under it
     carries one too and would underline with it. The other .rows surfaces —
     the bookmark row, the search hit — opt in by taking the class. */
  .row__title {
    font-weight: 600;
  }

  /* The hover, for every title that is a link: ink until the pointer, then the
     underline — at 1px, which is what HANSHI rules for a link and what a
     heading needs to keep the written line's weight. The thickness is spelled
     out because `text-decoration: underline` is a SHORTHAND and resets
     text-decoration-thickness to `auto`: a surface that restates the hover
     locally never reaches base.css's longhands at all, and draws whatever the
     font derives — visibly heavy on an h1.

     .board__title (boards.css), .inline-rename a and .rollup__subjects a are
     listed here on purpose, the way labels.css lists foreign selectors: layers
     only decide who wins a conflict, and nothing here conflicts; what matters
     is that the voice has one definition to change. The board title lived in
     boards.css until 2026-08-29, which put a `.row` rule in the file you would
     delete with the board. */
  .row:hover .row__title,
  .board__title:hover,
  .question-card__door:hover,
  .inline-rename a:hover,
  .rollup__subjects a:hover {
    text-decoration: underline;
    text-decoration-thickness: 1px;
    text-underline-offset: 0.15em;
  }

  .row__glyph {
    --icon-size: 1.25rem;

    display: grid;
    place-items: center;
    inline-size: 2.25rem;
    block-size: 2.25rem;
    color: var(--color-ink-subtle);
    background-color: var(--color-surface);
    border-radius: 50%;
  }

  /* Stretch, not start: a shrink-to-fit child collapses custom elements that
     size themselves from their container (Lexxy's editor went to 2px wide) —
     which leaves the submit button to opt back out on its own.

     It opts out to the end. "Action rows always right-align, primary
     outermost" (HANSHI 02) holds for a lone submit as much as for a row of
     three, and this is the one line that says so for every form in the app. */
  .stack {
    display: flex;
    flex-direction: column;
    gap: var(--block-space);
    align-items: stretch;

    > .btn {
      align-self: end;
    }
  }
}
