/*
 * Comments, the comment form, and the post composer.
 *
 * All three are the same shape: a person, a piece of text they wrote or are writing, and a row of controls
 * under it. They share a file because the comment form is the composer scaled down, and keeping them apart
 * would mean two sets of rules drifting away from each other.
 *
 * ### A comment is a stack, not an indent
 *
 * Identity on one line, then the text beneath it. The obvious alternative — picture on the leading edge with
 * the text beside it — cannot be built from this markup without either hiding the author's name or making a
 * second link to the profile beside the first, and a comment nobody can attribute is worse than a comment
 * that is not indented. Comments are flat here anyway: there are no replies to a reply in Phase 4, so there
 * is no depth for an indent to communicate.
 *
 * ### The editor appears only when editing
 *
 * The markup ships no edit form and no edit button: a comment that may be edited carries the address
 * and the labels as data attributes, and the script builds a `.comment__editor` — a textarea with two
 * buttons — from them, hiding the body and the meta row while it is open. A control that only works
 * with the script is not rendered without it, the same reasoning `partials/flash.php` uses for its
 * dismiss button. The textarea reuses the comment form's metrics, so the box being typed into looks
 * like the box a comment was written in (§64).
 *
 * ### Both forms hide their error until there is one
 *
 * `.field__error` in `forms.css` supplies the colour; the `hidden` attribute keeps the element out of the
 * page until the script has something to put in it. It is `role="alert"`, so it is announced when filled —
 * which only works because it was already in the document. Nothing here overrides `hidden`.
 */

.comment-list {
    margin: var(--space-3) 0 0;
    padding: 0;
    list-style: none;
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
}

.comment {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
}

.comment__author {
    display: inline-flex;
    align-self: flex-start;
    align-items: center;
    gap: var(--space-2);
    max-width: 100%;
    color: inherit;
    text-decoration: none;
}

.comment__author:hover .comment__name,
.comment__author:focus-visible .comment__name {
    color: var(--colour-primary);
    text-decoration: underline;
}

.comment__name {
    font-size: var(--text-sm);
    font-weight: var(--weight-medium);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.comment__main {
    min-width: 0;
    padding: var(--space-2) var(--space-3);
    background-color: var(--colour-surface-sunken);
    border-radius: var(--radius-md);
}

.comment__body {
    overflow-wrap: break-word;
    line-height: var(--leading-body);
}

/* The editor the script builds while editing (§64: same metrics as the comment form's textarea). It
   stands where the body stood, so no margin of its own. */
.comment__editor {
    margin: 0;
}

.comment__editor-actions {
    display: flex;
    gap: var(--space-2);
    margin-top: var(--space-2);
}

.comment__meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
    margin-top: var(--space-1);
}

.comment__edited {
    font-style: italic;
}

.comment__delete {
    margin: 0;
}

.comment__error {
    margin: var(--space-1) 0 0;
}

.comment-form {
    margin-top: var(--space-3);
}

.comment-form__field {
    margin: 0;
}

/* Two rows to start with, and it grows: a comment box the height of a post box invites an essay, and the
   script raises it as the text needs. */
.comment-form__input {
    min-height: 3.5rem;
    resize: vertical;
}

.comment-form__submit {
    margin-top: var(--space-2);
}

.comment-form__error {
    margin: var(--space-2) 0 0;
}

/*
 * The post composer.
 *
 * One card with three bands: the writing area above, a staging band in the middle that only occupies
 * space while something is staged, and the control bar along the bottom edge. The visibility selector
 * sits in that bar as a pill, because the post and its audience are decided in one gesture and the card
 * is the frame the gesture happens inside.
 *
 * The textarea loses its own border here: a box inside a box would read as two forms. The card's border
 * is the control's border, and its `:focus-within` state is the control's focus indicator.
 */
.composer {
    display: flex;
    flex-direction: column;
    margin: var(--space-4) 0;
    background-color: var(--colour-surface-raised);
    border: var(--border-width) solid var(--colour-border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-raised);
    overflow: hidden;
    transition:
        border-color var(--duration-base) var(--easing),
        box-shadow var(--duration-base) var(--easing);
}

/* The card is the control: writing anywhere inside lights the whole frame. */
.composer:focus-within {
    border-color: color-mix(in srgb, var(--colour-primary) 45%, var(--colour-border));
    box-shadow: var(--shadow-md);
}

