/* app.css — page and feature styles for Dobletilde.
 *
 * Loaded sitewide AFTER theme-quento.css so it can layer on top of the
 * brand/theme tokens. This file is for app-specific, page-specific, or
 * feature-specific CSS — e.g. dialog sizing, page-local layout glue,
 * one-off component overrides. The "theme" file should stay focused on
 * design tokens + WA component customization.
 *
 * Note: pre-existing app-level styles still live in theme-quento.css
 * (the .detail-*, .inbox-*, .msg-*, etc. families). Those can migrate
 * here incrementally; this file starts with what was being added new.
 */

/* ---------------------------------------------------------------------------
 * Pedidos inbox — single live region (Spec-0021).
 *
 * #inbox-content holds either the empty-state hint or the card grid, so the
 * snapshot-on-connect SSE path can outer-replace ONE stable id to swap
 * empty<->non-empty (no fragile remove-by-id of a maybe-absent #inbox-empty,
 * which Datastar v1.0.1 surfaces as PatchElementsNoTargetsFound). display:contents
 * removes the wrapper's own box so the hint and grid lay out exactly as if they
 * were direct children of .inbox.
 * ------------------------------------------------------------------------- */

.inbox__content {
  display: contents;
}

/* ---------------------------------------------------------------------------
 * App page shell — shared by the top-level, single-scroll-surface operator
 * pages (Pedidos inbox `.inbox`, order detail `.detail`).
 *
 * `.shell-main` is `overflow: hidden` so the /chat layout can own its own
 * internal scrolling. These pages are instead a single scroll surface, so each
 * acts as its own scroll container — otherwise content that doesn't fit the
 * viewport gets clipped with no way to reach it. They also share one max width
 * + horizontal centering so the layout (and its scrollbar) tracks the content
 * edge consistently rather than stretching edge-to-edge on wide monitors.
 *
 * Page-specific padding and internal flow stay on the page's own class.
 * ------------------------------------------------------------------------- */

.app-page {
  height: 100%;
  overflow-y: auto;
  max-width: 1400px;
  margin-inline: auto;
}

/* The editing-presence banner (#editing-banner) and stale-write warning
   (#stale-warning) are always-present SSE merge targets: they sit in the main
   column as empty placeholders until a presence_changed / stale-save event
   patches content into them. While empty they must occupy no space — the
   column is a flex stack with `gap`, so an empty-but-present placeholder still
   adds a gap above the Pedido card and pushes it out of alignment with the
   Cliente card. :empty collapses them; an SSE patch that adds content brings
   them back into flow. */
#editing-banner:empty,
#stale-warning:empty {
  display: none;
}

/* Plantillas (Spec-0040). Per the .app-page convention above, page-specific
   padding lives on the page's own class — same value as the admin pages'
   .dt-admin so the two simple stacked-content surfaces match. */
.templates {
  padding: var(--wa-space-l);
}
.templates__title {
  font-size: 1.5rem;
  font-weight: var(--wa-font-weight-bold);
  margin: 0;
}
.templates__hint {
  margin: 0;
  color: var(--wa-color-text-quiet);
}
.templates-suggest__title {
  font-size: 1rem;
  font-weight: var(--wa-font-weight-semibold);
  margin: 0;
}
.templates-suggest__hint {
  margin: 0;
  color: var(--wa-color-text-quiet);
  font-size: 0.9rem;
}
/* Starter / blank cards in the chooser grid: equal height (so a row's cards line
   up) with the footer pinned to the bottom — category tag bottom-left, action
   button bottom-right — regardless of how long each preview is. The grid stretches
   the cards; the card body becomes a flex column; the preview grows to fill. */
.templates-suggest__grid {
  align-items: stretch;
}
.suggestion-card {
  height: 100%;
}
.suggestion-card::part(body) {
  height: 100%;
  display: flex;
  flex-direction: column;
}
.suggestion-card__inner {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: var(--wa-space-2xs);
}
.suggestion-card__title {
  display: flex;
  align-items: center;
  gap: var(--wa-space-2xs);
}
.suggestion-card__name {
  font-weight: var(--wa-font-weight-semibold);
}
.suggestion-card__preview {
  flex: 1 1 auto;
  color: var(--wa-color-text-quiet);
  font-size: 0.9rem;
}
.suggestion-card__footer {
  display: flex;
  align-items: center;
  gap: var(--wa-space-2xs);
  margin-top: var(--wa-space-s);
}
/* Button always bottom-right (margin-left:auto pushes it right whether or not a
   tag is present — the blank card has no tag). */
.suggestion-card__footer wa-button {
  margin-left: auto;
}
/* The "Empezar en blanco" card's "+" cue — muted, so the card reads as the
   start-from-scratch escape hatch rather than a curated starter. */
.suggestion-card__blank-icon {
  color: var(--wa-color-text-quiet);
}
/* List-row card: the default card spacing (--wa-space-l) reads too loose for these
   short rows — tighten it so the header, preview, and actions sit closer. */
.template-card {
  --spacing: var(--wa-space-m);
}
/* Body laid out as a flank (see templ comment): the preview fills the left, the
   actions sit in a fixed-width column on the right so a short template doesn't
   leave the right half empty. Buttons fill that column for a tidy, aligned stack. */
.template-card__body {
  --flank-size: 11rem;
}
.template-card__actions wa-button {
  width: 100%;
}
/* A muted caption under a card's actions (e.g. "you'll be able to send this
   once Meta approves it" on a not-yet-approved template). */
.template-card__hint {
  color: var(--wa-color-text-quiet);
  font-size: 0.85rem;
}

/* Template preview — a WhatsApp-style chat bubble (Spec-0040, item 5). Used both
   as a per-row preview (TemplateBubble, from stored components) and as the live
   editor preview (LivePreview, driven by Datastar signals). white-space:pre-wrap
   preserves the body's line breaks (data-text sets textContent). */
