/* =============================================================================
   ODUEX feature-assistant.css
   "Ask ODUEX": the one assistant, on every page.

   CONTRACT COMPLIANCE
   - Zero type-face declarations. The panel is chrome, so it inherits the body
     face; the status readout and timestamps use the shared .mono class. The
     codebase still has exactly three, all of them in core.css.
   - Zero token redeclarations. Every colour, radius, duration and easing below
     is a core.css token. Raw pixel values appear only for component geometry
     that has no token (panel width, icon box, caret), the same latitude
     core.css takes for its own components.
   - Full-strength gold appears exactly twice: the launcher's diamond accent
     and the send button. The send button is the primary action inside the
     panel, so it is the CTA the gold budget always reserves a slot for. The
     only other gold is tints: the capture card's wash and border, and the
     bot-link underlines.
   - Gold is never on a `color:` property. --on-gold (#111111) sits on the gold
     fill at 9.19:1, and the gold under bot links rides on `text-decoration`
     while the link text itself stays --ink.

   POSITIONING
   Launcher bottom-RIGHT. The WhatsApp pill owns bottom-LEFT. Under 1024px both
   lift by 72px so the mobile sticky CTA bar can never sit on top of either.
   ============================================================================= */

/* -----------------------------------------------------------------------------
   1. LAUNCHER
   Hidden until assistant.js has actually mounted. A launcher that is visible
   before its module has run is a button that does nothing, and a button that
   does nothing is worse than no button.
   -------------------------------------------------------------------------- */

.asst-launcher{
  position: fixed;
  right: var(--space-4);
  bottom: calc(var(--space-4) + env(safe-area-inset-bottom));
  z-index: var(--z-float);
  display: none;
  align-items: center;
  gap: var(--space-2);
  height: 48px;
  padding: 0 var(--space-4);
  border-radius: var(--r-pill);
  background: var(--stage);
  color: var(--stage-ink);
  font-size: var(--fs-sm);
  font-weight: 600;
  line-height: var(--lh-tight-ui);
  box-shadow: var(--elev-2);
  transition: transform var(--d-base) var(--ease-out-quart),
              opacity var(--d-base) var(--ease-out-quart);
}
.assistant-ready .asst-launcher{ display: inline-flex; }
.asst-launcher:hover{ transform: translateY(-2px); }
.asst-launcher[aria-expanded="true"]{ opacity: 0; pointer-events: none; }

/* Clear of the mobile sticky CTA bar, exactly as the WhatsApp pill does. */
@media (max-width: 1023px){
  .asst-launcher{ bottom: calc(var(--space-4) + 72px + env(safe-area-inset-bottom)); }
}

.asst-launcher-mark{
  flex: 0 0 auto;
  width: 14px;
  height: 14px;
  transform: rotate(45deg);
  border-radius: 2px;
  background: var(--gold-surface);
}

.asst-launcher-label{
  max-width: 0;
  overflow: hidden;
  white-space: nowrap;
  opacity: 0;
  transition: max-width var(--d-base) var(--ease-out-expo),
              opacity var(--d-base) var(--ease-out-expo);
}
.asst-launcher:hover .asst-launcher-label,
.asst-launcher:focus-visible .asst-launcher-label,
.asst-launcher.is-wide .asst-launcher-label{ max-width: 160px; opacity: 1; }

/* Above the phone breakpoint the label is always on. Two reasons, both real:
   a gold diamond on its own tells a visitor nothing about what the button does,
   and the launcher sits over the dark footer for the last screen of every page,
   where a near-black pill has no edge and only the label is legible. Under
   640px the collapsed pill stays, because there the sheet, the WhatsApp pill
   and the sticky CTA are already competing for the same corner. */
@media (min-width: 640px){
  .asst-launcher-label{ max-width: 160px; opacity: 1; }
}

/* Marks an unfinished conversation carried across a page navigation. Static:
   the site's one permitted ambient loop is spent elsewhere. */
