:root {
  --fonteyn-green: #2d5e3e;
  --fonteyn-green-dark: #234c31;
  --bg: #f4f4f1;
  --card: #ffffff;
  --bot-bubble: #eef2ee;
  --user-bubble: var(--fonteyn-green);
  --text: #1c1f1c;
  --muted: #6b6f6b;
  --border: #e2e2dd;
  --shadow: 0 4px 24px rgba(0, 0, 0, 0.08);
  --radius: 14px;
  --link: var(--fonteyn-green-dark);
}

* {
  box-sizing: border-box;
}

body,
html {
  margin: 0;
  padding: 0;
  font-family:
    -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue",
    Arial, sans-serif;
  color: var(--text);
  background: var(--bg);
  height: 100%;
}

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.page {
  min-height: 100vh;
  display: flex;
}

.chat {
  width: 100%;
  height: 100vh;
  background: var(--card);
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.chat__header {
  background: var(--fonteyn-green);
  color: #fff;
  padding: 18px 20px 14px;
  display: flex;
  align-items: center;
  gap: 12px;
}

/* Embedded mode (loaded via embed.js into the storefront iframe) reserves
   extra right-padding so the language picker + new-chat pill stay clear of
   the parent page's absolute close button (top:14px right:14px). The
   standalone page (`/`) lacks the `?embedded=1` flag and keeps the
   original layout. */
.chat--embedded .chat__header {
  padding-right: 56px;
}

.chat__title-block {
  flex: 1;
  min-width: 0;
}

.chat__title {
  font-size: 18px;
  margin: 0;
  font-weight: 600;
  letter-spacing: 0.2px;
}

.chat__subtitle {
  margin: 4px 0 0;
  font-size: 13px;
  opacity: 0.9;
}

.chat__new {
  flex: none;
  width: 34px;
  height: 34px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.15);
  border: 1px solid rgba(255, 255, 255, 0.35);
  color: #fff;
  font-size: 22px;
  line-height: 1;
  padding: 0;
  cursor: pointer;
  font-family: inherit;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: background 120ms ease;
}

.chat__new:hover,
.chat__new:focus-visible {
  background: rgba(255, 255, 255, 0.28);
  outline: none;
}

/* Language selector — sits next to the new-chat pill, matches its translucent
   white-on-green look. Native <select> so the dropdown is OS-native and
   accessible; we just style the closed control to fit the brand header. */
.chat__lang {
  flex: none;
  height: 30px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.15);
  border: 1px solid rgba(255, 255, 255, 0.35);
  color: #fff;
  font-family: inherit;
  font-size: 13px;
  font-weight: 600;
  line-height: 1;
  padding: 0 10px;
  cursor: pointer;
  appearance: none;
  -webkit-appearance: none;
  -moz-appearance: none;
  transition: background 120ms ease;
}

.chat__lang:hover,
.chat__lang:focus-visible {
  background: rgba(255, 255, 255, 0.28);
  outline: none;
}

/* The native <option> list inherits from the document, not the dark
   header — give options readable defaults. */
.chat__lang option {
  color: var(--text);
  background: #fff;
}

.chat__messages {
  flex: 1;
  overflow-y: auto;
  padding: 16px 18px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  background: #fafaf7;
}

.bubble {
  max-width: 85%;
  padding: 10px 14px;
  border-radius: 14px;
  font-size: 14.5px;
  line-height: 1.5;
  word-wrap: break-word;
  white-space: pre-wrap;
}

.bubble--bot {
  background: var(--bot-bubble);
  color: var(--text);
  align-self: flex-start;
  border-bottom-left-radius: 4px;
}

.bubble--user {
  background: var(--user-bubble);
  color: #fff;
  align-self: flex-end;
  border-bottom-right-radius: 4px;
}

.bubble a {
  color: var(--link);
  text-decoration: underline;
  word-break: break-all;
}

