/* Lexxy rich text editor. Shadows the gem's own lexxy.css aggregator so the
   gem stylesheets land in our cascade layers, with its palette mapped onto
   the house tokens — monochrome ink, editor chrome stays quiet.

   The hazard is LAYER ORDER, not specificity: the gem's stylesheets are
   imported into `base`, so any bare element rule we write in `components`
   beats all of them however weak its selector — which is how the toolbar once
   rendered as black squares (de693f3). Keep the gem in `base`, and never paint
   a bare control in `components`. (The gem does use :where() in places, but it
   also ships unwrapped rules; specificity is not what saves us here.)

   Everything the gem can be told through a custom property is told that way
   rather than overridden with a selector — Basecamp, who wrote it, themes it
   the same way.

   Two composers, both wrapped in .composer, both sized through the gem's own
   variables (Hanshi 06 and 11). .composer is the BOXED one: long forms, where
   the writing area must read as an enclosed place before you enter it.
   .composer--compact is the LEAN one: comments, chat, notes — no frame at
   all, because the sheet is the field. */
@import url("/assets/lexxy-variables-3fef4323.css") layer(base);
@import url("/assets/lexxy-content-0ff2f961.css") layer(base);
@import url("/assets/lexxy-editor-5b842411.css") layer(base);

:root {
  --lexxy-color-ink: var(--color-ink);
  --lexxy-color-ink-medium: var(--color-ink-subtle);
  --lexxy-color-ink-light: var(--color-ink-faint);
  --lexxy-color-ink-lighter: var(--color-line);
  --lexxy-color-ink-lightest: var(--color-surface);
  --lexxy-color-ink-inverted: var(--color-canvas);

  --lexxy-color-canvas: var(--color-canvas);
  --lexxy-color-link: var(--color-link);

  --lexxy-color-accent-dark: var(--color-ink);
  --lexxy-color-accent-medium: var(--color-ink-subtle);
  --lexxy-color-accent-light: var(--color-ink-faint);
  --lexxy-color-accent-lightest: var(--color-surface);

  --lexxy-color-selected: var(--color-selected);
  --lexxy-color-selected-dark: var(--color-accent);

  /* The gem ships GitHub-light hexes for these and derives the code background
     from --lexxy-color-ink-lightest, which we map to --color-surface — 20% L in
     dark mode. Left unmapped, `punctuation` (#24292e, ~24% L) sits invisible on
     it. We have no syntax palette, so the eight roles collapse onto the inks
     plus the two hues the app already spends. */
  --lexxy-color-code-token-att: var(--color-accent-ink);
  --lexxy-color-code-token-comment: var(--color-ink-faint);
  --lexxy-color-code-token-function: var(--color-ink);
  --lexxy-color-code-token-operator: var(--color-ink-subtle);
  --lexxy-color-code-token-property: var(--color-selected-ink);
  --lexxy-color-code-token-punctuation: var(--color-ink-subtle);
  --lexxy-color-code-token-selector: var(--color-positive-ink);
  --lexxy-color-code-token-variable: var(--color-ink);

  /* Attachment icon fill and border. Unmapped, the gem leaks its own blue and
     purple into a palette that is ink plus one red. */
  --lexxy-color-blue: var(--color-ink-subtle);
  --lexxy-color-purple: var(--color-ink-subtle);
  /* The gem derives its "selected hover" from accent-light, which we map to a
     mid ink — far too heavy for a wash. Every wake state in a composer is the
     same surface fill, so say so once here. */
  --lexxy-color-selected-hover: var(--color-surface);
  --lexxy-color-red: var(--color-negative);
  --lexxy-color-green: var(--color-positive);

  --lexxy-font-base: var(--font-sans);
  --lexxy-font-mono: var(--font-mono);
  --lexxy-text-small: var(--text-small);
  --lexxy-radius: var(--border-radius);
  --lexxy-shadow: var(--shadow);

  /* Focus is shu inside the editor too — the toolbar controls and a selected
     node are the same mark, so they read as one language with the rest of the
     app. The offset goes to 0 because the gem insets its ring by -2px, which
     eats into small toolbar buttons; this is what Basecamp does, and they
     wrote the gem. Suppressing the ring and re-adding it elsewhere was the
     workaround this replaces. */
  --lexxy-focus-ring-color: var(--color-accent);
  --lexxy-focus-ring-size: var(--focus-ring-size);
  --lexxy-focus-ring-offset: 0;

  --lexxy-toolbar-button-size: 1.75rem;
}

