/* Comment threads. Flat, hairline-separated, newest last, with the lean
   composer waiting at the bottom — see lexxy.css. */
@layer components {
  /* ====================================================================
     Comments
     ==================================================================== */
  /* ——— Comments: flat threads, hairline-separated, newest last (Hanshi 07).
     The lean composer waits at the bottom of every one — see lexxy.css. ——— */

  /* ONE COLUMN FOR THE WHOLE THREAD (user, 2026-10-06): a comment's name,
     words and boosts, an event line, and the composer's prompt all start one
     face and one space in, and the face hangs in the gutter. The words are
     read where they were typed. Supersedes HANSHI 07's words at the margin.
     Basecamp's shape (its --thread-entry-indent); its gutter shrinks on a
     phone, ours is narrower than its smallest and has no breakpoint.

     The composer's face and gap ARE the column (.comment-composer below);
     this says the same length for everything else. Registered, so it
     computes once in the thread's own type: read raw, its 1ch would resolve
     in each reader's type, and an event line's smaller text sat a pixel off. */
  @property --thread-indent {
    syntax: "<length>";
    inherits: true;
    initial-value: 0px;
  }

  .comments {
    --thread-indent: calc(var(--avatar-size, 1.75rem) + var(--inline-space));

    > :is(.comment, .event) {
      padding-inline-start: var(--thread-indent);
    }
  }

  /* The thread label is a tracked-caps label like every other section label.
     `.comments > h2` is in labels.css's selector list; a comments heading is
     never anything else. */
  .comment {
    padding-block: var(--block-space);

    & + .comment {
      border-block-start: var(--border);
    }

    /* The byline is bylines.css's; here its face steps out into the gutter,
       level with the name. The line is the face's height, so the name
       centres on it as it does beside the composer's prompt. */
    .byline {
      position: relative;
      min-block-size: var(--avatar-size, 1.75rem);

      > .avatar {
        position: absolute;
        inset-block-start: 0;
        inset-inline-start: calc(-1 * var(--thread-indent));
      }
    }

    /* Rendered rich text leaves a trailing margin under its last block, which
       would double the rhythm above the next hairline. */
    .lexxy-content > :last-child {
      margin-block-end: 0;
    }
  }

  /* The composer row that closes every thread (comments/_section): the
     thread's hairline above, air, then your face beside the prompt — BC's
     calm (user, 2026-08-10). At rest that is the whole row: one line of
     prompt, no toolbar, no buttons (user, 2026-09-30). BESIDE means on the
     same line, so the one seat the line needs — centring its 1lh against the
     face — is said in the terms it is made of; the composer itself brings no
     padding of its own (lexxy.css). Top-aligned, not centred: the avatar must
     hold its line as the comment grows. */
  .comment-composer {
    display: flex;
    align-items: flex-start;
    gap: var(--inline-space);
    border-block-start: var(--border);
    padding-block-start: var(--block-space);

    .lexxy-editor__content {
      padding-block-start: calc((var(--avatar-size, 1.75rem) - 1lh) / 2);
    }
  }

  /* The action row wakes with the first click, never before it (user,
     2026-08-11): at rest the composer is a prompt and nothing else, so the
     T · × · ↑ standing under it would answer a question no one has asked yet.

     Empty AND unfocused, so nothing moves out from under a pointer once there
     are words — asked of the form rather than the composer, so the circles
     stay put once focus is on them and Tab out of an empty editor has
     somewhere to land.

     The edit form is exempt: it stands in a comment's own place with that
     comment's words already in it, so its Never mind has to stay reachable
     even in the moment the author has selected all and deleted.

     Hidden, not gone: the row keeps its height at rest, so the click shows
     the circles and moves nothing below (user, 2026-10-06). */
  form:not(.comment-edit):has(> .comment-composer):has(lexxy-editor.lexxy-editor--empty):not(:focus-within) > .actions {
    visibility: hidden;
  }

  /* The edit composer wears the thread composer's anatomy (comments/edit) but
     not its rule: it sits inside the comment article, which already carries
     the hairline above it, and a second one would draw the line twice. The
     article already stands in the column, so the row steps back out by it:
     the face lands in the gutter, the words stay where they were read. */
  .comment-edit .comment-composer {
    border-block-start: none;
    padding-block-start: 0;
    margin-inline-start: calc(-1 * var(--thread-indent));
  }

  /* An event line among the comments keeps the thread's hairline rhythm. Its
     boost used to be positioned here too; that treatment moved to events.css
     when the feeds turned out to want it as well — a line's boost belongs to
     the line, not to whichever page it is being read on (user, 2026-08-13). */
  .comments :is(.event, .comment) + :is(.event, .comment) {
    border-block-start: var(--border);
  }

  /* A comment's Reply (replies.css draws the quote it starts) waits for the
     comment to be pointed at, as a row's ⋯ does; on touch it is always there
     (hover-reveals.css). It appears, so it earns the quick fade (HANSHI,
     Motion). */
  .comment__reply {
    opacity: 0;
    transition: opacity var(--speed-quick) var(--ease-out);

    .comment:is(:hover, :focus-within) & {
      opacity: 1;
    }
  }

  /* A comment on a document's words says which (comments/_comment): the
     quote is a door back to them while the document holds them. The page
     stamps the comment `data-words-gone` once it does not
     (annotations_controller.js); then the door is struck through and shut,
     and the phrase after it shows. */
  .comment__on {
    margin-block-end: var(--block-space-half);
    font-size: var(--text-small);
    color: var(--color-ink-subtle);

    a {
      color: inherit;
    }

    [data-words-gone] & a {
      text-decoration: line-through;
      pointer-events: none;
    }
  }

  .comment:not([data-words-gone]) .comment__on-gone {
    display: none;
  }

  /* A settled comment on words goes faint, with the word "resolved" in its
     byline. */
  .comment--resolved {
    color: var(--color-ink-faint);

    .byline strong, .lexxy-content {
      color: inherit;
    }

    .avatar {
      opacity: 0.6;
    }
  }

  /* The comment a link or a quote jumped to: the mark you came for, as a
     chat permalink's line wears it, on the same fade (messages.css). */
  .comment:target {
    outline: var(--focus-ring);
    outline-offset: 2px;
    animation: message-highlight-fade 1s 1s forwards;
  }

  /* The trace a commentable surface carries, and the only other mark a card
     may show: a dotted circle and a count. Nothing at all when it is zero. */
  .comment-count {
    display: inline-flex;
    align-items: center;
    gap: var(--inline-space-half);
    font-size: var(--text-x-small);
    color: var(--color-ink-subtle);

    &::before {
      content: "";
      inline-size: 0.75rem;
      block-size: 0.75rem;
      border: var(--border-size) dotted currentColor;
      border-radius: 50%;
    }
  }
}
