/* ai-assistant.css — component library (product/promo/stall cards, quick
   replies, cart/recipe/meal-plan cards, market/stall "fichas") plus the
   full-screen chat chrome (templates/public/ai_assistant.html). Reuses
   design tokens from styles.css (--color-pine, --color-evergreen, --muted-
   text); no navbar/footer styling needed here (base.html/navbar.css).

   Sections in this file:
     1. Shared card surface
     2. Product / promotion / stall carousels
     3. Quick replies
     4. Cart summary / recipe / meal-plan cards
     5. Market summary / stall profile cards
     6. Full-screen chat page layout
     7. Assistant Home
     8. Chat bubbles / typing indicator
     9. Composer */

/* ============================================================
   1. Shared card surface (mercat.html's .mh-card recipe)
   Split into layers so each selector opts into only what it needs,
   instead of repeating the same declarations everywhere. Grouping is
   CSS-only — no class names change, so no JS component needs touching.
   ============================================================ */
.ai-product-card,
.ai-market-summary,
.ai-stall-profile,
.ai-home-card,
.ai-message-user,
.ai-message-assistant,
.ai-typing-indicator {
  border: 0.5px solid #b2bab1;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12);
}

/* + 16px corners (typing indicator overrides one corner to 4px further
   down; bubbles get it via .ai-message instead). */
.ai-product-card,
.ai-market-summary,
.ai-stall-profile,
.ai-home-card,
.ai-typing-indicator {
  border-radius: 16px;
}

/* + white fill, clipped — the photo-fronted cards only. */
.ai-product-card,
.ai-market-summary,
.ai-stall-profile,
.ai-home-card {
  overflow: hidden;
  background: #fff;
}

/* market/stall "ficha" cards get vertical breathing room like every other
   rich component dropped into the chat (cart/recipe/meal-plan below);
   product/home cards don't — their carousel/grid `gap` spaces them. */
.ai-market-summary,
.ai-stall-profile {
  margin: .5rem 0;
}

/* ============================================================
   2. Product / promotion / stall carousels
   Promotion and stall cards reuse this DOM/CSS wholesale
   (AIPromotionCard.js/AIStallCard.js build the same shape as
   AIProductCard.js) — no styles of their own beyond the shared scroller
   and card surface above.
   ============================================================ */
.ai-product-carousel,
.ai-promotion-list,
.ai-stall-list {
  display: flex;
  gap: .75rem;
  overflow-x: auto;
  padding: .5rem 0;
}

.ai-product-card {
  flex: 0 0 auto;
  width: 202px; /* 200px 1:1 image + 1px border each side */
}

.ai-product-card-imgwrap {
  position: relative;
  width: 100%;
  aspect-ratio: 1 / 1;
  background: #f2f2f2;
  overflow: hidden;
}

.ai-product-card-img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* AddToCartStepper overlay, bottom-right of the image; cart.css styles the
   button itself. :empty hides the ring for free-parada products with no
   stepper to show. */
.ai-product-card .product-action-stepper-wrapper {
  position: absolute;
  right: 5px;
  bottom: 5px;
  z-index: 999;
  pointer-events: auto;
  display: inline-block;
  background: transparent;
  box-shadow: 0 0 0 0.5px rgba(255, 255, 255, 0.95);
  border-radius: calc(var(--stepper-height, var(--stepper-height-default, 34px)) / 2 + 2px);
}
.ai-product-card .product-action-stepper-wrapper:empty {
  display: none;
}

.ai-product-card-body {
  padding: .5rem;
}

.ai-product-card-name {
  font-weight: 600;
  font-size: .9rem;
  margin-bottom: .2rem;
}

.ai-product-card-price {
  font-size: .85rem;
  color: #333;
  margin-bottom: .2rem;
}

