/* Facturette admin — the small amount of layout Polaris cannot express for us.
 *
 * Loaded from a file rather than an inline <style>. The CSP does allow 'unsafe-inline' for
 * style-src (Polaris needs it), so an inline block would work — but app.js is already a file for
 * the script-src reason, and keeping the stylesheet next to it means both are covered by
 * PublicStaticFilesTests' allowlist instead of hiding in the shell.
 */

/* Every page's markup sits in a [data-page] wrapper so the router can reveal one at a time.
 * That wrapper costs the page its spacing: Polaris spaces s-page's OWN children, with a selector
 * that stops matching once a wrapper is in between. Measured in the browser — banner to banner
 * and banner to section were 0px inside the wrapper and 16px as direct children of s-page.
 *
 * 16px is not a guess: it is what Polaris itself applies, and it is exactly the `base` gap token
 * (the scale measured `none`=0, `small-100`=12, `base`=16, `large-100`=20). An s-grid wrapper
 * would carry the token instead of the number, but s-grid forces `display: contents` on its host
 * and that fights the `hidden` attribute the router relies on.
 */
s-page > [data-page] {
  display: grid;
  /* minmax(0, 1fr) AND NOT the default `1fr`, which is `minmax(auto, 1fr)`.
   *
   * A grid track's automatic minimum is its item's MIN-CONTENT, so the default lets a wide table
   * widen the very container that is supposed to bound it — and then a feedback loop closes:
   * `s-table` sizes itself responsively against the room it is offered, the track hands it its own
   * min-content, so it is always offered exactly enough and never reflows. Measured at a 500px
   * frame before this line: the invoice table's min-content is 519px, the track grew to 519, the
   * grid and the stack beside it stretched to 519 too, and the whole DOCUMENT scrolled sideways
   * (559px for 500px of viewport) while Polaris sat in table mode believing it had room.
   *
   * Capping the track's minimum at 0 breaks the loop and hands the decision back to the component.
   * Re-measured across the range: ≥ 700px it renders as a table, ≤ 560px it switches to its own
   * list rendering, and it fits its container at 1200 / 700 / 560 / 500 / 469 / 420 / 360px with
   * no horizontal scrollbar anywhere — including the seven-column Factures table, which is the one
   * that used to overflow. Nothing was needed on the tables themselves.
   */
  grid-template-columns: minmax(0, 1fr);
  gap: 16px;
  /* Without this the single visible page stretches its sections down the whole frame. */
  align-content: start;
}

/* Re-assert what `display: grid` above overrides — the UA's `[hidden] { display: none }` is a
 * lower-priority rule, so every page would render at once. This is the single line standing
 * between the router and showing all five pages stacked.
 */
s-page > [data-page][hidden] {
  display: none;
}

/* `hidden` must actually hide — and on a Polaris element it does not.
 *
 * Every `s-*` element renders as `display: contents`, which is an AUTHOR rule and therefore outranks
 * the UA's `[hidden] { display: none }`. The element then generates no box of its own while its TEXT
 * CHILDREN keep rendering, so `hide()` appears to do nothing.
 *
 * Measured in a browser on 2026-07-30: the invoices page kept "Chargement…" visible above a fully
 * loaded table — 1 403 px² of text, with the `hidden` attribute correctly set. Banners and buttons
 * escaped it because they wrap their content in child elements, which their own shadow root hides;
 * exactly ONE of the thirteen hidden elements on the page was leaking, and it was the only one whose
 * content is a bare text node. That asymmetry is why this needs a rule and not a habit.
 *
 * No `!important`: document styles already beat a shadow root's `:host` rules. Verified both ways.
 */
[hidden] {
  display: none;
}

/* s-grid renders its host as `display: contents`, so the host generates no box: margins on it do
 * nothing, and the section's spacing does not carry across it. Measured inside a section, every
 * gap was 12px except the one FOLLOWING a grid, which was 0 — the field after a row of columns
 * collided with that row's "14 chiffres" helper text.
 *
 * Giving the host a real box restores the rhythm; the component's own grid lives on an inner
 * element, so the columns are unaffected (re-measured: 3 x 277px, same row, before and after).
 * `:not(:last-child)` so a grid ending a section does not pad the bottom of the card.
 */