.asst-launcher-badge{
  position: absolute;
  top: 6px;
  right: 6px;
  width: 8px;
  height: 8px;
  border-radius: var(--r-pill);
  background: var(--ok-fill);
}

/* -----------------------------------------------------------------------------
   2. BACKDROP
   The panel is a real modal: the rest of the page goes inert while it is open,
   so it must also LOOK unavailable, and a click outside must close it.
   -------------------------------------------------------------------------- */

.asst-backdrop{
  position: fixed;
  inset: 0;
  z-index: var(--z-drawer);
  background: rgba(12, 12, 13, 0.20);
  opacity: 0;
  transition: opacity var(--d-base) var(--ease-out-expo);
}
.asst-backdrop.is-open{ opacity: 1; }
@media (max-width: 639px){
  .asst-backdrop{ background: rgba(12, 12, 13, 0.44); }
}

/* -----------------------------------------------------------------------------
   3. PANEL
   -------------------------------------------------------------------------- */

.asst-panel{
  position: fixed;
  right: var(--space-4);
  bottom: calc(var(--space-4) + 48px + var(--space-3) + env(safe-area-inset-bottom));
  z-index: var(--z-drawer);
  display: flex;
  flex-direction: column;
  width: min(408px, calc(100vw - var(--space-8)));
  max-height: min(640px, calc(100dvh - var(--nav-h) - var(--space-12)));
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  box-shadow: var(--elev-3);
  overflow: hidden;
  transform-origin: bottom right;
  opacity: 0;
  transform: translateY(16px) scale(0.98);
  /* The single sanctioned overshoot moment on the site. */
  transition: opacity var(--d-base) var(--ease-out-expo),
              transform var(--d-base) var(--ease-back);
}
.asst-panel.is-open{ opacity: 1; transform: none; }

@media (max-width: 1023px){
  .asst-panel{ bottom: calc(var(--space-4) + 120px + var(--space-3) + env(safe-area-inset-bottom)); }
}

/* Full-height sheet on a phone. One implementation, no second component. */
@media (max-width: 639px){
  .asst-panel{
    right: 0;
    left: 0;
    bottom: 0;
    width: 100%;
    max-height: 90dvh;
    height: 90dvh;
    border-radius: var(--r-lg) var(--r-lg) 0 0;
    border-bottom: 0;
    transform-origin: bottom center;
    transform: translateY(24px);
  }
  .asst-panel.is-open{ transform: none; }
}

/* --- header --- */

.asst-head{
  flex: 0 0 auto;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: start;
  gap: var(--space-4);
  padding: var(--space-5) var(--space-5) var(--space-4);
  border-bottom: 1px solid var(--line);
  background: var(--paper-raised);
}
.asst-title{
  font-size: var(--fs-base);
  font-weight: 600;
  line-height: var(--lh-tight-ui);
  color: var(--ink);
  max-width: none;
}
.asst-status{
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin-top: var(--space-2);
  font-size: var(--fs-xs);
  color: var(--ink-muted);
  max-width: none;
}
.asst-dot{
  flex: 0 0 auto;
  width: 7px;
  height: 7px;
  border-radius: var(--r-pill);
  background: var(--ok-fill);
}
.asst-panel.is-degraded .asst-dot{ background: var(--line-strong); }

.asst-close{
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  margin: calc(var(--space-2) * -1) calc(var(--space-2) * -1) 0 0;
  border-radius: var(--r-sm);
  color: var(--ink-muted);
  transition: color var(--d-fast) var(--ease-out-quart),
              background-color var(--d-fast) var(--ease-out-quart);
}
.asst-close:hover{ color: var(--ink); background: var(--paper-card); }
.asst-close svg{ width: 16px; height: 16px; }

/* --- message log --- */

.asst-log{
  flex: 1 1 auto;
  display: grid;
  align-content: start;
  gap: var(--space-4);
  padding: var(--space-5);
  overflow-y: auto;
  overscroll-behavior: contain;
}