.template-preview {
  display: flex;
  flex-direction: column;
  gap: var(--wa-space-2xs);
}
.template-preview__bubble {
  align-self: flex-start;
  max-width: 28rem;
  background-color: var(--wa-color-surface-default);
  border: var(--wa-border-width-s) solid var(--wa-color-surface-border);
  border-radius: var(--wa-border-radius-l);
  border-start-start-radius: var(--wa-border-radius-s);
  padding: var(--wa-space-s) var(--wa-space-m);
  box-shadow: var(--wa-shadow-s);
  font-size: 0.95rem;
  line-height: 1.4;
}
.template-preview__header {
  font-weight: var(--wa-font-weight-bold);
  margin-block-end: var(--wa-space-2xs);
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}
.template-preview__body {
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}
.template-preview__footer {
  margin-block-start: var(--wa-space-2xs);
  color: var(--wa-color-text-quiet);
  font-size: 0.8rem;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}
.template-preview__note {
  color: var(--wa-color-text-quiet);
  font-style: italic;
}

/* Dedicated template editor page (Spec-0040, item 2 + item 5): a back link, a
   two-column form + live-preview grid, and a preview pane that sticks while the
   form scrolls. The grid collapses to one column on narrow viewports (wa-grid). */
.templates-editor__back {
  color: var(--wa-color-text-quiet);
  text-decoration: none;
  font-size: 0.9rem;
}
.templates-editor__back:hover { text-decoration: underline; }
.templates-editor__grid {
  align-items: start;
}
.templates-editor__preview-title {
  font-size: 1rem;
  font-weight: var(--wa-font-weight-semibold);
  margin: 0;
}
.templates-editor__preview {
  position: sticky;
  top: var(--wa-space-l);
}

/* The confirm dialog's body carries a multi-line explanation (the "Enviar a Meta"
   what/why, item 4) set via data-text — preserve its line breaks + bullets. */
.template-confirm-dialog__body {
  white-space: pre-line;
}

/* ---------------------------------------------------------------------------
 * Order detail — Add-line dialog (Spec-0016).
 *
 * - Widen the dialog via the WA `--width` CSS custom property.
 * - Hold the results region at a fixed height so the dialog doesn't
 *   resize as the result count changes between queries.
 *
 * Internal layout (qty + search row) uses WA's `wa-flank` utility, so
 * there's nothing to declare here for it.
 * ------------------------------------------------------------------------- */

.detail-add-line {
  --width: 36rem;
}

.detail-add-line #add-line-results {
  height: 22rem;
  overflow-y: auto;
  margin-top: var(--wa-space-s);
}

/* ---------------------------------------------------------------------------
 * Order detail — lines table: keep row height stable when Editar/Listo toggles.
 *
 * In read mode the qty cell renders plain text and the actions cell is empty;
 * in edit mode they show a small `wa-input` + small `wa-button`s. Datastar's
 * `data-show` swaps `display: none`, so without a reservation the table
 * reflows on every toggle. We reserve enough height for the edit-mode controls
 * in both modes via `min-block-size` on the two affected cells.
 * ------------------------------------------------------------------------- */

/* `min-height` on a <td> is ignored by the CSS table layout algorithm —
   row heights are computed by the row, not the cell. So set `block-size`
   on the <tr> (HTML tables interpret it as min-height) to reserve the
   edit-mode height for every row, regardless of which `data-show` branch
   is currently visible.

   The reserved height = wa-input/wa-button at size="small" (~2.375rem) plus
   the cell's vertical padding (var(--wa-space-2xs) on each side, from the
   .detail-lines td rule in theme-quento.css). Empirically that lands at
   ~47px with the default theme; we use a calc on the form-control-height
   token so the value tracks theme changes. */
.detail-lines tbody tr,
.detail-lines tfoot tr {
  block-size: calc(var(--wa-form-control-height) + 2 * var(--wa-space-2xs));
}
.detail-line__qty,
.detail-line__money,
.detail-line__actions {
  vertical-align: middle;
}

.detail-lines .detail-lines__numeric,
.detail-lines td.detail-line__qty,
.detail-lines td.detail-line__money {
  text-align: right;
}

/* Footer row inside the order-block card — pairs the "Agregar línea"
   button (left, visible only when editing) with the Editar/Listo toggle
   (right). wa-split handles the space-between layout; we just add the
   top border + spacing so it reads as a footer. */
.detail-block__footer {
  margin-top: var(--wa-space-m, 0.75rem);
  padding-top: var(--wa-space-s, 0.5rem);
  border-top: 1px solid var(--wa-color-surface-border);
}

/* When a change originated from THIS tab, the inline script on the detail
   page adds .dt-suppress-glow to <html> for a few seconds. The SSE
   --glow class still arrives on the element (the markup is the same one
   the server broadcasts to every tab) but we disable its animation so
   the operator doesn't see a flash for an action they just took. */
.dt-suppress-glow .detail-block--glow,
.dt-suppress-glow .detail-status--glow,
.dt-suppress-glow .inbox-card--glow {
  animation: none !important;
}

/* Editable tables also reserve column widths so the columns don't shift
   horizontally when the edit-mode controls (a small wa-input in qty and
   the Resolver SKU / × / Restaurar buttons in actions) appear. Empirical
   widths: qty ~8.5rem fits the size="small" wa-input + cell padding;
   actions ~9rem fits Resolver-SKU + × side by side. */
.detail-lines--editable .detail-line__qty {
  min-inline-size: 8.5rem;
}
.detail-lines--editable .detail-line__actions {
  min-inline-size: 9rem;
}