.bubble--user a {
  color: #fff;
}

/* Error bubble — muted warm-grey surface (not the punchy red the chat
   used to render upstream API failures into). Uses the same palette
   variables as the rest of the widget plus a brand-green left border so
   the message clearly reads as a system notice without screaming. */
.bubble--error {
  background: var(--bot-bubble);
  color: var(--text);
  border: 1px solid var(--border);
  border-left: 3px solid var(--fonteyn-green-dark);
  max-width: 95%;
}

.bubble__retry {
  display: inline-block;
  margin-top: 8px;
  background: transparent;
  border: 1px solid var(--fonteyn-green-dark);
  color: var(--fonteyn-green-dark);
  padding: 4px 10px;
  border-radius: 8px;
  font-size: 12.5px;
  cursor: pointer;
  font-family: inherit;
}

.bubble__retry:hover,
.bubble__retry:focus-visible {
  background: var(--fonteyn-green-dark);
  color: #fff;
  outline: none;
}

.chat__busy {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 0 18px 8px;
}

/* `display:flex` above overrides the user-agent's `[hidden] { display:none }`,
 * so the typing indicator would otherwise show constantly. Re-assert here. */
.chat__busy[hidden] {
  display: none;
}

.chat__busy-bubble {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 10px 14px;
  background: var(--bot-bubble);
  border-radius: 14px;
  border-bottom-left-radius: 4px;
}

.chat__busy-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--fonteyn-green);
  opacity: 0.4;
  animation: fonteyn-busy-bounce 1.2s infinite ease-in-out;
}

.chat__busy-dot:nth-child(2) {
  animation-delay: 0.15s;
}

.chat__busy-dot:nth-child(3) {
  animation-delay: 0.3s;
}

@keyframes fonteyn-busy-bounce {
  0%,
  60%,
  100% {
    transform: translateY(0);
    opacity: 0.4;
  }
  30% {
    transform: translateY(-5px);
    opacity: 1;
  }
}

.chat__busy-label {
  font-style: italic;
  color: var(--muted);
  font-size: 12.5px;
  line-height: 1.3;
}

@media (prefers-reduced-motion: reduce) {
  .chat__busy-dot {
    animation: none;
    opacity: 0.7;
  }
}

/* In-widget confirm bar — replaces window.confirm() for the "+" new-chat
   action. Sits between the busy indicator and the composer so it reads as
   a slide-in tray attached to the input area. Brand-green primary button
   and a thin top border anchor it visually. The bar is hidden by default
   (markup `hidden` attribute); widget.js toggles visibility. */
.chat__confirm {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 10px 14px;
  background: #fff;
  border-top: 1px solid var(--border);
  flex-wrap: wrap;
}

.chat__confirm[hidden] {
  display: none;
}

.chat__confirm-text {
  margin: 0;
  font-size: 13.5px;
  line-height: 1.4;
  color: var(--text);
  flex: 1;
  min-width: 0;
}

.chat__confirm-actions {
  display: flex;
  gap: 8px;
  flex: none;
}

.chat__confirm-btn {
  border-radius: 999px;
  padding: 6px 14px;
  font-size: 13px;
  font-weight: 600;
  font-family: inherit;
  cursor: pointer;
  line-height: 1.2;
  transition:
    background 120ms ease,
    color 120ms ease;
}

.chat__confirm-btn--ghost {
  background: transparent;
  border: 1px solid var(--border);
  color: var(--text);
}

.chat__confirm-btn--ghost:hover,
.chat__confirm-btn--ghost:focus-visible {
  background: var(--bot-bubble);
  outline: none;
}

.chat__confirm-btn--primary {
  background: var(--fonteyn-green);
  border: 1px solid var(--fonteyn-green);
  color: #fff;
}

.chat__confirm-btn--primary:hover,
.chat__confirm-btn--primary:focus-visible {
  background: var(--fonteyn-green-dark);
  border-color: var(--fonteyn-green-dark);
  outline: none;
}