.composer__editor {
    padding: var(--space-4) var(--space-4) 0;
}

/* Borderless inside the card: the card carries the border. The element selector in forms.css gives a
   textarea its frame and limits; every one of them is undone here. */
.composer__content {
    width: 100%;
    max-width: none;
    min-height: 6rem;
    padding: 0;
    background-color: transparent;
    border: none;
    border-radius: 0;
    resize: vertical;
}

.composer__content:focus-visible {
    outline: none;
}

/* Staging holds what is waiting to go out: thumbnails, the accepted link card, the caption fields.
   Children bring their own top space, so an empty staging band occupies no height at all. */
.composer__staging {
    display: flex;
    flex-direction: column;
    padding-inline: var(--space-4);
}

.composer__staging > * {
    margin-top: var(--space-3);
}

/* Thumbnails of the chosen pictures, drawn by the script before the upload. Fixed squares in a row
   that wraps, so one picture and four occupy the same shape of space. */
.composer__previews {
    display: grid;
    grid-template-columns: repeat(auto-fill, 5.5rem);
    gap: var(--space-2);
}

.composer__previews:empty {
    display: none;
}

.composer__preview-image {
    width: 5.5rem;
    height: 5.5rem;
    object-fit: cover;
    background-color: var(--colour-surface-sunken);
    border: var(--border-width) solid var(--colour-border);
    border-radius: var(--radius-md);
}

/* The staged Blink: one wide preview spanning the thumbnail row. The video element is paused —
   `controls` and `preload="metadata"` only, never `autoplay` — so the first frame is visible and the
   duration badge can name the length the metadata reported, but nothing plays without a press. */
.composer__preview-blink {
    position: relative;
    grid-column: 1 / -1;
    overflow: hidden;
    border: var(--border-width) solid var(--colour-border);
    border-radius: var(--radius-md);
    background-color: #000;
}

.composer__blink-video {
    display: block;
    width: 100%;
    max-height: 16rem;
    object-fit: contain;
    background-color: #000;
}

/* The badge naming the staged length; hidden until the metadata has named one. */
.composer__blink-badge {
    position: absolute;
    top: var(--space-2);
    inset-inline-start: var(--space-2);
    padding: var(--space-1) var(--space-2);
    background: color-mix(in srgb, #000 65%, transparent);
    border-radius: var(--radius-full);
    color: #fff;
    font-size: var(--text-sm);
    line-height: 1;
    pointer-events: none;
}

.composer__blink-badge[hidden] {
    display: none;
}

/* Unstage the Blink: the same quiet disc the link card's refusal uses, on the opposite corner so
   the two controls never meet. */
.composer__blink-dismiss {
    position: absolute;
    top: var(--space-2);
    inset-inline-end: var(--space-2);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.75rem;
    height: 1.75rem;
    padding: 0;
    background: color-mix(in srgb, var(--colour-surface-raised) 82%, transparent);
    border: var(--border-width) solid var(--colour-border);
    border-radius: var(--radius-full);
    color: var(--colour-ink-quiet);
    font-size: var(--text-base);
    line-height: 1;
    cursor: pointer;
    transition:
        color var(--duration-fast) var(--easing),
        background-color var(--duration-fast) var(--easing);
}

.composer__blink-dismiss:hover {
    color: var(--colour-error-ink);
    background-color: var(--colour-surface-raised);
}

/* The `hidden` attribute only works until something sets `display`; nothing here does, and this rule
   keeps it that way. */
.composer__link[hidden] {
    display: none;
}

/* The loading note standing in for the card while the endpoint is being asked. */
.composer__link-status {
    display: block;
    padding: var(--space-2) 0;
    font-size: var(--text-sm);
    color: var(--colour-ink-quiet);
}

/* Refuse the staged card: a small disc floating over its corner, quiet until hovered, named from
   markup rather than from script. */
.composer__link-dismiss {
    position: absolute;
    top: var(--space-2);
    inset-inline-end: var(--space-2);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.75rem;
    height: 1.75rem;
    padding: 0;
    background: color-mix(in srgb, var(--colour-surface-raised) 82%, transparent);
    border: var(--border-width) solid var(--colour-border);
    border-radius: var(--radius-full);
    color: var(--colour-ink-quiet);
    font-size: var(--text-base);
    line-height: 1;
    cursor: pointer;
    transition:
        color var(--duration-fast) var(--easing),
        background-color var(--duration-fast) var(--easing);
}

.composer__link-dismiss:hover {
    color: var(--colour-error-ink);
    background-color: var(--colour-surface-raised);
}

/* One caption field per chosen picture, added by the script. Empty until then, so it must not leave a
   gap above the bar. */
.composer__captions {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}

.composer__captions:empty {
    display: none;
}

/* One caption per chosen picture, built by the script as a wrapping label: the sentence above its
   input, index-aligned with media[]. */
.composer__caption {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
}

/* The bar along the bottom edge: audience pill, picture toggle and publish, in the order the decision
   flows. A hairline and a sunken tint separate it from the writing area without making it a second
   surface — it is the card's edge, where a post is finished. */
.composer__bar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-3);
    margin-top: var(--space-4);
    padding: var(--space-3) var(--space-4);
    border-top: var(--border-width) solid var(--colour-border);
    background-color: var(--colour-surface-sunken);
}