.detail-line__money {
  font-family: var(--wa-font-family-code);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.detail-lines__total td {
  border-top: 1px solid var(--wa-color-surface-border);
  font-weight: var(--wa-font-weight-semibold);
}

/* The lines table is wrapped in a <wa-scroller> so it scrolls horizontally
   inside the card on narrow viewports instead of overflowing past the card's
   right edge. The table keeps width:100% so it stretches to fill the card
   when it fits; the scroller only kicks in (with its edge-shadow cue) once the
   rigid columns — nowrap money + edit-mode qty/actions min-widths — exceed the
   available width. Reset the WA native-styles block margin so the table sits
   flush with the rest of the card. */
.detail-lines-scroller table.detail-lines {
  margin-block: 0;
}

/* Per-line confidence dot sits at the right edge of the actions cell. The
   cell itself must stay display: table-cell (so the row's reserved
   block-size still applies), so we wrap the cell's contents in an inner
   flex row. The wrapper fills the cell's height so align-items: center
   centers against the same reserved height the qty/unit cells use. The
   ring is pinned right via margin-inline-start: auto so it stays at the
   edge whether or not the edit-mode buttons are visible. */
.detail-line__actions-inner {
  display: flex;
  align-items: center;
  gap: var(--wa-space-2xs);
  block-size: 100%;
}
.detail-line__actions-inner .confidence--sm {
  margin-inline-start: auto;
}
.confidence--sm {
  width: 16px;
  height: 16px;
}
.confidence--sm .confidence__track,
.confidence--sm .confidence__fill {
  stroke-width: 5;
}

/* ---------------------------------------------------------------------------
 * Order card / detail header — customer name first, then a meta line carrying
 * the display number and source-channel summary.
 *
 * Layout-only rules; color comes from WA utility classes (`wa-caption-s`,
 * `wa-color-text-quiet`) attached to the markup so theme switches stay clean.
 * ------------------------------------------------------------------------- */

/* The meta line under the customer name renders as an inline-flex row so the
   channel icon sits on the baseline with the surrounding numbers and dot
   separators, with a small consistent gap. */
.inbox-card__meta,
.detail__meta {
  display: flex;
  align-items: center;
  gap: 0.25rem;
  /* Override the legacy 0.8rem in theme-quento.css. The WA utility classes
     (wa-caption-*) live inside @layer wa-utilities and lose to unlayered
     rules, so the size has to be set here unlayered for it to apply.
     Body size (m = 16px) reads cleanly at arm's length. */
  font-size: var(--wa-font-size-m);
}

/* Display-number tokens (#1234) and source-message counts are numerals — use
   tabular figures so they don't shift when values change live (SSE updates). */
.inbox-card__number,
.inbox-card__meta,
.detail__meta {
  font-variant-numeric: tabular-nums;
}

/* The WhatsApp glyph rendered inline with the source-message count. Sized in
   em so it scales with the meta-line font (caption-m today, easily bumped). */
.inbox-card__channel-icon,
.detail__channel-icon {
  width: 1.1em;
  height: 1.1em;
  flex-shrink: 0;
}

/* Totals row at the bottom of each card — the left side of the footer. Sits
   opposite the "Abrir" button. Will grow to include the $ total once pricing
   lands; today it's just the line count. */
.inbox-card__totals {
  margin-right: auto;
}

/* Right-side cluster of the card header: the status pill, then the
   confidence ring. Mirrors the detail-page header layout (status pill at the
   right of the title row). */
.inbox-card__head-right {
  display: flex;
  align-items: center;
  gap: var(--wa-space-s);
  flex-shrink: 0;
}

/* ---------------------------------------------------------------------------
 * Detail-page header layout.
 *
 * Restructured so the header reads like an enlarged inbox card:
 *   [back link]
 *   [name + status]  [meta line]   [confidence ring]   [actions panel]
 *
 * Overrides the pre-existing flex rules on .detail__head in theme-quento.css.
 * Those rules predate this layout; once we collapse the legacy theme-quento
 * `.detail-*` block into here we can drop the override.
 * ------------------------------------------------------------------------- */

.detail__head {
  flex-direction: column;
  align-items: stretch;
}

/* Head-row mirrors the body grid below (.detail__grid: 2fr main + 1fr side)
   so the title-block has exactly the same width as the orderBlock card and
   the right-edge status pill lines up with the card's right edge. */
.detail__head-row {
  display: grid;
  grid-template-columns: minmax(0, 2fr) minmax(0, 1fr);
  gap: var(--wa-space-l);
  align-items: center;
}

@media (max-width: 900px) {
  .detail__head-row { grid-template-columns: 1fr; }
}

.detail__title-block {
  min-width: 0;
}

/* Action buttons flush to the right edge of their grid column (which lines up
   with the customer/conversation column below). */
.detail__head-row > .detail__actions {
  justify-content: flex-end;
}


/* ---------------------------------------------------------------------------
 * Inbox card — fixed height so cards align across rows and wrap into a tidy
 * grid. The card body (where the lines table renders) scrolls when a draft
 * has more lines than fit; header + footer stay pinned. wa-card exposes
 * `part="body"` (see assets/static/webawesome/chunks/chunk.UK3KF2N5.js).
 * ------------------------------------------------------------------------- */

.inbox-card {
  height: 22rem;
}

.inbox-card::part(body) {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
}

/* Monetary amount in the card footer — monospace for legible alignment of
   prices across cards, regardless of theme. */
.inbox-card__amount {
  text-align: right;
  font-family: var(--wa-font-family-code);
  font-variant-numeric: tabular-nums;
}

.inbox-card__qty {
  text-align: right;
}

/* Confidence ring lives inside the order-block (next to the "Pedido" h2), not
   in the page header — keeps it close to the data it summarizes and clear of
   the action buttons. */
.detail-block__title-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--wa-space-s);
  margin-bottom: var(--wa-space-s);
}

.detail-block__title-row > .detail-block__title {
  margin: 0;
}

/* ---------------------------------------------------------------------------
 * Spec-0020 — small set of style hooks; everything else (layout, gap,
 * pill shape, tag colors) comes from Web Awesome utility classes and the
 * <wa-tag> component applied directly in the markup.
 * ------------------------------------------------------------------------- */

/* Jump-link from the order-detail conversation panel to the full chat —
   the link sits in its own flex row pinned to the right of the panel. */
.detail-conversation__footer {
  display: flex;
  justify-content: flex-end;
  margin-top: var(--wa-space-s);
}
.detail-conversation__full-link {
  color: var(--wa-color-brand-on-quiet, var(--wa-color-brand-fill-loud));
  text-decoration: none;
}
.detail-conversation__full-link:hover { text-decoration: underline; }