.chat__composer {
  display: flex;
  gap: 8px;
  padding: 12px 14px 14px;
  border-top: 1px solid var(--border);
  background: #fff;
}

.chat__input {
  flex: 1;
  resize: none;
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 10px 16px;
  font: inherit;
  font-size: 14.5px;
  outline: none;
  background: #fff;
  max-height: 120px;
  line-height: 1.4;
}

.chat__input:focus {
  border-color: var(--fonteyn-green);
  box-shadow: 0 0 0 2px rgba(45, 94, 62, 0.15);
}

.chat__send {
  background: var(--fonteyn-green);
  color: #fff;
  border: 0;
  border-radius: 999px;
  padding: 0 18px;
  font-weight: 600;
  font-size: 14px;
  cursor: pointer;
  transition: background 120ms ease;
}

.chat__send:hover {
  background: var(--fonteyn-green-dark);
}

.chat__send:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

/* ---------------------------------------------------------------------------
 * Product cards — rendered inline inside a bot bubble when the backend
 * streams a successful `search_products` / `recommend_products` tool_result.
 * The grid sits BELOW any intro text the bot has streamed so far, and any
 * follow-up text the bot streams afterwards appears below the grid.
 * ------------------------------------------------------------------------ */

/* Dense auto-fill grid: 3 columns when the bubble can fit ~140px wide
   cards (standalone chat / wide embed), 2 columns when narrower, 1 only
   when truly cramped. Replaces the prior fixed 2-column-then-1-column
   media query — auto-fill adapts to the actual available width inside
   the bot bubble (which itself is max-width: 85% of .chat__messages). */
.fonteyn-product-grid {
  display: grid;
  /* Always 3 columns. The bot bubble is widened to 95% via :has() below so
   * even on phones there's enough room for three small cards. */
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 6px;
  margin: 10px 0;
  /* position: relative is the anchor for the hover overlay (a card on hover
   * becomes position: absolute and uses left:0/right:0 to span this grid's
   * full width). Anchoring to the grid (not the bubble) is the only
   * configuration that gives a stable static y-position for the overlay —
   * anchoring to the bubble triggered a hover-flicker loop. */
  position: relative;
}

/* Widen the bot bubble whenever it contains a product grid — the 85% default
 * is fine for prose but wastes space when we're trying to fit 2-3 cards. */
.bubble--bot:has(.fonteyn-product-grid) {
  max-width: 95%;
}

/* The bot bubble has max-width 95% (widened by :has() above) — cards sit on
   top with their own card-like surface. They feel like their own surface
   rather than blending into the bubble.

   No min-height: the card's intrinsic content (image + title + price)
   drives the height in the compact state. Title clamp to 2 lines keeps
   cards in the same row visually aligned.

   Note: overflow lives on the image wrapper (not the card) so the
   rounded card corners + the hover-state's row layout both work without
   needing to clip on the card itself. */
.fonteyn-product-card {
  display: flex;
  flex-direction: column;
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 10px;
  text-decoration: none;
  color: var(--text);
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);
  transition: box-shadow 160ms ease;
  position: relative;
  /* Explicit grid placement — see appendProductGrid in widget.js for the
     reasoning. Without this, the absolute-positioned hover overlay leaves
     a gap that CSS Grid auto-placement fills by shifting other cards. */
  grid-column: var(--grid-col, auto);
  grid-row: var(--grid-row, auto);
}

/* When the card is wrapped in an <a> (has a URL), make it clearly clickable. */
a.fonteyn-product-card {
  cursor: pointer;
}

/* Invisible placeholder that occupies a grid cell. Inserted by
   appendProductGrid to pad trailing partial rows so every row always has
   3 in-flow items. Why this matters: when a real card becomes
   position: absolute on hover, it leaves grid flow; if its row had only
   1 or 2 real cards, the row would collapse to 0 height and the whole
   grid (and bubble) would shrink mid-hover — causing a hover-flicker.
   With placeholders the row always has 3 in-flow items holding it open. */