.ai-product-card-name .product-qty,
.ai-product-card-per,
.ai-product-card-unit {
  color: var(--muted-text, #6a7a72);
  font-weight: 400;
  font-size: .8rem;
  margin-left: 6px;
}

.ai-product-card-qty-line {
  color: var(--color-pine, #5B7065);
  font-weight: 600;
}

.ai-product-card-parada {
  font-size: .75rem;
  color: #777;
  margin-bottom: .35rem;
}

/* ============================================================
   3. Quick replies
   ============================================================ */
.ai-quick-replies {
  display: flex;
  flex-wrap: wrap;
  gap: .5rem;
  margin: .5rem 0;
}

/* .ai-home-question-btn (Assistant Home) reuses this exact rule — same
   height/padding/border/shadow(none)/radius — rather than a lookalike
   copy, so the two chip styles can never quietly drift apart. Only what
   genuinely differs (hover/press color, Home's own left-aligned
   multi-line layout) stays on its own selector, further down. */
.ai-quick-reply-btn,
.ai-home-question-btn {
  border: 1px solid transparent;
  background: var(--color-pine, #5B7065);
  color: #fff;
  border-radius: 999px;
  padding: .35rem .9rem;
  font-size: .85rem;
  cursor: pointer;
}
.ai-quick-reply-btn:hover {
  background: color-mix(in srgb, var(--color-pine, #5B7065) 85%, #000);
}
.ai-quick-reply-btn:disabled {
  opacity: .5;
  cursor: default;
}

/* ============================================================
   4. Cart summary / recipe / meal-plan cards
   Cart summary and recipe cards share one plain "info box" (lighter than
   the .mh-card recipe: 1px neutral border, off-white, no shadow). The
   meal-plan wrapper (several recipe cards = one meal) uses darker
   neutrals on purpose, to read as one heavier group — kept separate from
   that box.
   ============================================================ */
.ai-cart-summary,
.ai-recipe-card {
  border: 1px solid #e0e0e0;
  border-radius: 12px;
  padding: .75rem;
  margin: .5rem 0;
  background: #fafafa;
}

.ai-cart-summary-list {
  list-style: none;
  margin: 0 0 .5rem;
  padding: 0;
  font-size: .9rem;
}

.ai-cart-summary-total {
  font-weight: 600;
  font-size: .9rem;
}

.ai-recipe-card-title {
  font-weight: 700;
  font-size: 1rem;
  margin-bottom: .4rem;
}

.ai-recipe-card-total {
  font-weight: 600;
  font-size: .9rem;
  margin-top: .4rem;
}

.ai-meal-plan-card {
  border: 1px solid #c9c9c9;
  border-radius: 14px;
  padding: .75rem;
  margin: .5rem 0;
  background: #f2f2f2;
}

.ai-meal-plan-title {
  font-weight: 700;
  font-size: 1.05rem;
  margin-bottom: .4rem;
}

.ai-meal-plan-total {
  font-weight: 700;
  font-size: .95rem;
  margin-top: .5rem;
  padding-top: .5rem;
  border-top: 1px solid #c9c9c9;
}

/* ============================================================
   5. Market summary / stall profile cards ("ficha d'entrada")
   Same shape for both: a wide photo up top, heavier than the other
   cards since each reads as its own entry point. Shared
   container/image/name/body rules below; whatever differs (status
   margin, the stats row, the vendor badge) stays on its own selector.
   ============================================================ */
.ai-market-summary-img,
.ai-stall-profile-img {
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  display: block;
  background: #f2f2f2;
}

.ai-market-summary-body,
.ai-stall-profile-body {
  padding: .75rem .9rem;
}

.ai-market-summary-name,
.ai-stall-profile-name {
  font-weight: 700;
  font-size: 1.05rem;
  color: var(--color-evergreen, #304040);
  margin-bottom: .25rem;
}

.ai-market-summary-status.is-open,
.ai-stall-profile-status.is-open {
  color: var(--color-pine, #5B7065);
}
.ai-market-summary-status.is-closed,
.ai-stall-profile-status.is-closed {
  color: var(--muted-text, #6a7a72);
}

.ai-market-summary-status {
  font-size: .85rem;
  margin-bottom: .6rem;
}

.ai-market-summary-stats {
  display: flex;
  gap: .75rem;
  padding-top: .6rem;
  border-top: 1px solid #eee;
}

.ai-market-summary-stat {
  flex: 1 1 0;
  text-align: center;
}

.ai-market-summary-stat-num {
  font-weight: 700;
  font-size: 1.1rem;
  color: var(--color-evergreen, #304040);
}

.ai-market-summary-stat-label {
  font-size: .7rem;
  color: var(--muted-text, #6a7a72);
}

.ai-stall-profile-photowrap {
  position: relative;
}

/* Circular "who runs this stall" badge overlapping the photo's bottom-left
   corner, so it doesn't cost its own row. The :has() rule below adds the
   extra top padding its overlap needs, only when the badge is present. */
.ai-stall-profile-vendor-img {
  position: absolute;
  left: 10px;
  bottom: -18px;
  width: 52px;
  height: 52px;
  border-radius: 50%;
  object-fit: cover;
  border: 3px solid #fff;
  box-shadow: 0 1px 4px rgba(0, 0, 0, .15);
  background: #f2f2f2;
}
.ai-stall-profile-photowrap:has(.ai-stall-profile-vendor-img) + .ai-stall-profile-body {
  padding-top: 1.4rem;
}

.ai-stall-profile-status {
  font-size: .85rem;
  margin-bottom: .3rem;
}

.ai-stall-profile-meta {
  font-size: .8rem;
  color: var(--muted-text, #6a7a72);
  margin-bottom: .5rem;
}

/* Quick-reply chips inside a card use .ai-quick-replies/.ai-quick-reply-btn
   as-is — no separate wrapper class. */

/* ============================================================
   6. Full-screen chat page layout (templates/public/ai_assistant.html)
   The page extends public/base.html like any other page, but the chat
   scrolls with the DOCUMENT (so iOS Safari's toolbar can collapse), with
   the composer as position:fixed over that flow — an inner overflow
   scroller pinned to 100dvh was tried and rejected, it kept Safari's
   toolbar stuck open. The on-screen keyboard needs no CSS/JS math:
   ai_assistant.html opts this page's viewport into
   `interactive-widget=resizes-content`, so the keyboard shrinks the
   layout viewport itself — dvh/vh and any `bottom: 0` fixed element
   already account for it.
   ============================================================ */

/* min-vh-100 (Bootstrap) can exceed the visible 100dvh on iOS Safari with
   the toolbar expanded, adding scrollable slack above the chat before any
   content needs it. Cap the minimum at the real viewport instead. */
body.ai-page {
  min-height: 100vh !important;
  min-height: 100dvh !important;
}

main.ai-main {
  min-height: 100vh;
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
  /* Composer's current total height — .ai-messages offsets its bottom
     padding against it. Static fallback for first paint; JS
     (AIAssistantPage.js's composerResizeObserver) overwrites this on
     THIS element (not documentElement — an inherited value can never
     beat a rule targeting the element itself) with the composer's real
     measured height, so the reserved space stays in sync as the
     textarea grows/shrinks. */
  --ai-composer-h: 96px;
  --ai-gutter: 12px; /* side gutter: messages, composer, full-bleed scrollers */
  padding-bottom: 0; /* the composer owns the bottom edge, not styles.css's --cart-safe-bottom */
}

/* The fixed cart pill would sit on top of the composer; the chat has its
   own cart affordances instead (get_cart summaries, add_to_cart intents). */
body.ai-page #cart-simple-root {
  display: none;
}

.ai-messages {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  /* Bottom padding clears the fixed composer, plus a little breathing
     room above it. */
  padding: 1rem var(--ai-gutter, 12px) calc(var(--ai-composer-h, 112px) + .75rem);
}

.ai-messages-inner {
  display: flex;
  flex-direction: column;
  gap: .25rem;
  flex: 1 1 auto;
}

/* Card scrollers go full-bleed edge-to-edge inside the chat (same pattern
   as parada.html's scroller): negative margins cancel .ai-messages' own
   gutter, re-created inside via padding so it scrolls away with the
   content, with a flex-spacer ::after doing the same at the end. */
.ai-messages .ai-product-carousel,
.ai-messages .ai-promotion-list,
.ai-messages .ai-stall-list {
  margin-inline: calc(-1 * var(--ai-gutter, 12px));
  padding-inline: var(--ai-gutter, 12px) 0;
  scroll-padding-inline: var(--ai-gutter, 12px);
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
  -ms-overflow-style: none;
}
.ai-messages .ai-product-carousel::-webkit-scrollbar,
.ai-messages .ai-promotion-list::-webkit-scrollbar,
.ai-messages .ai-stall-list::-webkit-scrollbar {
  display: none;
}
.ai-messages .ai-product-carousel::after,
.ai-messages .ai-promotion-list::after,
.ai-messages .ai-stall-list::after {
  content: '';
  flex: 0 0 var(--ai-gutter, 12px);
}

.ai-messages-inner > * {
  flex-shrink: 0;
}

/* ============================================================
   7. Assistant Home (assistant/home.py + static/js/ai/AIHome.js)
   ============================================================ */

/* Anchored a bit above center rather than dead-centered. Margin/gap/
   padding here are deliberately tight: greeting + 4 questions + cards must
   fit small phones with NO vertical scroll — re-verify with Playwright at
   ~360x640 if any of these values grow. */
.ai-home {
  margin: 1vh auto auto;
  display: flex;
  flex-direction: column;
  gap: .45rem;
  padding: .1rem 0;
  text-align: center;
}

.ai-home-greeting h1 {
  font-size: 1.3rem;
  color: var(--color-evergreen, #304040);
  margin: 0;
}

/* One section = one title + the content it introduces. .ai-home's own gap
   separates the 3 zones (welcome/needs/discovery); this tighter gap binds
   a title to its own content. */
.ai-home-section {
  display: flex;
  flex-direction: column;
  gap: .45rem;
}

.ai-home-section-title {
  margin: .75rem 0 0;
  font-size: 1.05rem;
  font-weight: 400;
  color: var(--color-evergreen, #304040);
  text-align: left;
}

/* One chip per row, stacked — always exactly 4 questions
   (assistant/questions.py). align-items: flex-start keeps each chip sized
   to its own text (the flex default, stretch, would fill the row instead
   — exactly the "bocadillo" look this replaced). */
.ai-home-questions {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: .5rem;
  text-align: left;
}

/* Base look (padding/font/radius/border) comes from the shared
   .ai-quick-reply-btn rule above — same chip as the in-chat "selecció de
   resposta" ones, on purpose. Only the Home-specific bits live here: left
   alignment (in-chat chips can be short/centered-ish in a wrapped row;
   these read top-to-bottom, longer sentences, so keep them left-aligned)
   and the hover/press treatment already established for this page. */
.ai-home-question-btn {
  text-align: left;
  transition: transform .12s ease, background-color .2s ease;
}
.ai-home-question-btn:hover,
.ai-home-question-btn:focus {
  background: var(--color-evergreen, #304040);
}
.ai-home-question-btn:active {
  transform: scale(.96); /* same press-scale as .btn-pill:active */
  background: var(--color-evergreen, #304040);
}
.ai-home-question-btn:disabled {
  opacity: .5;
  cursor: default;
}

/* 1-3 cards side by side (assistant/card_engine.py caps at 3), not shown at
   all while empty. auto-fit collapses unused columns so 1 card fills the
   row instead of leaving empty tracks next to it. 96px floor: below it, 3
   cards don't fit a 360px phone's content width and silently wrap to a 2nd
   row, blowing the Home's no-scroll budget — re-verify if card content
   ever needs more width than this. */
.ai-home-cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(96px, 1fr));
  gap: .5rem;
  text-align: left;
}

.ai-home-card {
  padding: 0;
  display: flex;
  flex-direction: column;
  cursor: pointer;
  font: inherit;
  color: inherit;
  transition: transform 0.15s ease, box-shadow 0.15s ease;
  -webkit-tap-highlight-color: transparent;
}
.ai-home-card:active {
  transform: scale(0.97);
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.12);
}

/* 4:3 for every card image, no max-height — height is a fixed fraction of
   the auto-fit column width above. */
.ai-home-card-image {
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  background: #f2f2f2;
  display: block;
}

.ai-home-card-body {
  padding: .15rem .55rem .2rem;
  display: flex;
  flex-direction: column;
  gap: .1rem;
  /* flex:1 gives .ai-home-card-cta's margin-top:auto real space to push
     into, so the CTA pins to the card's bottom regardless of how many
     optional fields (badge/subtitle/footer) come before it. */
  flex: 1;
}

.ai-home-card-badge {
  align-self: flex-start;
  background: var(--color-pine, #5B7065);
  color: #fff;
  font-size: .6rem;
  font-weight: 600;
  padding: .1rem .4rem;
  border-radius: 999px;
  margin-bottom: .2rem;
}

.ai-home-card-title {
  font-weight: 600;
  font-size: .78rem;
  color: var(--color-evergreen, #304040);
}

.ai-home-card-subtitle {
  font-size: .7rem;
  color: var(--color-pine, #5B7065);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.ai-home-card-footer {
  font-size: .65rem;
  color: #888;
  display: -webkit-box;
  -webkit-line-clamp: 1;
  line-clamp: 1;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.ai-home-card-cta {
  margin-top: auto; /* always pins to the card's true bottom edge — see .ai-home-card-body */
  padding-top: .3rem;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 4px;
  font-size: .7rem;
  font-weight: 600;
  color: var(--color-pine, #5B7065);
}
.ai-home-card-cta i {
  font-size: .65rem;
  transition: transform 0.15s ease;
}
.ai-home-card:hover .ai-home-card-cta i,
.ai-home-card:focus-visible .ai-home-card-cta i {
  transform: translateX(3px);
}

/* Server-rendered skeleton (no JS needed to show it) fills the gap before
   the module script paints the real Home; removed the instant it runs. */
.ai-home-skeleton {
  margin: auto 0;
  padding: 1rem 0;
}
.ai-skel {
  background: rgba(91, 112, 101, 0.12);
  border-radius: 8px;
  animation: ai-skel-pulse 1.4s ease-in-out infinite;
}
.ai-skel-title {
  width: 70%;
  height: 1.3rem;
  margin: 0 auto .6rem;
}
.ai-skel-subtitle {
  width: 55%;
  height: .9rem;
  margin: 0 auto 1.2rem;
}
.ai-home-skeleton-questions {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: .6rem;
}
.ai-skel-question {
  height: 3rem;
  border-radius: 14px;
}
@keyframes ai-skel-pulse {
  0%, 100% { opacity: .6; }
  50%      { opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
  .ai-skel { animation: none; }
}

/* ============================================================
   8. Chat bubbles / typing indicator
   Bubbles render a small markdown subset (AIMessage.js): paragraphs,
   <br>, bullet lists, <strong> — no pre-wrap, line breaks are explicit
   markup.
   ============================================================ */
.ai-message {
  max-width: 80%;
  padding: .6rem .9rem;
  border-radius: 16px;
  margin-bottom: .6rem;
}
.ai-message p {
  margin: 0;
}
.ai-message ul {
  margin: 0;
  padding-left: 1.25rem;
}
.ai-message li {
  margin: .2rem 0;
}
.ai-message p + p,
.ai-message p + ul,
.ai-message ul + p {
  margin-top: .5rem;
}

.ai-message-user {
  align-self: flex-end;
  background: var(--color-pine, #5B7065);
  color: #fff;
  border-bottom-right-radius: 4px;
}
.ai-message-assistant {
  align-self: flex-start;
  background: #fff;
  color: #222;
  border-bottom-left-radius: 4px;
}

.ai-typing-indicator {
  align-self: flex-start;
  display: flex;
  align-items: center;
  gap: .3rem;
  padding: .7rem .9rem;
  background: #fff;
  border-bottom-left-radius: 4px;
  margin-bottom: .6rem;
}
.ai-typing-indicator span {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--color-pine, #5B7065);
  opacity: .4;
  animation: ai-typing-bounce 1s infinite ease-in-out;
}
.ai-typing-indicator span:nth-child(2) { animation-delay: .15s; }
.ai-typing-indicator span:nth-child(3) { animation-delay: .3s; }
@keyframes ai-typing-bounce {
  0%, 80%, 100% { opacity: .4; transform: translateY(0); }
  40% { opacity: 1; transform: translateY(-3px); }
}

.ai-typing-label {
  font-style: normal;
  font-size: .85rem;
  color: #5B7065;
  margin-left: .2rem;
  white-space: nowrap;
}

/* ============================================================
   9. Composer
   A single floating "glass" panel, fixed over the page, safe-area
   aware: translucent Pine + backdrop blur so the conversation keeps
   scrolling (and softly defocuses) behind it. Two rows inside — the
   textarea, then a toolbar with "Nova conversa" on the left and the
   send/stop action on the right (ai_assistant.html) — both fully
   opaque/solid Pine on purpose: only the panel itself is glass, never
   the controls on it.
   ============================================================ */
.ai-composer {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0; /* interactive-widget=resizes-content already accounts for the keyboard */
  z-index: 5;
  /* 12px bottom, matching the side gutters. bottom:0 sits flush with the
     true bottom of the page — nothing past this element's own box to
     paint into — so .ai-composer-glass's shadow/glow layers below must
     stay small enough to fully fade out within this room, or they hit a
     hard visible cut instead of dissolving. */
  padding: .5rem var(--ai-gutter, 12px) calc(12px + env(safe-area-inset-bottom, 0px));
}

/* ---- Glass panel -------------------------------------------------- */
.ai-composer-glass {
  position: relative; /* hosts the thinking-state ring/glow below */
  display: flex;
  flex-direction: column;
  /* Uniform 8px on every axis — gap between rows, and the glass's own
     padding — so the toolbar row sits exactly as far from the box's
     bottom/side edges as the textarea sits from its top/side edges. */
  gap: 8px;
  border-radius: 16px;
  padding: 8px;
  background: rgba(91, 112, 101, .7); /* Pine, semi-transparent glass */
  backdrop-filter: blur(18px) saturate(160%);
  -webkit-backdrop-filter: blur(18px) saturate(160%);
  border: 1px solid var(--color-pine, #5B7065);
  /* Clips the backdrop blur to this box's own rounded edge — without it,
     Safari can blur slightly past the border-radius, reading as extra
     border weight. */
  overflow: hidden;
  transition: border-color .25s ease;
}

/* ---- Textarea + placeholders ---------------------------------------
   Two placeholder layers: the native `placeholder` attribute (plain
   "Què necessites?" once a conversation exists) and, only on the Home,
   AIComposerPlaceholder.js's rotating overlay just below — an overlay
   because swapping phrases needs to fade, which a native placeholder
   can't do. */
.ai-composer-field {
  position: relative;
}

.ai-composer textarea {
  display: block;
  width: 100%;
  box-sizing: border-box;
  border: none;
  border-radius: 10px;
  -webkit-appearance: none; /* else WebKit paints its own translucent :disabled skin */
  appearance: none;
  padding: 10px 12px;
  line-height: 20px;
  font-size: max(16px, 1rem); /* 16px floor: below it iOS Safari auto-zooms on focus */
  font-family: inherit;
  font-weight: 600; /* plain 400 white-on-Pine over a blurred backdrop read as thin/faint */
  /* A dedicated compact value, not the shared --btn-pill-height (48px,
     for ordinary tap-target buttons) — this is a one-line text field,
     not a button. Matches COMPOSER_MIN_HEIGHT in AIAssistantPage.js. */
  min-height: 40px;
  background: transparent; /* the glass panel behind it is the only surface */
  color: #fff;
  resize: none; /* height is driven by JS (resizeComposer()), a drag handle would fight it */
  overflow-y: hidden;
  position: relative; /* stays above .ai-composer-placeholder below */
  z-index: 1;
}
.ai-composer textarea:focus {
  outline: none;
}
.ai-composer textarea:disabled {
  opacity: 1; /* stays fully legible while locked during a running turn */
}
.ai-composer textarea::placeholder {
  color: rgba(255, 255, 255, .8);
  font-weight: 600;
  opacity: 1; /* Firefox dims ::placeholder by default; keep it at our own rgba alpha instead */
}
/* "Un moment..." (showThinkingUi()) reads as disabled — dimmer, no bold,
   unlike the resting placeholder above. */
.ai-composer textarea:disabled::placeholder {
  color: rgba(255, 255, 255, .45);
  font-weight: 400;
}

/* Sized/positioned to sit exactly where typed text starts; JS toggles
   [hidden] once the Home/empty-textarea condition no longer holds. */
.ai-composer-placeholder {
  position: absolute;
  inset: 0;
  padding: 10px 12px; /* matches .ai-composer textarea's own padding exactly */
  line-height: 20px;
  font-size: max(16px, 1rem);
  color: rgba(255, 255, 255, .8);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  pointer-events: none;
  opacity: 1;
  transition: opacity .4s ease;
}
.ai-composer-placeholder.is-fading {
  opacity: 0;
}
.ai-composer-placeholder[hidden] {
  display: none;
}

/* ---- Toolbar / buttons ---------------------------------------------
   "Nova conversa" (left) + Envia/Atura (right) — both fully solid Pine;
   only the panel above them is glass. */
.ai-composer-toolbar {
  display: flex;
  align-items: center;
  gap: .5rem;
}

/* Pins the send/stop action to the right on its own — not
   justify-content: space-between on the toolbar, which would strand it
   on the LEFT the moment "Nova conversa" is hidden (Home state):
   space-between with a single visible flex item places that item at the
   start, not the end. */
.ai-composer-action {
  margin-left: auto;
}

.ai-composer-pill,
.ai-composer-action {
  border: none;
  border-radius: 999px;
  padding: .4rem .95rem;
  font-size: .82rem;
  font-weight: 600;
  color: #fff;
  background: var(--color-pine, #5B7065);
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: .35rem;
  line-height: 1.3;
}
.ai-composer-pill:hover,
.ai-composer-pill:focus-visible,
.ai-composer-action:hover:not(:disabled),
.ai-composer-action:focus-visible:not(:disabled) {
  background: var(--color-evergreen, #304040);
}
.ai-composer-action:disabled {
  opacity: .45;
  cursor: default;
}
.ai-composer-action[hidden] {
  display: none;
}

/* ---- "Still working" cue --------------------------------------------
   Same technique as the navbar Assistent chip's own "running" cue
   (navbar.css): a masked-gradient ::before ring (padding + double mask +
   mask-composite:exclude carves a thin band, not a filled box), hidden
   at rest, plus an outward box-shadow glow pulsing between two
   intensities. Pine throughout, not the navbar's blue, to match this
   page's palette.
   Unlike the navbar chip, this panel has its own always-on 1px solid
   border — so that border goes transparent for exactly as long as the
   ring is shown, instead of both rendering at once (which read as a box
   nested inside another box in an earlier version of this effect). */
.ai-composer-glass::before {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: 16px;
  padding: 1px; /* ring width, matching the panel's own static border */
  background: transparent;
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask-composite: exclude;
  opacity: 0;
  pointer-events: none;
  transition: opacity .25s ease;
}
.ai-composer-glass:has(#composer-input.is-thinking) {
  border-color: transparent; /* the ::before ring takes over */
}
.ai-composer-glass:has(#composer-input.is-thinking)::before {
  opacity: 1;
  background: linear-gradient(135deg,
    rgba(91, 112, 101, .95),
    rgba(91, 112, 101, .55) 50%,
    rgba(91, 112, 101, .95)
  );
}
@media (prefers-reduced-motion: no-preference) {
  .ai-composer-glass:has(#composer-input.is-thinking) {
    animation: ai-composer-glow-pulse 1.6s ease-in-out infinite;
  }
}
/* Peak reach (8px blur + 2px spread = 10px) stays inside .ai-composer's
   12px bottom padding above, so it fully fades before the page's true
   bottom edge (the navbar chip has no such ceiling, hence its larger
   8px/1px → 18px/5px glow). */
@keyframes ai-composer-glow-pulse {
  0%, 100% { box-shadow: 0 0 4px 1px rgba(91, 112, 101, .45); }
  50%      { box-shadow: 0 0 8px 2px rgba(91, 112, 101, .85); }
}