/* ---------------------------------------------------------------------------
 * Chat page — layout formerly supplied by Tailwind utility classes.
 *
 * Web Awesome utilities cover text and simple stack/cluster behavior in the
 * markup. These rules cover app-specific geometry: the two-pane shell, fixed
 * conversation-list width, internal scroll containers, native textarea layout,
 * and attachment sizing.
 * ------------------------------------------------------------------------- */

.chat {
  display: flex;
  block-size: 100%;
  min-block-size: 0;
  min-inline-size: 0;
}

.chat-sidebar {
  display: flex;
  flex-direction: column;
  flex: 0 0 20rem;
  inline-size: 20rem;
  min-block-size: 0;
}

.chat-sidebar__header,
.chat-thread__header {
  block-size: 3.5rem;
  padding-inline: var(--wa-space-m);
  flex: 0 0 auto;
}

.chat-sidebar__header {
  align-items: center;
}

.chat-list {
  flex: 1 1 auto;
  min-block-size: 0;
  overflow-y: auto;
}

.chat-empty-list {
  padding: var(--wa-space-m);
}

.chat-list__item {
  display: block;
  padding: var(--wa-space-s) var(--wa-space-m);
}

.chat-list__name {
  min-inline-size: 0;
}

.chat-list__activity {
  margin-top: var(--wa-space-3xs);
}

.chat-thread,
.chat-thread-empty {
  flex: 1 1 auto;
  min-inline-size: 0;
  min-block-size: 0;
}

.chat-thread {
  display: flex;
  flex-direction: column;
}

.chat-thread-empty {
  display: flex;
  align-items: center;
  justify-content: center;
}

.chat-thread__header {
  justify-content: center;
}

.chat-thread__header--active {
  position: relative;
  display: flex;
  align-items: center;
  padding-inline: calc(var(--wa-space-m) + 2.75rem);
}

.chat-thread__identity {
  min-inline-size: 0;
  max-inline-size: 100%;
  text-align: center;
}

.chat-wallpaper-picker {
  /* <wa-dropdown> hosts as `display: contents` by default, so it generates no
     box and would drop its trigger into the header's centered flex flow (right
     next to the name). Force a box so `position: absolute` actually pins the
     picker to the right edge. */
  display: inline-flex;
  align-items: center;
  position: absolute;
  inset-inline-end: var(--wa-space-m);
}

.chat-thread__name,
.chat-thread__address {
  line-height: var(--wa-line-height-condensed);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.chat-thread__body {
  flex: 1 1 auto;
  min-block-size: 0;
  overflow-y: auto;
  padding: var(--wa-space-m);
}

/* Shared wallpaper backdrop. Both the full chat thread body and the
   order-detail conversation snippet read the `--chat-wallpaper-*` variables
   set on <html> by the pre-paint script in applayout, so the operator's chosen
   pattern follows them from /chat onto the order-detail page. */
.chat-thread__body,
.detail-thread {
  background-color: var(--chat-wallpaper-bg, var(--wa-color-surface-lowered));
  background-image: var(--chat-wallpaper-image, none);
  background-size: var(--chat-wallpaper-size, 160px 160px);
}

/* In the detail panel the thread is an embedded snippet inside a card (not a
   full-height scroll pane), so it gets its own padding + rounding to read as a
   contained chat surface rather than bleeding to the card edges. */
.detail-thread {
  padding: var(--wa-space-m);
  border-radius: var(--wa-border-radius-m);
}

/* Chat wallpapers for the QuentoSnacks reseller (first customer). The two
   "productos" tiles are ghosted collages built from the real product-bag
   packshots on quentosnacks.com/productos (sweet-potato chips, corn snacks,
   etc.), heavily desaturated and alpha-knocked so they read as a calm
   texture behind the bubbles, never competing with the message text. The
   PNGs live under /static/img/ because photographic tiles can't be inline
   SVG; "papas" is a lightweight inline-SVG line-art alternative. The default
   (set in the pre-paint script in applayout) is `chips`. */
.chat-wallpaper-quento {
  --chat-wallpaper-bg: #efe6d3;
  --chat-wallpaper-image: url("/static/img/chat-wp-quento-sepia.png");
  --chat-wallpaper-size: 320px 320px;
}

.chat-wallpaper-quento-color {
  --chat-wallpaper-bg: #efe6d3;
  --chat-wallpaper-image: url("/static/img/chat-wp-quento-color.png");
  --chat-wallpaper-size: 320px 320px;
}

.chat-wallpaper-papas {
  --chat-wallpaper-bg: #efe6d3;
  --chat-wallpaper-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='150' height='150' viewBox='0 0 150 150'%3E%3Cg fill='none' stroke='%235a4024' stroke-width='2.1' stroke-linecap='round' stroke-linejoin='round' opacity='.18'%3E%3Cg transform='translate(34,30) rotate(-18)'%3E%3Cpath d='M-16,0 C-16,-9 16,-9 16,0 C16,9 -16,9 -16,0 Z'/%3E%3Cpath d='M-12,-2 C-4,4 4,4 12,-2'/%3E%3C/g%3E%3Ccircle cx='70' cy='16' r='1.4'/%3E%3Cg transform='translate(108,40) rotate(12)'%3E%3Cpath d='M-13,-8 h26 a3,3 0 0 1 3,3 v10 a3,3 0 0 1 -3,3 h-26 a3,3 0 0 1 -3,-3 v-10 a3,3 0 0 1 3,-3 Z'/%3E%3Cpath d='M-8,-6 v14 M-2,-6 v14 M4,-6 v14 M10,-6 v14'/%3E%3C/g%3E%3Ccircle cx='20' cy='66' r='1.4'/%3E%3Cg transform='translate(70,80) rotate(8)'%3E%3Cpath d='M-16,0 C-16,-9 16,-9 16,0 C16,9 -16,9 -16,0 Z'/%3E%3Cpath d='M-12,-2 C-4,4 4,4 12,-2'/%3E%3C/g%3E%3Ccircle cx='126' cy='92' r='1.4'/%3E%3Cg transform='translate(28,116) rotate(-10)'%3E%3Cpath d='M-13,-8 h26 a3,3 0 0 1 3,3 v10 a3,3 0 0 1 -3,3 h-26 a3,3 0 0 1 -3,-3 v-10 a3,3 0 0 1 3,-3 Z'/%3E%3Cpath d='M-8,-6 v14 M-2,-6 v14 M4,-6 v14 M10,-6 v14'/%3E%3C/g%3E%3Cg transform='translate(116,120) rotate(22)'%3E%3Cpath d='M-16,0 C-16,-9 16,-9 16,0 C16,9 -16,9 -16,0 Z'/%3E%3Cpath d='M-12,-2 C-4,4 4,4 12,-2'/%3E%3C/g%3E%3Ccircle cx='74' cy='134' r='1.4'/%3E%3C/g%3E%3C/svg%3E");
  --chat-wallpaper-size: 150px 150px;
}

/* Hand-drawn chips/snacks pattern. The PNG is already desaturated + lightened
   at export (ImageMagick `-modulate 107,46`) so it reads muted; on top of that
   a translucent surface-tinted layer sits OVER the image to dim it further and
   keep the bubbles readable. Tune the overlay alpha here for more/less dimming;
   re-export the PNG to change the colour knock-down. */
.chat-wallpaper-chips {
  --chat-wallpaper-bg: #cfe5e0;
  --chat-wallpaper-image: linear-gradient(rgba(247, 244, 236, 0.78), rgba(247, 244, 236, 0.78)), url("/static/img/chat-wp-chips.png");
  --chat-wallpaper-size: 460px auto;
}

.chat-wallpaper-plain {
  --chat-wallpaper-bg: var(--wa-color-surface-lowered);
  --chat-wallpaper-image: none;
}

.chat-empty-message {
  text-align: center;
}

/* Bubble contrast against the patterned wallpapers. theme-quento.css gives the
   bubble its base 1px border + fill (brand colour there); here we lift it off
   busy backgrounds with a crisper border and a soft drop shadow. Structural
   (separation from background), not theming, so it lives here and overrides the
   theme rule — app.css loads after theme-quento.css. Scoped to the chat
   + detail threads so non-thread `.msg` uses (if any) are untouched. */
:is(.chat-thread__body, .chat-draft-group, .detail-thread) .msg {
  border-color: var(--wa-color-surface-border-loud, rgba(0, 0, 0, 0.18));
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.14);
}