.fonteyn-product-card-placeholder {
  visibility: hidden;
  pointer-events: none;
  min-height: 190px;
  grid-column: var(--grid-col, auto);
  grid-row: var(--grid-row, auto);
}

/* Hover affordance — confined to devices with a real hover capability so
   touch screens never get a stuck `:hover` state.

   On hover the card becomes a position: absolute overlay anchored to the
   grid's top-left and right edges, so it spans the FULL width of the
   product grid (= the bubble interior). The non-hovered siblings keep
   their layout slots (no reflow) but become visibility: hidden so the
   overlay reads cleanly on top.

   Layout stays vertical (image on top, text below) — only the image and
   card get bigger. Font sizes don't change. */
@media (hover: hover) {
  .fonteyn-product-card:hover,
  .fonteyn-product-card:focus-visible {
    position: absolute;
    /* Override grid-column to span the whole row so the abspos
       containing block is the full row width — that's what makes
       left:0/right:0 stretch to the bubble's inner edges instead of
       being clamped to a single column. grid-row stays at the card's
       assigned row, so the overlay anchors at that row's top in
       grid-coords (which equals the card's static y-position).

       Why not `a.fonteyn-product-card:hover`: products without an
       `onlineStoreUrl` (Storefront API returns null for unpublished
       items) render as <div> instead of <a> (see widget.js
       makeProductCard). The `a.` qualifier silently skipped them, so
       the inner image/details rules fired (height grew, panel showed)
       but the outer abspos rule didn't (card stayed clamped to one
       column). Dropping the `a.` makes both anchor and div cards get
       the full hover overlay. */
    grid-column: 1 / -1;
    left: 0;
    right: 0;
    box-shadow: 0 10px 28px rgba(0, 0, 0, 0.2);
    outline: none;
    z-index: 50;
  }

  /* No visibility toggle on siblings — the overlay's opaque card
     background + z-index: 50 hide everything behind it visually anyway,
     so we don't need a CSS toggle that re-evaluates on every hover
     state change. Toggling visibility via :has(:hover) was causing
     mouse-between-cards flicker: when the mouse left one overlay,
     siblings would briefly un-hide before the next hover registered,
     creating a frame where no card was hovered. Letting the siblings
     sit in flow (just painted under the overlay) makes card-to-card
     transitions stable. */
}

.fonteyn-product-card-image {
  width: 100%;
  height: 120px;
  background: var(--bot-bubble);
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  flex-shrink: 0;
  /* Match the card's rounded top corners — needed now that the card itself
     no longer has overflow: hidden to clip its children. */
  border-radius: 9px 9px 0 0;
}

/* On hover, the image grows tall (≈280px) and keeps the full card width
   on top of the vertical stack. Same border-radius (top-only) as the
   compact state — the card stays vertical, just bigger. */
@media (hover: hover) {
  .fonteyn-product-card:hover .fonteyn-product-card-image,
  .fonteyn-product-card:focus-visible .fonteyn-product-card-image {
    height: 280px;
  }
}

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

/* No-image placeholder: brand-green block with the title centered. Avoids
   the browser's broken-image icon on products where Shopify returns no
   featuredImage. Scaled down with the image area to keep the proportion. */
.fonteyn-product-card--no-image .fonteyn-product-card-image {
  background: var(--fonteyn-green);
  color: #fff;
}

.fonteyn-product-card-image__placeholder {
  display: block;
  padding: 8px 10px;
  text-align: center;
  font-size: 12px;
  font-weight: 600;
  line-height: 1.3;
  overflow: hidden;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 3;
}

.fonteyn-product-card-body {
  padding: 8px 10px 10px;
  display: flex;
  flex-direction: column;
  /* Title and price sit immediately adjacent — line-height handles their
     spacing instead of an explicit gap, which used to push the price to
     the bottom of the card. */
}