@layer components {
  /* ——— The boxed composer (Hanshi 06) ——— */

  /* The wrapper provides the frame, so the editor doesn't draw a second one
     (fizzy's treatment). Scoped to .composer: an element selector standing on
     its own in this layer is exactly what flattened the toolbar once. */
  .composer lexxy-editor {
    background: transparent;
    border: none;
  }

  /* The frame carries the focus ring — HANSHI 06: "hairline frame, shu focus
     ring on the frame". That is a design decision, not the old workaround: the
     editor body no longer draws anything of its own to suppress, because
     base.css scopes :focus-visible to controls rather than everything. */
  .composer {
    border: var(--border);
    border-radius: var(--border-radius);
    background-color: var(--color-canvas);

    &:focus-within {
      outline: var(--focus-ring);
      outline-offset: var(--focus-offset);
    }
  }

  /* The prompt is a voice, not a field: ink-faint at full size rather than the
     gem's dimmed copy of whatever colour it inherits. */
  .composer .lexxy-editor__content::before {
    color: var(--color-ink-faint);
    opacity: 1;
  }

  /* A phone writes plainly — chalet's rule, on fizzy's signal: where nothing
     can hover, no composer shows a toolbar, and the chat's toggle goes with
     it (chat-composer.css). Just a line and the words. */
  @media (any-hover: none) {
    .composer lexxy-toolbar {
      display: none;
    }
  }

  /* Tools are monochrome ink glyphs. Hover and the active tool — including the
     tools inside a dropdown — are the same surface fill, never a colour; left
     alone the gem reaches for its selection blue. */
  .composer lexxy-toolbar {
    color: var(--color-ink-subtle);

    /* At rest a tool stands on whatever the composer stands on: the gem
       paints every bare button in canvas, which reads as a white chip on
       any tint (the panel's, a comment's). */
    .lexxy-editor__toolbar-button {
      background-color: transparent;
    }

    [aria-pressed="true"],
    .lexxy-editor__toolbar-button:is(:hover, :active):not([aria-disabled="true"]) {
      color: var(--color-ink);
      background-color: var(--color-surface);
    }
  }

  /* The toolbar wakes on focus; until then the composer is frame and prompt.
     Only while *empty and unfocused*: a composer that shed its toolbar on blur
     would yank the submit button out from under the pointer that just left it.
     The gem maintains .lexxy-editor--empty for us. A revealed composer is
     exempt: its frame-and-prompt face is the placeholder line it replaced
     (reveal.css), so it arrives awake — toolbar showing before focus even
     lands — and never asks a second click (user, 2026-08-11). */
  .composer:has(lexxy-editor.lexxy-editor--empty):not(:focus-within, .reveal__content) lexxy-toolbar {
    display: none;
  }

  /* Dropdowns (link, colour, overflow) are floats: hairline, the float radius,
     the one warm shadow. The gem draws a 2px accent frame instead. */
  .composer [data-dropdown-panel] {
    border: var(--border);
    border-radius: var(--border-radius-float);
  }

  /* The @-mention menu is a float too, and it is how mentions are reached —
     the lean composer has no toolbar button for them. */
  .lexxy-prompt-menu {
    border: var(--border);
    border-radius: var(--border-radius-float);
  }

  /* ——— The rhythm, both sides of the glass ——— */

  /* Enter moves one line, not one section. The gem hangs 1rem under every
     block, so a run of paragraphs reads as a stack of filed sections and
     typing feels like completing a form rather than writing. Basecamp's own
     answer for this editor (fizzy) is these two declarations: half a line of
     content margin, and none at all between consecutive paragraphs. A blank
     line then means what it says — an empty paragraph you typed on purpose.

     `p:has(+ p)` and not `p + p`: the gem sets bottom margins only, so the gap
     between two paragraphs belongs to the first of them.

     The class marks editor-authored markup on BOTH sides — the gem puts it on
     lexxy-editor, and layouts/action_text/contents/_content wraps every
     rendered body in it — so one rule governs composing and reading alike.
     A caller passing its own `class:` drops the gem's default, which is why
     rich_text_helper spells lexxy-content out. */
  .lexxy-content {
    --lexxy-content-margin: 0.5lh;

    /* Fizzy's paragraph rhythm, verbatim (its lexxy.css:161): a paragraph
       followed by another gives up its margin, so consecutive lines sit
       flush and only a heading, a list or a rule opens a gap. This is the
       behaviour we ported fizzy for, and it stands on every surface — I
       argued against it for long-form prose and was wrong to (user,
       2026-08-29). Chat goes one step further, chalet's way (messages.css). */
    p:has(+ p) {
      margin: 0;
    }
  }

  /* ——— The lean composer (Hanshi 11) ——— */

  /* No frame: the sheet is the field. At rest, a hairline rule and the
     prompt; on focus the toolbar wakes and that is the whole signal. */
  .composer--compact {
    border: none;
    border-block-start: var(--border);
    border-radius: 0;
    padding-block-start: var(--block-space-half);
    background-color: transparent;
  }

  /* Where the surface already says "you are typing here", the shu ring on top
     of it reads as a stray red border. Ruled three times now: on the lean
     composer beside the avatar and on the sheet's notes field (user,
     2026-08-10), and again over both (user, 2026-08-30). Recorded under
     HANSHI's Deviations, since 06 rules a ring on the frame.

     Stated once for both families rather than a third copy — the sheet's rule
     was written out in todo-form.css, and deleting that file's copy is what put
     the ring back on the notes field and, for the first time, on the card's,
     which renders into the same `.todo-fields` grid. */
  .composer--compact:focus-within,
  .todo-fields .composer:focus-within {
    outline: none;
  }

  /* Comment boxes stay small until you mean it — Basecamp's "Add your
     comment…" pattern, done with the gem's own row variable.

     The gem declares --lexxy-editor-rows on lexxy-editor itself, so a value
     inherited from the wrapper would lose — set it on the element. The two
     heights are the compact composer's to retune (`--composer-rows`,
     `--composer-rows-at-rest`): the chat's line is one row either way
     (chat-composer.css). */
  .composer--compact {
    --composer-rows: 6lh;
    --composer-rows-at-rest: 2lh;
  }

  .composer--compact lexxy-editor {
    --lexxy-editor-rows: var(--composer-rows);
  }

  .composer--compact:has(lexxy-editor.lexxy-editor--empty):not(:focus-within) lexxy-editor {
    --lexxy-editor-rows: var(--composer-rows-at-rest);
  }

  /* Without a frame the toolbar's own rule would be a second line competing
     with the margin line, so the tools stand bare above the text. */
  .composer--compact lexxy-toolbar {
    border-block-end: none;
  }

  /* A composer with no box at all has nothing to hold its words away from, so
     the gem's padding stops being breathing room and becomes an indent: on the
     message sheet it set the body 1ch right of the title it belongs under
     (user, 2026-08-29), which is the one edge the sheet is built on.

     On the element, not the wrapper — the gem declares it there, so an
     inherited value would lose (same story as --lexxy-editor-rows). Written
     once here rather than per surface: comments/_composer, comments/edit and
     the message edit all wear this pair and all wanted it. */
  .composer--compact.borderless lexxy-editor {
    --lexxy-editor-padding: 0px;
  }
}