.msg__body {
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

/* Delivery-status glyph on outbound bubbles (Spec-0023). The glyph sits at the
   right end of the .msg__meta row; its colour encodes the state. The meta row
   is already a flex container (theme-quento.css), so margin-inline-start:auto
   pushes the glyph away from the timestamp to the bubble's trailing edge. */
.msg__status {
  margin-inline-start: auto;
  display: inline-flex;
  align-items: center;
  color: var(--wa-color-text-quiet);
}

.msg__status .wa-icon {
  inline-size: 1.05em;
  block-size: 1.05em;
}

/* read → coloured (filled) double check; failed → red error mark. sent and
   delivered keep the quiet default colour, differing only by glyph (single vs
   double check). */
.msg__status--read {
  color: var(--wa-color-brand-fill-loud);
}

.msg__status--failed {
  color: var(--wa-color-danger-fill-loud);
}

/* Optimistic placeholder rendered the instant the operator hits Enter, before
   the server round-trip (Spec-0023 R1). Dimmed so it reads as not-yet-confirmed;
   it is swapped for the canonical bubble the moment that arrives over /events. */
.msg--pending {
  opacity: 0.7;
}

.chat-attachment,
.chat-attachment__media {
  max-inline-size: 20rem;
}

.chat-attachment__media {
  max-block-size: 16rem;
  object-fit: cover;
  border-radius: var(--wa-border-radius-s);
}

.chat-part-caption {
  margin-top: var(--wa-space-3xs);
}

/* Inbound media understanding (Spec-0045): the automatic audio transcript and
   image reading shown beneath the player/thumbnail. Visually subordinate to the
   artifact — smaller and muted — so the original media stays primary (§5.1/§5.2). */
.chat-transcript,
.chat-reading {
  margin-top: var(--wa-space-2xs);
  font-size: var(--wa-font-size-s);
  color: var(--wa-color-text-quiet);
}

.chat-transcript__label {
  font-size: var(--wa-font-size-xs);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  opacity: 0.75;
}

.chat-transcript__text,
.chat-reading__text {
  /* Transcripts/readings are multi-line and carry [ilegible]/newline structure:
     preserve it without letting a long unbroken token overflow the bubble. */
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

.chat-transcript--pending,
.chat-reading--pending {
  font-style: italic;
}

.chat-transcript--failed,
.chat-reading--failed {
  font-style: italic;
  opacity: 0.8;
}

/* The image reading collapses behind a "Ver texto detectado" toggle (native
   <details>). Keep the summary compact and clickable; the muted tone matches the
   rest of the subordinate metadata. */
.chat-reading__toggle {
  cursor: pointer;
  font-size: var(--wa-font-size-xs);
  text-decoration: underline;
  width: fit-content;
}

.chat-reading__text {
  margin-top: var(--wa-space-3xs);
}

.chat-reply {
  flex: 0 0 auto;
  padding: var(--wa-space-s);
}

.chat-reply__row {
  display: flex;
  align-items: flex-end;
  gap: var(--wa-space-s);
}

/* Icon-only send button (Spec-0023 follow-up): the paper-plane SVG carries
   only a viewBox, so it needs an explicit size. Centre it inside wa-button's
   `label` part — a lone block SVG otherwise sits on the text baseline and
   reads as bottom/left-shifted. */
.chat-reply__send::part(label) {
  display: flex;
  align-items: center;
  justify-content: center;
}

.chat-reply__send .wa-icon {
  display: block;
  width: 1.25rem;
  height: 1.25rem;
}

.chat-reply__input {
  flex: 1 1 auto;
  min-inline-size: 0;
  /* WhatsApp-parity composer: one line tall by default, grows upward as the
     user adds newlines (the row is align-items:flex-end, so extra height
     pushes the top edge up). Height itself is driven by the autosize handler
     on the textarea; we just cap it and let it scroll past the cap. Manual
     drag-resize is off — height is content-driven. */
  resize: none;
  max-block-size: 9rem;
  overflow-y: auto;
}

/* Per-draft message group on /chat (Spec-0020). The wrapper bundles the
   separator pill and all the bubbles that belong to one draft into a
   single DOM node, so the `?fromDraft=` highlight tints + glows the whole
   region as one instead of pulsing each bubble. The group is a flex
   column so the in/out alignment selectors keep working (extended via
   :is() in theme-quento.css). */
.chat-draft-group {
  display: flex;
  flex-direction: column;
  gap: var(--wa-space-2xs);
  border-radius: var(--wa-border-radius-m);
}

.chat-draft-group--highlighted {
  /* The pulsing glow alone marks the jumped-to group; no background tint —
     a fill read poorly against some bubble backgrounds. */
  padding: var(--wa-space-2xs);
  animation: msg-highlight-pulse 1.2s ease-in-out 0s 2;
}

@keyframes msg-highlight-pulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(99, 102, 241, 0); }
  50%      { box-shadow: 0 0 0 6px rgba(99, 102, 241, 0.35); }
}