/* The audience pill: a select with rounded ends and small type. Its label is present but visually
   hidden; the option words name the audience themselves. */
.composer__visibility {
    display: flex;
    margin: 0;
}

.composer__visibility-select {
    width: auto;
    max-width: none;
    min-height: 0;
    padding: var(--space-1) var(--space-5) var(--space-1) var(--space-3);
    background-color: var(--colour-surface-raised);
    border: var(--border-width) solid var(--colour-border-strong);
    border-radius: var(--radius-full);
    font-size: var(--text-sm);
    color: var(--colour-ink-quiet);
    transition:
        border-color var(--duration-fast) var(--easing),
        color var(--duration-fast) var(--easing);
}

.composer__visibility-select:hover {
    border-color: var(--colour-primary);
    color: var(--colour-ink);
}

/* The picture toggle: a real file input, visually hidden, and its label as the visible control — so
   choosing pictures still works with the script layer blocked. `:focus-within` draws the ring around
   the label when the hidden input is focused by keyboard. */
.composer__media-toggle {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-1) var(--space-3);
    border-radius: var(--radius-full);
    color: var(--colour-ink-quiet);
    font-size: var(--text-sm);
    cursor: pointer;
    transition:
        background-color var(--duration-fast) var(--easing),
        color var(--duration-fast) var(--easing);
}

.composer__media-toggle:hover {
    background-color: color-mix(in srgb, var(--colour-ink) 6%, transparent);
    color: var(--colour-ink);
}

.composer__media-toggle:focus-within {
    outline: var(--focus-width) solid var(--colour-focus);
    outline-offset: var(--focus-offset);
}

.composer__submit {
    margin-inline-start: auto;
}

.composer__error {
    margin: 0;
    padding: var(--space-2) var(--space-4) var(--space-3);
    font-size: var(--text-sm);
    font-weight: var(--weight-medium);
    color: var(--colour-error);
}

/* The reaction control: a button that carries a word and a number, and the same pair as plain text for a
   viewer who may not press it. The two shapes are given the same metrics so a feed does not jog left and
   right depending on who wrote which post. */
.reaction,
.reaction--static {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-1) var(--space-3);
    border: var(--border-width) solid transparent;
    border-radius: var(--radius-full);
    background-color: transparent;
    color: var(--colour-ink-quiet);
    font: inherit;
    font-size: var(--text-sm);
    line-height: var(--leading-tight);
}

.reaction-form {
    margin: 0;
}

button.reaction {
    cursor: pointer;
    transition:
        background-color var(--duration-fast) var(--easing),
        border-color var(--duration-fast) var(--easing),
        color var(--duration-fast) var(--easing);
}

button.reaction:hover {
    background-color: var(--colour-surface-sunken);
    border-color: var(--colour-border);
    color: var(--colour-ink);
}

/* Pressed state: colour and a filled icon, never a change of size. A control that grows when it is active
   moves everything after it on the row, and this one is pressed twice in a row all the time. */
.reaction--active {
    color: var(--colour-primary);
}

.reaction--active .reaction__icon {
    fill: currentColor;
}

.reaction__icon {
    flex: none;
}

.reaction__count {
    font-variant-numeric: tabular-nums;
}

/* The static form is text, so it should not look like a target at all. */
.reaction--static {
    padding-inline: 0;
}