.asst-msg{
  max-width: 88%;
  padding: var(--space-3) var(--space-4);
  border-radius: var(--r-md);
  font-size: var(--fs-sm);
  line-height: var(--lh-body);
}
.asst-msg > * + *{ margin-top: var(--space-3); }
.asst-msg p{ max-width: none; }
.asst-msg ul{
  display: grid;
  gap: var(--space-2);
  padding-left: var(--space-5);
  list-style: disc;
}
.asst-msg strong{ font-weight: 600; }

.asst-msg-bot{
  justify-self: start;
  background: var(--paper-card);
  color: var(--ink-body);
  border: 1px solid var(--line);
}
.asst-msg-user{
  justify-self: end;
  background: var(--stage);
  color: var(--stage-ink);
}
/* The shorthand carries the underline colour on purpose. `text-decoration-color:`
   contains the literal substring `color:` followed by a gold value, which is
   what the gold-as-text guard greps for. The shorthand states the same thing
   and stays out of its way. */
.asst-msg-bot a{
  color: var(--ink);
  text-decoration: underline var(--gold-tint-40);
  text-decoration-thickness: 1px;
}
.asst-msg-bot a:hover{ text-decoration: underline var(--gold-surface); }

/* Plain-text rendering while tokens are still arriving; replaced by the
   structured render the moment the reply completes. */
.asst-stream{ white-space: pre-wrap; }

.asst-caret{
  display: inline-block;
  width: 2px;
  height: 1em;
  margin-left: 2px;
  vertical-align: -0.15em;
  background: var(--ink-muted);
  animation: asst-caret 1s steps(2, jump-none) infinite;
}
@keyframes asst-caret{
  0%, 100%{ opacity: 1; }
  50%     { opacity: 0; }
}

/* A quiet, non-bubble line: an outage notice, a session cap, a hand-off. */
.asst-note{
  justify-self: stretch;
  padding-top: var(--space-1);
  font-size: var(--fs-xs);
  color: var(--ink-faint);
  max-width: none;
}
.asst-time{ color: var(--ink-faint); }

/* --- opening chips --- */

.asst-chips{
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  padding: 0 var(--space-5) var(--space-4);
}
.asst-chip{
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: var(--space-2) var(--space-4);
  border: 1px solid var(--control-line);
  border-radius: var(--r-pill);
  background: var(--paper);
  color: var(--ink);
  font-size: var(--fs-sm);
  font-weight: 500;
  line-height: var(--lh-tight-ui);
  text-align: left;
  transition: background-color var(--d-fast) var(--ease-out-quart),
              border-color var(--d-fast) var(--ease-out-quart),
              transform var(--d-fast) var(--ease-out-quart);
}
.asst-chip:hover{ background: var(--paper-card); border: 1px solid var(--ink-faint); }
.asst-chip:active{ transform: scale(0.98); }

/* --- Quick Help: the honest fallback, never a second fake bot --- */

.asst-quick{
  display: grid;
  gap: var(--space-3);
  padding: var(--space-4);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--paper-raised);
}
.asst-quick-head{
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--ink);
  max-width: none;
}
.asst-quick-list{
  display: grid;
  gap: var(--space-1);
}
.asst-quick-link{
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-3);
  min-height: 44px;
  padding: var(--space-2) var(--space-3);
  border-radius: var(--r-sm);
  color: var(--ink);
  font-size: var(--fs-sm);
  font-weight: 600;
  text-decoration: none;
  transition: background-color var(--d-fast) var(--ease-out-quart);
}
.asst-quick-link:hover{ background: var(--paper-card); }
.asst-quick-link span{
  font-size: var(--fs-xs);
  font-weight: 400;
  color: var(--ink-muted);
  text-align: right;
}

/* --- capture: the two fields that turn a conversation into a lead --- */