s-section > s-grid {
  display: block;
}

s-section > s-grid:not(:last-child) {
  margin-block-end: 12px;
}

/* s-stack is the SAME BUG, one component over, and it bites the same way: `display: contents`, no
 * box, so the section's spacing does not carry across it either.
 *
 * Measured on the invoices page: the gap between the bottom of "Exporter en CSV" and the top of the
 * table's header row was exactly 0px — the button sat welded to the table. Reported by the merchant,
 * not by a test, because nothing is broken in that state; it just looks wrong.
 *
 * Same treatment and same 12px as the grid above, so the rhythm inside a section stays one value.
 * The component's own flex lives on an inner element, so a stack laid out with
 * justifyContent="space-between" is unaffected (re-measured: count still at x=173, button still
 * ending at x=1107, still one line, before and after).
 */
s-section > s-stack {
  display: block;
}

s-section > s-stack:not(:last-child) {
  margin-block-end: 12px;
}

/* And s-table, for the third time. Measured on the same page: the pager's buttons sat welded to the
 * last row, 0px, because the TABLE is the element with no box — it can neither carry a bottom margin
 * nor let the section's spacing reach the sibling after it.
 *
 * The pattern is worth naming rather than fixing case by case: EVERY `s-*` element that renders
 * `display: contents` breaks Polaris' own `s-section > *` spacing, and the symptom is always the
 * same — the gap FOLLOWING it is zero while every other gap in the card is 12px. Before adding a
 * new element as a direct child of a section, check `getComputedStyle(el).display` and give it a
 * box here if it is `contents`.
 *
 * The real <table> lives in the shadow root, so the host becoming a block changes nothing about the
 * table itself (re-measured: 934px wide and no document overflow, before and after).
 */
s-section > s-table {
  display: block;
}

s-section > s-table:not(:last-child) {
  margin-block-end: 12px;
}

/* A <form data-save-bar> wraps several sections, and it is the same wrapper problem again:
 * Polaris' spacing selector does not reach through it, so the sections inside would touch.
 * Same treatment, same token value as the page wrapper above.
 */
form[data-save-bar] {
  display: grid;
  gap: 16px;
  align-content: start;
}

/* The Liquid snippet a merchant copies into a Shopify notification template (chantier A4.2).
 *
 * `pre` already has a box, so Polaris' `s-section > *` spacing reaches it — unlike the three
 * `display: contents` elements above, it needs no rescue, only styling. What it does need is
 * `overflow-x: auto`: the snippet's longest line is a metafield path that does not wrap, and
 * without this the whole document scrolls sideways on a narrow frame. That is the same failure
 * `s-page > [data-page]` was fixed for, arriving through a different element.
 *
 * `white-space: pre` and not `pre-wrap` because this is CODE: wrapping Liquid mid-attribute hides
 * its structure, and the merchant is reading it to find where their own text goes. Copying is not
 * the reason — an earlier version of this comment claimed a soft wrap would be copied as a line
 * break, and it would not: the copy button reads `textContent`, where soft wraps insert nothing.
 * See `.link-value` below, which wraps for exactly that reason.
 */
.snippet {
  /* The bottom margin is not decoration. What follows the snippet is an `s-button`, which renders
   * `display: contents` and therefore cannot be given a box of its own — measured in a browser at
   * exactly 0 px from the snippet, welded to it, the same symptom s-grid, s-stack and s-table each
   * produced. The margin goes on the element that HAS a box. */
  margin: 0 0 12px;
  padding: 12px;
  overflow-x: auto;
  white-space: pre;
  font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
  font-size: 13px;
  line-height: 1.5;
  border-radius: 8px;
  /* Polaris' own surface tokens, so the block follows the merchant's admin theme instead of
   * hard-coding a light background that turns unreadable in dark mode. */
  color: var(--s-color-text, inherit);
  background: var(--s-color-bg-surface-secondary, rgba(0, 0, 0, 0.05));
}

/* The copy button and its status line. A plain box around two `display: contents` elements, so
 * they get a gap from something that can actually carry one — see the comment in the fragment.
 * `[hidden]` on the status line still wins: this rule targets the wrapper, never the child.
 */