/* Order-draft separator on /chat — a centered, clickable <wa-tag pill>
   flanked by two horizontal rules. Layout is inline here (not via wa-
   utilities) because the `::before/::after` rules double as both layout
   (flex: 1 grows them) and visual (1px HR). `scroll-margin-top` gives
   the operator a few pixels of breathing room above the pill when the
   `?fromDraft=` jump scrolls here. */
.chat-day-separator {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--wa-space-s);
  scroll-margin-top: var(--wa-space-m);
}
.chat-day-separator::before,
.chat-day-separator::after {
  content: "";
  flex: 1;
  /* Thicker + darker than the default 1px/quiet border, and lifted with a soft
     shadow, so the rule reads clearly over the patterned wallpaper instead of
     getting lost in it. Matches the bubble lift below. */
  height: 2px;
  border-radius: 1px;
  background: var(--wa-color-surface-border-loud, rgba(0, 0, 0, 0.22));
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.12);
}

/* Give the "Pedido #N" pill the same drop shadow as the message bubbles so it
   sits above the wallpaper as a distinct chip. The shadow goes on the wa-tag
   host element (not ::part(base), whose shadow is clipped inside the tag's
   shadow root), and the host gets the full pill radius so the shadow follows
   the rounded shape instead of drawing a rectangle around it. */
.chat-day-separator wa-tag {
  border-radius: 9999px;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.18);
}

/* Inbox card line table — give the unit cell breathing room from the
   product name on its right. The base rule in theme-quento.css uses a
   tight horizontal cell padding (2xs) and right-aligns the unit (left over
   from when it was the trailing column); now that unit sits between qty
   and product, nudge it left-aligned with a small right padding. */
.inbox-card__unit {
  text-align: left;
  padding-right: var(--wa-space-s);
}

/* ---------------------------------------------------------------------------
 * Dev user-switcher (Spec-0027).
 *
 * A header control that only renders locally (ALLOW_DEV_IMPERSONATION). An
 * amber "DEV" badge flags it as a development-only affordance; the compact
 * <select> impersonates any operator. Lives here, not theme-quento.css, since
 * it's feature layout/structure rather than brand theming.
 * ------------------------------------------------------------------------- */

.dev-switcher {
  display: inline-flex;
  align-items: center;
  gap: var(--wa-space-2xs);
  margin: 0;
}

