/* ============================================================================
   Writing — the authoring surface, the add slots, the conversation
   ----------------------------------------------------------------------------
   An index card somebody is writing on, not a form somebody is filling in. The
   difference is carried by three things and by nothing else: the title is typed
   at the size it will be read at, the surface is marked by shape and one brand
   rule rather than by a fill nobody has seen before, and every optional control
   is quieter than the one field that names the thing.

   The card is small on purpose. SPEC-Authoring caps a title at 72 characters
   because a story that does not fit on a card is too big, and the measure set on
   .writing is the visual half of that cap: 72 characters across a full-width page
   look like a fragment, and across a card they look like a title.

   The surface itself stands on no script. The cap is maxlength, it opens on a GET
   and it submits on a POST, and the counter that would tick as you type buys a
   number the input already enforces. The one script in this sheet's territory is
   the dialog below, and it opens a <dialog> the server already wrote: showModal()
   is the only way to get a focus trap, an inert backdrop and Escape, and none of
   the three can be had from CSS at all.
   ========================================================================== */

/* === The surface =========================================================== */

/* Sunken paper with a brand rule down the left. That is .card-accent-* applied to
   a purpose rather than to a severity: the accent tokens in the cards sheet are
   graded by risk and none of them mean "you are writing this one". Full radius,
   like those cards, because squaring the left edge turns a rule into a callout.
   No fill of its own, no shadow and no second accent: the shape is the signal. */
.writing {
    background: var(--surface-alt);
    border: var(--border-width) solid var(--border);
    border-left: var(--border-accent) solid var(--brand);
    border-radius: var(--radius-lg);
    padding: var(--space-12) var(--space-14);
    max-width: 640px;
}

/* The title, typed at the size it is read at, one step under a page h1. Borderless
   and transparent so the line looks written on the card; a bordered box here would
   say "field", and a field is what this whole surface refuses to be. The focus
   treatment is a halo rather than an outline for the same reason: the box must not
   reappear the moment somebody clicks into it. */
.writing-title {
    display: block;
    width: 100%;
    padding: var(--space-2) 0;
    border: none;
    border-radius: var(--radius-sm);
    background: transparent;
    font-size: var(--text-2xl);
    font-weight: var(--weight-bold);
    line-height: var(--leading-tight);
    letter-spacing: var(--tracking-tight);
    color: var(--text);
}
.writing-title::placeholder { font-weight: var(--weight-normal); }
.writing-title:focus {
    outline: none;
    box-shadow: 0 0 0 var(--border-accent) var(--brand-ring);
}

/* Both boxes are the same box, so they are one rule and only the floor differs.
   The body renders through .md-content once it is saved, so it is typed in that
   face, that size and that line height; typing at one measure and reading at
   another is how a paragraph that fitted in the box turns out three lines longer
   on the card.

   field-sizing is declared bare rather than inside @supports. A browser without it
   drops the line and keeps min-height, which is the fallback the @supports block
   would have had to spell out anyway.

   The floors are eight lines and four lines of exactly the type above them, plus
   the two paddings because the reset makes every box border-box. Written as a calc
   over the tokens so a change to the scale moves the floor with it, instead of
   leaving a pixel number that used to mean eight rows. */
.writing-body,
.conversation-say textarea {
    display: block;
    width: 100%;
    padding: var(--space-5) var(--space-6);
    border: var(--border-width) solid var(--border);
    border-radius: var(--radius-md);
    background: var(--surface);
    font-family: inherit;
    font-size: var(--text-md);
    line-height: var(--leading-relaxed);
    color: var(--text-body);
    field-sizing: content;
    resize: vertical;
    transition: border-color var(--transition);
}
.writing-body { min-height: calc(8 * var(--leading-relaxed) * var(--text-md) + 2 * var(--space-5)); }
.conversation-say textarea { min-height: calc(4 * var(--leading-relaxed) * var(--text-md) + 2 * var(--space-5)); }