.snippet-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  align-items: center;
}

/* A button standing on its own inside a section, with something after it (chantier A6). `s-button`
 * renders `display: contents`, so Polaris' `s-section > *` spacing does not reach the sibling that
 * follows — the gap after it measures 0. The wrapper is a real box, which is the same fix as
 * `.snippet-actions` and for the same reason; it exists separately only because the name has to say
 * where it is used, and this one is not beside a snippet.
 */
.section-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  align-items: center;
}

/* And it carries the gap to whatever follows it, because the button inside cannot: measured at
 * `margin-block-end: 0` with the outcome welded to the button above it, which is the same 0 px the
 * grid, the stack and the table each produced before their own rule. Same 12 px as those.
 */
.section-actions:not(:last-child) {
  margin-block-end: 12px;
}

/* Two independent actions can share one table cell — a platform remedy and the customer link — and
 * `s-button` renders `display: contents`, so without a box around them they would touch. Same
 * treatment as `.snippet-actions`, at the tighter 8px a table row wants.
 */
.row-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: center;
}

/* The re-issued customer link, shown so the merchant can pass it on. It is a 64-character token in
 * a URL that does not wrap, so it scrolls inside its own box for the same reason `.snippet` does —
 * otherwise it sets the min-content of the whole page and the document scrolls sideways.
 */
.link-value {
  display: block;
  /* WRAPS rather than scrolls, and that is the opposite of `.snippet` above on purpose.
   *
   * `s-banner` renders `display: contents` — the fifth component in this file to do so — so this
   * element sits inside the banner's own shadow card and neither `min-width: 0` nor `overflow-x`
   * reaches the box that actually clips it: measured at 947px of URL cut off at the card's edge.
   * A 64-character token has no spaces, so only an explicit break opportunity makes it fit.
   *
   * Safe for the copy button, which reads `textContent` — a SOFT wrap inserts no character, unlike
   * the hard newlines `.snippet` must preserve.
   */
  overflow-wrap: anywhere;
  word-break: break-all;
  font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
  font-size: 13px;
  padding: 8px;
  margin-block-end: 8px;
  border-radius: 6px;
  color: var(--s-color-text, inherit);
  background: var(--s-color-bg-surface-secondary, rgba(0, 0, 0, 0.05));
}

/* The copy button and the mailto beside it — a real box, because `s-button` is `display: contents`
 * and the two would otherwise touch. Same reason as `.snippet-actions` and `.row-actions`.
 */
.link-result {
  display: flex;
  min-width: 0;
  flex-wrap: wrap;
  gap: 12px;
  align-items: center;
}

/* The logo preview. A real box for the same reason every wrapper on this page is one — the section
 * spacing is selector-based (`s-section > *`) and nothing here is an `s-*` element to inherit it.
 *
 * `max-width`/`max-height` in CSS as well as in the renderer, because they answer different
 * questions: the renderer bounds the logo on the PRINTED page, this bounds what the merchant is
 * shown. A 200 Ko PNG can be four thousand pixels wide, and unbounded it would push the admin
 * frame into a horizontal scrollbar — the exact failure `minmax(0, 1fr)` was added to close.
 *
 * The checkerboard is not decoration: a PNG with a transparent background is invisible against the
 * admin's white surface, and the merchant would read that as the upload having failed.
 */
.logo-preview {
  display: inline-block;
  max-width: 100%;
  padding: 8px;
  margin-block-end: 12px;
  border-radius: 6px;
  border: 1px solid var(--s-color-border, rgba(0, 0, 0, 0.12));
  background-color: var(--s-color-bg-surface-secondary, rgba(0, 0, 0, 0.04));
  background-image:
    linear-gradient(45deg, rgba(0, 0, 0, 0.06) 25%, transparent 25%, transparent 75%, rgba(0, 0, 0, 0.06) 75%),
    linear-gradient(45deg, rgba(0, 0, 0, 0.06) 25%, transparent 25%, transparent 75%, rgba(0, 0, 0, 0.06) 75%);
  background-size: 16px 16px;
  background-position: 0 0, 8px 8px;
}

.logo-preview img {
  display: block;
  max-width: 240px;
  max-height: 96px;
  width: auto;
  height: auto;
}