.dev-switcher__badge {
  font-size: 0.625rem;
  font-weight: var(--wa-font-weight-bold);
  letter-spacing: 0.05em;
  line-height: 1;
  padding: 0.2rem 0.35rem;
  border-radius: var(--wa-border-radius-s);
  color: var(--wa-color-warning-on-loud, #3a2a00);
  background: var(--wa-color-warning-fill-loud, #f5a623);
}

.dev-switcher__select {
  max-width: 14rem;
  font-size: 0.8125rem;
  padding: 0.2rem 0.4rem;
  border-radius: var(--wa-border-radius-s);
  border: 1px solid var(--wa-color-surface-border, rgb(255 255 255 / 0.4));
  background: var(--wa-color-surface-default, #fff);
  color: var(--wa-color-text-normal, #111);
}

/* /dev/pick — the no-identity operator chooser (Spec-0027). Rendered inside
   AppShell with a nil user, so it sits in the main content area. */
.dev-pick {
  max-width: 32rem;
  margin: var(--wa-space-2xl) auto;
  padding: 0 var(--wa-space-l);
}

.dev-pick__list {
  display: flex;
  flex-direction: column;
  gap: var(--wa-space-xs);
  margin-top: var(--wa-space-l);
}

.dev-pick__item {
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
  padding: var(--wa-space-s) var(--wa-space-m);
  border: 1px solid var(--wa-color-surface-border);
  border-radius: var(--wa-border-radius-m);
  text-decoration: none;
  color: inherit;
}

.dev-pick__item:hover {
  border-color: var(--wa-color-brand-fill-loud, var(--wa-color-surface-border));
  background: var(--wa-color-surface-raised, transparent);
}

.dev-pick__name {
  font-weight: var(--wa-font-weight-semibold);
}

.dev-pick__email {
  font-size: 0.8125rem;
  color: var(--wa-color-text-quiet);
}

/* ---------------------------------------------------------------------------
   Login page (Spec-0039) — standalone OAuth sign-in, no app shell.
   Layout/structure only; lives here in app.css, never in theme-quento.css.
   The page is theme-pinned to light Quento (pre-identity, no theme picker), so
   these rules target that one theme directly — no dark-mode hedging.
--------------------------------------------------------------------------- */
.login-page {
  /* Accent tied to the logo's green (not the app's amber brand) so the colorful
     double-tick mark is the only chromatic hero on this pre-identity page. */
  --login-green: #53b448;
  --login-green-soft: #6ace4a;

  min-height: 100dvh;
  display: grid;
  place-items: center;
  padding: var(--wa-space-l);
  position: relative;
  isolation: isolate;
  overflow: hidden;
  background: var(--wa-color-neutral-95);
}

/* Soft neutral wash with a faint green breath in the corners — echoes the mark
   without competing with it. */
.login-page::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -2;
  background:
    radial-gradient(58rem 44rem at 12% -12%,
      color-mix(in srgb, var(--login-green-soft) 13%, transparent), transparent 60%),
    radial-gradient(48rem 40rem at 108% 112%,
      color-mix(in srgb, var(--login-green) 9%, transparent), transparent 55%);
}

/* Faint film grain for texture (inline SVG noise — no network request). */
.login-page::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  opacity: 0.05;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

.login-card {
  width: 100%;
  max-width: 25rem;
  padding: clamp(var(--wa-space-l), 6vw, var(--wa-space-2xl));
  position: relative;
  background: var(--wa-color-surface-raised);
  border: 1px solid var(--wa-color-surface-border);
  /* Green cap on the card. A real border-top follows the corner radius (no
     overhang past the rounded corners, unlike an absolutely-positioned bar). */
  border-top: 3px solid var(--login-green);
  border-radius: var(--wa-border-radius-l);
  box-shadow:
    0 1px 2px rgb(20 30 20 / 0.05),
    0 22px 48px -24px rgb(20 30 20 / 0.28);
}

.login-card__brand {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--wa-space-xs);
}
.login-card__brand-mark {
  width: auto;
  height: 2rem;
  flex: none;
}
.login-card__brand-title {
  font-size: 1.3rem;
  font-weight: var(--wa-font-weight-bold, 700);
  letter-spacing: -0.015em;
  color: var(--wa-color-text-normal);
}

.login-card__heading {
  text-align: center;
}
.login-card__title {
  margin: 0;
  font-size: 1.05rem;
  font-weight: var(--wa-font-weight-semibold);
  color: var(--wa-color-text-normal);
}
.login-card__subtitle {
  margin: 0;
  font-size: 0.875rem;
  line-height: 1.4;
  color: var(--wa-color-text-quiet);
}

.login-providers {
  width: 100%;
}
.login-provider {
  display: block;
  width: 100%;
}
.login-provider::part(base) {
  width: 100%;
}

.login-card__footer {
  margin: 0;
  text-align: center;
  font-size: 0.8125rem;
  color: var(--wa-color-text-quiet);
}

/* One orchestrated entrance: the card eases in, its rows rise in a gentle stagger. */
@media (prefers-reduced-motion: no-preference) {
  .login-card {
    animation: login-card-in 0.6s cubic-bezier(0.2, 0.7, 0.2, 1) both;
  }
  .login-card > * {
    animation: login-row-in 0.5s cubic-bezier(0.2, 0.7, 0.2, 1) both;
  }
  .login-card > *:nth-child(1) { animation-delay: 0.12s; }
  .login-card > *:nth-child(2) { animation-delay: 0.18s; }
  .login-card > *:nth-child(3) { animation-delay: 0.24s; }
  .login-card > *:nth-child(4) { animation-delay: 0.30s; }
  .login-card > *:nth-child(5) { animation-delay: 0.36s; }
}
@keyframes login-card-in {
  from { opacity: 0; transform: translateY(12px) scale(0.99); }
  to   { opacity: 1; transform: none; }
}
@keyframes login-row-in {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: none; }
}

/* ── Super admin console (Spec-0041) ─────────────────────────────────────────
   The super-only tenant directory + operator management. Layout uses WA utility
   classes in the templates; this is the table + form chrome no utility covers. */
.dt-admin {
  padding: var(--wa-space-l);
}
.dt-admin__title {
  font-size: 1.5rem;
  font-weight: var(--wa-font-weight-bold);
  margin: 0;
}
.dt-admin__subtitle {
  margin: 0;
  color: var(--wa-color-text-quiet);
}
.dt-admin__back {
  text-decoration: none;
  color: var(--wa-color-text-quiet);
  font-size: 0.875rem;
}
.dt-admin__back:hover { text-decoration: underline; }

.dt-admin__table-wrap {
  overflow: auto;
  /* Cap the height so a long operator/tenant list scrolls inside the panel and the
     sticky header below stays pinned. A short list never reaches the cap, so it
     renders at its natural height with no inner scrollbar. */
  max-height: 70vh;
  border: 1px solid var(--wa-color-surface-border);
  border-radius: var(--wa-border-radius-m);
}
.dt-admin__table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--wa-font-size-m);
}
.dt-admin__table th,
.dt-admin__table td {
  text-align: left;
  padding: var(--wa-space-s) var(--wa-space-m);
  border-bottom: 1px solid var(--wa-color-surface-border);
  vertical-align: middle;
}
.dt-admin__table thead th {
  font-weight: var(--wa-font-weight-semibold);
  color: var(--wa-color-text-quiet);
  background: var(--wa-color-surface-lowered);
  white-space: nowrap;
  /* Keep the column headers visible while the list scrolls. border-collapse drops the
     cell border during scroll, so paint it as an inset box-shadow that rides along. */
  position: sticky;
  top: 0;
  z-index: 1;
  box-shadow: inset 0 -1px var(--wa-color-surface-border);
}
.dt-admin__table tbody tr:last-child td { border-bottom: none; }
.dt-admin__name { font-weight: var(--wa-font-weight-semibold); }
.dt-admin__id {
  font-family: var(--wa-font-family-code);
  font-size: 0.75rem;
  color: var(--wa-color-text-quiet);
}
.dt-admin__col-actions { text-align: right; white-space: nowrap; }

.dt-admin--form .dt-admin__form { max-width: 32rem; }

/* Edit-tenant two-column: the form flanks at its natural 32rem on the left while the
   Números panel fills the space to its right; wa-flank wraps them to a single column
   when the viewport is too narrow. */
.dt-admin__form-split { --flank-size: 32rem; }
.dt-admin__form-split > .dt-admin__form { max-width: none; }