/* One quiet line under a control, saying what the control takes. Its two
   declarations are .form-hint's two declarations, and the duplication is
   deliberate: every other control on this surface is defined here, and one
   borrowed name is how a surface starts inheriting spacing decisions from a
   component it is not. */
.writing-hint {
    font-size: var(--text-xs);
    color: var(--text-muted);
    margin-top: var(--space-2);
}

/* The optional fields: assignee, estimate, labels. They wrap, their labels are
   muted, and they sit two steps below the title on the scale, so nothing in the
   row competes with the field that names the card.

   Styled by element rather than by classes of their own, so the markup carries no
   forms classes here and the two sheets never meet on one element. 180px is the
   basis at which three fields hold one row on a full card and fall to one per row
   on a phone. */
.writing-meta {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-6);
    margin-top: var(--space-10);
}
.writing-meta > * { flex: 1 1 180px; min-width: 0; }
.writing-meta label {
    display: block;
    font-size: var(--text-xs);
    font-weight: var(--weight-medium);
    color: var(--text-muted);
    margin-bottom: var(--space-2);
}
/* One box for both controls in this row. A field with a known set of answers is a select and a field
   somebody types into is an input, and that is the only difference the reader should be able to see:
   two boxes of different heights a gap apart is a row that looks assembled rather than designed. The
   select draws the style book's arrow, so it reads as the same dropdown as a .form-input select. */
.writing-meta input,
.writing-meta select {
    width: 100%;
    padding: var(--space-3) var(--space-5);
    border: var(--border-width) solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--surface);
    font-size: var(--text-sm);
    color: var(--text);
    transition: border-color var(--transition);
}
.writing-meta select {
    padding-right: var(--space-16);
    background: var(--select-arrow), var(--surface);
    cursor: pointer;
}

/* Placeholders are the same grey everywhere, because a placeholder that reads as
   text is a card that looks written when it is empty. */
.writing-title::placeholder,
.writing-body::placeholder,
.writing-meta input::placeholder,
.conversation-say textarea::placeholder { color: var(--text-subtle); }

/* One focus treatment for every bordered control here, and it is .form-input's:
   the border goes brand and a soft ring sits outside it. A surface that focused
   differently would be the one place in the application where the reader has to
   learn what focus looks like. */
.writing-body:focus,
.writing-meta input:focus,
.writing-meta select:focus,
.conversation-say textarea:focus {
    outline: none;
    border-color: var(--brand);
    box-shadow: 0 0 0 var(--border-accent) var(--brand-ring);
}

/* One primary button, then plain links, ruled off from the fields so the row reads
   as the end of the card rather than as another field. A link wearing .btn is a
   button and keeps the buttons sheet's size; the quiet ones are bare anchors and
   take their tone from here. */
.writing-actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-8);
    margin-top: var(--space-12);
    padding-top: var(--space-10);
    border-top: var(--border-width) solid var(--border-subtle);
}
.writing-actions a:not(.btn) {
    font-size: var(--text-base);
    color: var(--text-muted);
    transition: color var(--transition);
}
.writing-actions a:not(.btn):hover { color: var(--text-body); }

/* === The surface as a dialog =============================================== */

/* The same card, opened over the page the new one will live on.

   The shell carries no chrome of its own. A dialog with a title bar, a rule and
   a close cross in the corner would put a second heading above the surface's own
   and a third way out beside Escape and Cancel, and the surface would stop
   looking like the thing it looks like everywhere else. What is added is depth
   and a lid: a raised fill instead of the sunken one, the extra shadow, and a
   backdrop dimming the page the card will land on rather than hiding it.

   The element itself is transparent and unpadded, so the card inside is what
   the backdrop frames. margin: auto is not optional: the UA centres a modal
   dialog with it and the reset at the top of the cascade zeroes the margin on
   every element, so without this line the dialog pins itself to the top-left
   corner and the backdrop has no corner to be clicked in. */