/* On hover, the body gets more breathing room. min-width: 0 lets long
   text children clip instead of pushing the card wider. */
@media (hover: hover) {
  .fonteyn-product-card:hover .fonteyn-product-card-body,
  .fonteyn-product-card:focus-visible .fonteyn-product-card-body {
    padding: 14px 18px 16px;
    min-width: 0;
  }
}

.fonteyn-product-card-title {
  font-size: 13px;
  font-weight: 600;
  line-height: 1.3;
  color: var(--text);
  /* Clamp to 2 lines so cards in the same row stay roughly aligned. */
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  overflow: hidden;
}

/* On hover the title is one line, full row, no ellipsis. Same font size
   as the compact state — only the wrapping changes (the wider overlay
   gives the title enough room to render in one line for typical titles). */
@media (hover: hover) {
  .fonteyn-product-card:hover .fonteyn-product-card-title,
  .fonteyn-product-card:focus-visible .fonteyn-product-card-title {
    display: block;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: clip;
    -webkit-line-clamp: unset;
  }
}

.fonteyn-product-card-price {
  font-size: 13px;
  font-weight: 700;
  color: var(--fonteyn-green-dark);
  margin-top: 2px;
}

/* Hover-reveal details panel — surfaces a tight, definition-list-style
   view of the product's top metafields. Hidden by default on the compact
   card; only devices that report a true hover capability get the reveal,
   and only when the card is hovered (at which point the card is in its
   wide horizontal layout). Mobile (touch) keeps the card compact and
   tappable with the panel completely hidden. */
.fonteyn-product-card-details {
  display: none;
}

@media (hover: hover) {
  .fonteyn-product-card-details {
    display: block;
    max-height: 0;
    opacity: 0;
    overflow: hidden;
    margin-top: 0;
    padding: 0 0 0 10px;
    border-left: 3px solid var(--fonteyn-green);
    background: transparent;
    transition:
      max-height 200ms ease,
      opacity 160ms ease,
      margin-top 160ms ease,
      padding 160ms ease;
  }

  .fonteyn-product-card:hover .fonteyn-product-card-details,
  .fonteyn-product-card:focus-visible .fonteyn-product-card-details {
    max-height: 320px;
    opacity: 1;
    margin-top: 10px;
    padding: 4px 0 4px 10px;
  }
}

.fonteyn-product-card-details-row {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  font-size: 11px;
  line-height: 1.4;
  padding: 1px 0;
  /* Each row is a single line — label left, value right, both ellipsised
     if they outgrow their share. Required because the card's hover state
     guarantees room for a full row (≈45% of the bubble width). */
  min-width: 0;
}

.fonteyn-product-card-details-label {
  color: var(--muted);
  font-weight: 500;
  flex-shrink: 0;
  white-space: nowrap;
}

.fonteyn-product-card-details-value {
  color: var(--text);
  text-align: right;
  font-weight: 600;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
}

/* ---------------------------------------------------------------------------
 * Customer Account login button (Wave 16).
 *
 * Rendered inline inside a bot bubble when the order_status tool returns
 * `authenticated:false`. Compact pill button in the brand green, sized to
 * read as a clear call-to-action without dominating the bubble.
 * ------------------------------------------------------------------------ */

.fonteyn-login-wrap {
  margin: 10px 0 4px;
}

.fonteyn-login-button {
  background: var(--fonteyn-green);
  color: #fff;
  border: 0;
  border-radius: 999px;
  padding: 8px 16px;
  font-size: 13.5px;
  font-weight: 600;
  font-family: inherit;
  cursor: pointer;
  transition: background 120ms ease;
}

.fonteyn-login-button:hover,
.fonteyn-login-button:focus-visible {
  background: var(--fonteyn-green-dark);
  outline: none;
}