/* Operator-management add panel + per-row actions (Spec-0041 R3). */
.dt-admin__panel {
  padding: var(--wa-space-m);
  border: 1px solid var(--wa-color-surface-border);
  border-radius: var(--wa-border-radius-m);
  background: var(--wa-color-surface-lowered);
}
.dt-admin__panel-title {
  margin: 0;
  font-size: var(--wa-font-size-m);
  font-weight: var(--wa-font-weight-semibold);
}
.dt-admin__op-actions { justify-content: flex-end; }
.dt-admin__dialog-actions { justify-content: flex-end; }
.dt-admin__muted { color: var(--wa-color-text-quiet); }
/* A soft-locked operator (Spec-0043): dim the identity cells so the disabled state
   reads at a glance, but keep the actions column legible so the super can re-enable
   or delete it. */
.dt-admin__op-row--disabled td:not(.dt-admin__col-actions) { opacity: 0.5; }

/* Tenant-less "pick a business" landing (Spec-0042 R3): a super with no tenant
   selected gets a centered, width-constrained list of POST /tenant/switch forms.
   Layout only — the wa-stack utility handles the vertical rhythm; these rules just
   constrain and center the list and make each tenant button fill its row. */
.tenant-picker {
  max-inline-size: 24rem;
  margin-inline: auto;
  margin-block-start: var(--wa-space-l);
}
.tenant-picker__button { width: 100%; }

/* ---------------------------------------------------------------------------
 * fakewa fake-phone chat UI (Spec-0046) — dev-only page served by cmd/fakewa
 * at /ui, never by the app. It reuses the .chat / .msg systems above; the
 * fw-* rules here only add the standalone page chrome (no app shell) and the
 * persona rail ("who am I" switcher).
 * ------------------------------------------------------------------------- */

.fw-body {
  height: 100vh;
  margin: 0;
  display: flex;
  flex-direction: column;
  background: var(--wa-color-surface-lowered);
}
.fw-topbar {
  flex: 0 0 auto;
  align-items: baseline;
  padding: var(--wa-space-xs) var(--wa-space-m);
  border-block-end: 1px solid var(--wa-color-surface-border);
  background: var(--wa-color-surface-default);
}
.fw-body > main {
  flex: 1 1 auto;
  min-block-size: 0;
  display: flex;
}
.fw-phone {
  flex: 1 1 auto;
  background: var(--wa-color-surface-default);
}
.fw-rail {
  flex: 0 0 7.5rem;
  inline-size: 7.5rem;
  padding: var(--wa-space-xs);
  border-inline-end: 1px solid var(--wa-color-surface-border);
  overflow-y: auto;
}
.fw-rail__header { padding-inline: var(--wa-space-2xs); }
.fw-rail__item {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--wa-space-3xs);
  padding: var(--wa-space-2xs);
  border-radius: var(--wa-border-radius-m);
  text-decoration: none;
  color: inherit;
}
.fw-rail__item:hover { background: var(--wa-color-surface-lowered); }
.fw-rail__item--active {
  background: var(--wa-color-brand-fill-quiet);
  outline: 1px solid var(--wa-color-brand-border-quiet);
}
.fw-rail__name { max-inline-size: 100%; }
.fw-rail__add summary { cursor: pointer; padding: var(--wa-space-2xs); }
.fw-rail__add input { inline-size: 100%; }
.fw-presence--typing {
  color: var(--wa-color-success-on-quiet);
  font-style: italic;
}
/* WhatsApp-parity composer: one rounded pill with the (+) attach menu, the
   text box, and mic ⇄ send swap. The attach-caption and voice-recording rows
   swap in for the pill while active. */
.fw-composer {
  flex: 0 0 auto;
  padding: var(--wa-space-xs) var(--wa-space-m);
}
/* display:flex below outranks the UA stylesheet's [hidden]{display:none}, so
   the inactive rows need an explicit guard — without it all three bars render
   stacked. */
.fw-bar[hidden],
.fw-attach[hidden],
.fw-rec[hidden] {
  display: none;
}
.fw-bar,
.fw-attach,
.fw-rec {
  display: flex;
  align-items: center;
  gap: var(--wa-space-2xs);
  padding: var(--wa-space-3xs) var(--wa-space-xs);
  border: 1px solid var(--wa-color-surface-border);
  border-radius: 1.6rem;
  background: var(--wa-color-surface-default);
  box-shadow: var(--wa-shadow-s);
}
.fw-bar__input {
  flex: 1 1 auto;
  border: none;
  outline: none;
  resize: none;
  background: transparent;
  font: inherit;
  line-height: 1.4;
  max-block-size: 8rem;
  padding-block: var(--wa-space-2xs);
}
.fw-bar__icon::part(base) {
  border-radius: 50%;
  padding: var(--wa-space-2xs);
}
.fw-bar__icon .wa-icon {
  inline-size: 1.35rem;
  block-size: 1.35rem;
}
.fw-bar__icon--send::part(base) { color: var(--wa-color-brand-fill-loud); }
.fw-menu__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  inline-size: 1.9rem;
  block-size: 1.9rem;
  border-radius: 50%;
  color: white;
  margin-inline-end: var(--wa-space-2xs);
}
.fw-menu__icon .wa-icon { inline-size: 1.05rem; block-size: 1.05rem; }
.fw-menu__icon--photos { background: #007bfc; }
.fw-menu__icon--audio { background: #fa6533; }
.fw-attach__name { max-inline-size: 14rem; flex: 0 0 auto; }
.fw-attach__caption {
  flex: 1 1 auto;
  border: none;
  outline: none;
  background: transparent;
  font: inherit;
}
.fw-rec__dot {
  flex: 0 0 auto;
  inline-size: 0.7rem;
  block-size: 0.7rem;
  border-radius: 50%;
  background: var(--wa-color-danger-fill-loud, #e53935);
  animation: fw-rec-pulse 1.2s ease-in-out infinite;
}
@keyframes fw-rec-pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.25; }
}
.fw-rec__time { flex: 0 0 auto; font-variant-numeric: tabular-nums; }
.fw-rec__error { flex: 1 1 auto; color: var(--wa-color-danger-on-quiet, #b3261e); }