.writing-dialog {
    margin: auto;
    padding: 0;
    border: none;
    background: transparent;
    overflow: visible;
    color: var(--text);
}
.writing-dialog::backdrop { background: var(--backdrop); }
.writing-dialog[open] { animation: writingIn var(--transition) ease; }

/* The card at dialog size. It keeps the brand rule and the radius it has on a
   page; what changes is that it is raised rather than sunken, because a sunken
   panel floating over a dimmed page reads as a hole in the backdrop. The height
   cap and the scroll are for the body: a long paste into the textarea must not
   push the commit button past the bottom of the window. */
.writing-dialog .writing {
    width: 640px;
    max-width: calc(100vw - var(--space-16));
    max-height: calc(100vh - var(--space-16));
    overflow-y: auto;
    background: var(--surface-raised);
    box-shadow: var(--shadow-xl);
}
@keyframes writingIn { from { opacity: 0; transform: translateY(-8px); } to { opacity: 1; transform: translateY(0); } }

/* === The add slots ========================================================= */

/* An empty place on the wall where a card will go. Dashed, muted and card-shaped
   rather than filled and labelled, because a button says "an action happens here"
   and this says "something is missing here". That is what lets the roadmap carry
   four of them without reading as a toolbar.

   The plus is drawn from the sheet rather than from the markup, so every slot in
   every product gets the same glyph in the same place and no page adds a second
   one with an <i>. It goes brand on hover, which is the only place the brand
   appears on this element. */
.add-slot {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-4);
    width: 100%;
    padding: var(--space-16) var(--space-10);
    border: var(--border-width) dashed var(--border);
    border-radius: var(--radius-lg);
    background: transparent;
    color: var(--text-muted);
    font-size: var(--text-sm);
    text-align: center;
    transition: background var(--transition), border-color var(--transition), color var(--transition);
}
.add-slot::before {
    content: "+";
    font-size: var(--text-xl);
    line-height: var(--leading-none);
    color: var(--text-subtle);
}
.add-slot:hover {
    background: var(--surface-hover);
    border-color: var(--border-strong);
    color: var(--text-body);
}
.add-slot:hover::before { color: var(--brand); }
.add-slot:focus-visible {
    outline: none;
    border-color: var(--brand);
    box-shadow: 0 0 0 var(--border-accent) var(--brand-ring);
}

/* The one-line variant, for the foot of a list or a table where a card-shaped hole
   would stand taller than every row above it. Worn with .add-slot: it changes the
   height and the alignment and nothing else. */
.add-slot-row {
    justify-content: flex-start;
    padding: var(--space-4) var(--space-8);
    text-align: left;
}
.add-slot-row::before { font-size: var(--text-md); }

/* === The conversation ====================================================== */

/* The thread inside the card that already wraps it, so this replaces nothing and
   claims no border of its own. A stack with a gap, because the comments are
   .divided-row and carry their own rules already. */
.conversation {
    display: flex;
    flex-direction: column;
    gap: var(--space-8);
}

/* Saying something is always open and never behind a disclosing button, so it
   needs a rule above it to mark where the thread ends and you begin. The box
   itself is the writing body at a four-line floor, set with it above. */
.conversation-say {
    padding-top: var(--space-10);
    border-top: var(--border-width) solid var(--border-subtle);
}
/* The last thing said carries no rule under it. .divided-row draws one after every
   comment and .conversation-say draws one above the box, so without this the foot
   of a thread is the same line twice, a gap apart. */
.conversation .divided-row:last-of-type { border-bottom: none; }

/* The action row under the box is .writing-actions with its rule dropped: the
   border above has already done the separating, and two rules a textarea apart
   draw a box around one control. */
.conversation-say .writing-actions {
    margin-top: var(--space-6);
    padding-top: 0;
    border-top: none;
}
