/*
 * Rendered Action Text content, themed to our OKLCH design tokens. The gem's CSS is
 * pulled into the `base` layer so our `components`-layer rules win, and its `--lexxy-*`
 * variables are remapped to our tokens (so it retints with the brand and flips in dark
 * mode for free). Mirrors Fizzy's vendoring approach.
 *
 * Bulk-included via `stylesheet_bundle "shared"` → present in both the admin and public
 * layouts. The editor's own 29kb of CSS is admin-only: see admin/lexxy.css.
 */
@import url("/assets/lexxy-variables-a4c922d5.css") layer(base);
@import url("/assets/lexxy-content-b2bd89df.css") layer(base);

:root {
  /* Ink scale → our warm near-neutrals (flip to dark automatically). */
  --lexxy-color-ink: var(--color-ink);
  --lexxy-color-ink-medium: var(--color-ink-medium);
  --lexxy-color-ink-light: var(--color-ink-light);
  --lexxy-color-ink-lighter: var(--color-ink-lighter);
  --lexxy-color-ink-lightest: var(--color-ink-lightest);
  --lexxy-color-ink-inverted: var(--color-on-brand);

  /* Editor + code surfaces match our form inputs / canvas. */
  --lexxy-color-canvas: var(--color-surface-raised);
  --lexxy-color-code-bg: var(--color-canvas);

  /* Accent → brand (active toolbar buttons, selection, links). */
  --lexxy-color-accent-dark: var(--color-brand-strong);
  --lexxy-color-accent-medium: var(--color-brand);
  --lexxy-color-accent-light: var(--color-brand-soft);
  --lexxy-color-accent-lightest: var(--color-brand-tint);
  --lexxy-color-blue: var(--color-brand);
  --lexxy-color-link: var(--color-link);

  /* Status hues. */
  --lexxy-color-red: var(--color-danger);
  --lexxy-color-green: var(--color-positive);

  /* Tables / borders. */
  --lexxy-color-table-cell-border: var(--color-border);

  /* Shape + type to match the admin. */
  --lexxy-font-mono: var(--font-mono);
  --lexxy-text-small: var(--text-small);
  --lexxy-radius: var(--radius-small);
  --lexxy-shadow: var(--shadow);
  --lexxy-focus-ring-color: var(--color-brand-strong);
}