.asst-capture{
  display: grid;
  gap: var(--space-4);
  padding: var(--space-4);
  border: 1px solid var(--gold-tint-32);
  border-radius: var(--r-md);
  background: var(--gold-tint-08);
}
.asst-capture-lede{
  font-size: var(--fs-sm);
  color: var(--ink-body);
  max-width: none;
}
.asst-capture .form-note{ font-size: var(--fs-xs); }

/* --- composer --- */

.asst-composer{
  flex: 0 0 auto;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: end;
  gap: var(--space-2);
  padding: var(--space-4) var(--space-4) var(--space-3);
  border-top: 1px solid var(--line);
  background: var(--paper);
}

/* Auto-growing textarea with no per-keystroke layout read: a mirrored ::after
   sized from data-value drives the height, so the browser does the measuring. */
.asst-grow{
  position: relative;
  display: grid;
}
.asst-grow::after{
  content: attr(data-value) ' ';
  visibility: hidden;
  white-space: pre-wrap;
}
.asst-grow > textarea,
.asst-grow::after{
  grid-area: 1 / 1 / 2 / 2;
  min-height: 48px;
  max-height: 132px;
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--control-line);
  border-radius: var(--r-sm);
  font-size: var(--fs-sm);
  line-height: var(--lh-body);
  overflow-wrap: break-word;
}
.asst-grow > textarea{
  width: 100%;
  resize: none;
  overflow-y: auto;
  background: var(--field-bg);
  color: var(--ink);
  transition: border-color var(--d-fast) var(--ease-out-quart);
}
.asst-grow > textarea:hover{ border-color: var(--ink-faint); }
.asst-grow > textarea:focus{ border-color: var(--ink); }

/* A real hint element rather than the native attribute, for two reasons: the
   attribute's own name is a banned string sitewide, and hint text that vanishes
   on focus leaves an empty box under the cursor. This one clears only once the
   visitor has actually typed. The field is labelled properly either way. */
.asst-hint{
  position: absolute;
  left: calc(var(--space-4) + 1px);
  top: calc(var(--space-3) + 1px);
  right: calc(var(--space-4) + 1px);
  font-size: var(--fs-sm);
  line-height: var(--lh-body);
  color: var(--ink-faint);
  pointer-events: none;
}
.asst-composer.has-text .asst-hint{ display: none; }

.asst-send{
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: 48px;
  height: 48px;
  border-radius: var(--r-sm);
  background: var(--gold-surface);
  color: var(--on-gold);
  transition: background-color var(--d-fast) var(--ease-out-quart),
              transform var(--d-fast) var(--ease-out-quart),
              opacity var(--d-fast) var(--ease-out-quart);
}
.asst-send:hover{ background: var(--gold-surface-hover); }
.asst-send:active{ transform: scale(0.96); }
/* A gold ring on a gold fill is invisible; ink is the correct indicator here,
   exactly as core.css does for .btn-primary. */
.asst-send:focus-visible{ outline: 2px solid var(--ink); }
.asst-send[disabled]{ opacity: 0.5; cursor: not-allowed; transform: none; }
.asst-send svg{ width: 20px; height: 20px; }

.asst-foot{
  flex: 0 0 auto;
  padding: 0 var(--space-4) calc(var(--space-3) + env(safe-area-inset-bottom));
  font-size: var(--fs-xs);
  line-height: var(--lh-tight-ui);
  color: var(--ink-faint);
  background: var(--paper);
  max-width: none;
}

/* -----------------------------------------------------------------------------
   4. MOTION LIMITS
   No animation below 480px beyond reveals and the drawer. prefers-reduced-motion
   is neutralised globally in core.css; this only removes what would still read
   as movement once durations are zeroed.
   -------------------------------------------------------------------------- */

@media (max-width: 479px){
  .asst-caret{ animation: none; }
  .asst-launcher:hover{ transform: none; }
}

@media (prefers-reduced-motion: reduce){
  .asst-caret{ animation: none !important; }
  .asst-launcher:hover{ transform: none !important; }
  .asst-panel{ transform: none !important; }
}