@layer components {
  /* Block alignment carried on a class (see lib/lexxy/text_alignment.js for why the editor can't
     store it as an inline text-align). Deliberately physical, not logical: the toolbar's
     left/right buttons mean visual left/right — an explicit editorial choice — where the rest of
     the CMS leaves prose to flow from the locale's start. */
  /* A Custom HTML block (HtmlEmbed). Inline-block so it sits inside its paragraph and a centred
     paragraph (text-align) centres it; capped to the content column so a fixed-size iframe can't
     overflow and force sideways scroll on a phone. */
  .html-embed { display: inline-block; max-inline-size: 100%; }
  .html-embed iframe { max-inline-size: 100%; }

  /* In the editor an embedded iframe (a Custom HTML block, or a video) is a preview: it renders the
     real content but mustn't swallow clicks, or the block can't be selected or deleted. Scoped to
     the attachment decorator ([data-lexxy-decorator]), which exists only in the editor — on the
     public page the iframe stays fully interactive. */
  action-text-attachment[data-lexxy-decorator] iframe { pointer-events: none; }

  .lexxy-content .lexxy-align-left { text-align: left; }
  .lexxy-content .lexxy-align-center { text-align: center; }
  .lexxy-content .lexxy-align-right { text-align: right; }
  .lexxy-content .lexxy-align-justify { text-align: justify; }

  /* Pin galleries LTR so the editor (grid) and live page (inline-flex) order images the
     same under RTL — parity over locale-flow for a row of images. */
  .attachment-gallery { direction: ltr; }

  /* The prose column is the yardstick for anything inside the body that has to fit it — today the
     galleries below. A container, not a media query: the same body renders in the admin's narrow
     editor pane and across a full page, and only the column's own width says what fits. */
  .lexxy-content { container: prose / inline-size; }

  /* A gallery is a row, and the editor draws it: Lexxy groups adjacent images into one gallery and
     stamps the count on it (attachment-gallery--N), so "how many across" is "how many images in
     this group" — a blank line between two groups makes two rows. Past six a row reads as a
     filmstrip rather than photographs, so seven or more falls back to three across, a grid.
     Nothing is cropped, and a short last row centres rather than hugging the start. */
  .lexxy-content .attachment-gallery {
    --gallery-columns: 3;

    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: var(--inline-space);
  }
  .lexxy-content .attachment-gallery--2 { --gallery-columns: 2; }
  .lexxy-content .attachment-gallery--3 { --gallery-columns: 3; }
  .lexxy-content .attachment-gallery--4 { --gallery-columns: 4; }
  .lexxy-content .attachment-gallery--5 { --gallery-columns: 5; }
  .lexxy-content .attachment-gallery--6 { --gallery-columns: 6; }
  /* A gallery of one only reaches us from an import (the editor dissolves it back into a plain
     image): hold it to a width the 800×600 variant fills without being blown up. */
  .lexxy-content .attachment-gallery--1 {
    --gallery-columns: 1;
    max-inline-size: 30rem;
    margin-inline: auto;
  }

  /* The editor asks for a row; the column decides how much of it fits. A photograph stops being one
     below about 200px, so each count keeps its row only while the column can pay for it (n × 200px
     plus the gaps) and otherwise halves into two balanced rows — a six becomes 3 + 3, a five 3 + 2,
     a four 2 + 2. Measured against the prose column, not the viewport, so the admin's editor pane
     halves on its own width — narrower than the page's column, so she sees the more conservative
     reading of her grouping (a four pairs up there, goes four across live), never a row the page
     won't render.
     Thresholds in px, not rem: the floor is a fact about photographs, not about type (and the root
     font here is 17px, which quietly moves every rem). Widest first — each block overrides the one
     above it. */
  @container prose (width < 1240px) {
    .lexxy-content .attachment-gallery--6 { --gallery-columns: 3; }
  }
  @container prose (width < 1035px) {
    .lexxy-content .attachment-gallery--5 { --gallery-columns: 3; }
  }
  @container prose (width < 825px) {
    .lexxy-content .attachment-gallery--4 { --gallery-columns: 2; }
  }
  /* Narrower than three photographs: everything pairs up, and a phone lands here. */
  @container prose (width < 620px) {
    .lexxy-content .attachment-gallery { --gallery-columns: 2; }
    .lexxy-content .attachment-gallery--1 { --gallery-columns: 1; }
  }

  /* The row's cells. On the page each image arrives wrapped in <action-text-attachment>; inside the
     editor Lexical renders the same image as a bare <figure> decorator, so both are cells or the
     editor lays the row out on its own terms and lies about the result. Each takes its share of the
     row; a wide one shrinks rather than spilling. */
  .lexxy-content .attachment-gallery > :is(action-text-attachment, figure.attachment) {
    flex: 0 1 calc((100% - (var(--gallery-columns) - 1) * var(--inline-space)) / var(--gallery-columns));
  }
  /* Lexical parks a <br> at the end of the gallery block. As a flex item it claims a cell and a gap,
     which is enough to wrap the last photo onto a row of its own — drop it from the flow. */
  .lexxy-content .attachment-gallery > br { display: none; }
  /* Lexxy sizes .attachment--preview to fit-content, so force the figure and its image to the full
     column width; the height follows the image's own aspect ratio. */
  .lexxy-content .attachment-gallery figure { display: block; margin: 0; inline-size: 100%; text-align: center; }
  /* On the page the gallery's gap parts the photos, so Lexxy's side padding on each figure would
     only inset them from the row's edges — and, as a fixed width in every cell, skew the shares of a
     justified row (below). The editor keeps it: it frames the selection outline there. */
  .lexxy-content .attachment-gallery > action-text-attachment > figure { padding-inline: 0; }
  .lexxy-content .attachment-gallery figure > img {
    display: block;
    inline-size: 100%;
    max-inline-size: 100%;
    block-size: auto;
  }

  /* A row mixing portrait and landscape photos, given equal columns, stands each portrait nearly
     twice its neighbour's height. Such a row lays out justified instead: each photo's share follows
     its shape (the nearest common one, named by the image partial — ImagesHelper), so the row keeps
     one height, and it still wraps once the photos would shrink below about 9rem tall. On the page
     only: the editor's figures carry no shape. */
  .lexxy-content .attachment-gallery:has(.attachment--portrait):has(.attachment--landscape) {
    > action-text-attachment { flex: var(--shape) 1 calc(var(--shape) * 9rem); }
    figure > img { aspect-ratio: var(--shape); object-fit: cover; }
  }
  .lexxy-content .attachment-gallery > action-text-attachment {
    &:has(.attachment--16x9) { --shape: 1.7778; }
    &:has(.attachment--3x2) { --shape: 1.5; }
    &:has(.attachment--4x3) { --shape: 1.3333; }
    &:has(.attachment--1x1) { --shape: 1; }
    &:has(.attachment--3x4) { --shape: 0.75; }
    &:has(.attachment--2x3) { --shape: 0.6667; }
    &:has(.attachment--9x16) { --shape: 0.5625; }
  }

  /* Audio players: capped, full-width on narrow screens (Lexxy's fit-content collapses them). */
  .lexxy-content .attachment--audio { inline-size: min(100%, 28rem); }
  .lexxy-content .attachment--audio audio { inline-size: 100%; }
  .lexxy-content .attachment--file .attachment__link {
    display: inline-flex;
    align-items: center;
    gap: 0.5em;
  }
  /* An editor-embedded iframe (e.g. a Google Map) carries fixed width/height attributes; cap its
     width to the content column so it can't overflow and force sideways scroll on a phone. */
  .lexxy-content iframe { max-inline-size: 100%; }

  /* A body image sits in a container that already has a width — a gallery cell, a table cell
     from an imported layout — but its own width came from the attributes, which the container
     then overrides, leaving nothing definite to lay out before the image loads. Taking the
     container's width gives the browser a width, and the height follows from the attributes'
     ratio, so the box is reserved instead of springing open on arrival. */
  .lexxy-content .attachment--preview img { inline-size: 100%; }

  /* Width capped at what the height cap allows — see the hero rule in layout.css. */
  .lexxy-content .attachment--file .attachment__preview {
    --cap: 3rem;
    max-block-size: var(--cap);
    max-inline-size: min(100%, calc(var(--cap) * var(--ratio, 100)));
    block-size: auto;
  }

  /* Video states: not-ready placeholder, transcoding note, failed (named by title). */
  .lexxy-content .attachment--video .attachment__placeholder { color: var(--color-muted); font-style: italic; }
  .lexxy-content .attachment--video .attachment__placeholder--failed { color: var(--color-danger); font-style: normal; }
  .lexxy-content .attachment--video .attachment__status {
    display: block;
    margin-block-start: 0.25rem;
    font-size: 0.875em;
    color: var(--color-muted);
  }

  /* The WhatsApp-number attachable sits inline in prose (a tap-to-chat link), so its
     attachment wrapper mustn't box it onto its own line. */
  .lexxy-content action-text-attachment:has(:is(.wa-contact, .phone-number, .chat-group-link, .email-contact)) { display: inline; }
  .lexxy-content :is(.wa-contact, .phone-number) { white-space: nowrap; font-variant-numeric: tabular-nums; }
  /* A number stays LTR inside RTL prose. Their partials say dir="ltr", but the editor's
     sanitizer strips dir from attachment content, so the editor needs it in CSS. */
  :is(.lexxy-content, .lexxy-editor__content) :is(.wa-contact, .phone-number) { direction: ltr; unicode-bidi: isolate; }
  /* The address reads as a link even before Stimulus turns it into one (it ships href-less, as
     two halves, so it can't be scraped) — and stays on one line inside Hebrew prose. */
  .lexxy-content .email-contact { white-space: nowrap; text-decoration: underline; }
  /* An embedded group reads as an inline text link, tagged with the WhatsApp mark so it's
     clearly a group link — not a button. */
  .lexxy-content .chat-group-link { text-decoration: underline; }
  .lexxy-content .chat-group-link::before {
    content: "";
    display: inline-block;
    inline-size: 1em;
    block-size: 1em;
    margin-inline-end: 0.25em;
    vertical-align: -0.15em;
    background-color: var(--color-whatsapp);
    -webkit-mask: var(--glyph-whatsapp) center / contain no-repeat;
    mask: var(--glyph-whatsapp) center / contain no-repeat;
  }

  /* Collapsible "toggle" section (lib/lexxy/collapsible.js) — a summary line that reveals the
     content nested under it. Deliberately unscoped: the editor's contenteditable is
     .lexxy-editor__content while the page is .lexxy-content, and our node builds the same markup
     in both, so one rule set keeps writing and reading identical.

     The disclosure triangle is ours, not the browser's. Lexxy's editor CSS already sets
     `list-style: none` and hides ::-webkit-details-marker on every summary inside the editor, so
     a native marker would show on the page and be missing while writing. */
  .lexxy-toggle {
    margin-block: var(--block-space);
  }

  /* Normal inline flow, and no weight of its own. `display: flex` here would make every run of the
     summary — each <strong>, each stretch of plain text — its own flex item, so anything longer
     than a few words wraps into fragments with gaps torn between them. And the summary takes rich
     text: an editor who wants a bold heading bolds it, where forcing a weight would override that
     and leave the emphasis they did author nothing to stand out against. */
  .lexxy-toggle__summary {
    cursor: pointer;
    list-style: none;
  }
  .lexxy-toggle__summary::-webkit-details-marker { display: none; }
  /* Undo the button chrome the editor paints onto every summary in its scope — inside the body
     this is prose, not a control. */
  .lexxy-editor__content .lexxy-toggle__summary {
    background: none;
    border-radius: 0;
    padding: 0;
    font-size: inherit;
    line-height: inherit;
  }

  /* A triangle that points along the reading direction when closed and down when open — drawn
     with a border so it needs no glyph, and rotated from the inline axis so RTL is free. */
  .lexxy-toggle__summary::before {
    content: "";
    display: inline-block;
    inline-size: 0;
    block-size: 0;
    margin-inline-end: 0.5em;
    border-block: 0.3em solid transparent;
    border-inline-start: 0.45em solid currentColor;
    border-inline-end: 0;
    transition: rotate 120ms ease-out;
  }
  /* Closed needs no RTL rule: the border sits on the inline-start edge, so the triangle already
     points the way the text runs. Open has to turn toward the content, which is clockwise in LTR
     and anticlockwise in RTL — a single `rotate: 90deg` would point it up on a Hebrew page. */
  .lexxy-toggle[open] > .lexxy-toggle__summary::before { rotate: 90deg; }
  [dir="rtl"] .lexxy-toggle[open] > .lexxy-toggle__summary::before { rotate: -90deg; }

  @media (prefers-reduced-motion: reduce) {
    .lexxy-toggle__summary::before { transition: none; }
  }

  .lexxy-toggle__content { padding-block-start: var(--block-space-half); }
  /* The summary already spaces the section; a first paragraph adding its own doubles the gap. */
  .lexxy-toggle__content > :first-child { margin-block-start: 0; }
  .lexxy-toggle__content > :last-child { margin-block-end: 0; }

  /* A link to WhatsApp wears its mark, whichever number or group it opens: wa.me, whatsapp.com,
     or a site's own /whatsapp… short address. After the text, not before: a Hebrew prefix
     (ה, ב, ל…) often sits just outside the link, and a mark in front would split the word.
     A .btn--whatsapp draws its own. */
  .lexxy-content a:is([href*="wa.me/"], [href*="whatsapp.com"], [href*="/whatsapp"]):not(.btn)::after {
    content: "";
    display: inline-block;
    inline-size: 1em;
    block-size: 1em;
    margin-inline-start: 0.3em;
    vertical-align: -0.15em;
    background-color: var(--color-whatsapp);
    -webkit-mask: var(--glyph-whatsapp) center / contain no-repeat;
    mask: var(--glyph-whatsapp) center / contain no-repeat;
  }
}
