/* ht-kit — assistant.css
   Layer 2 component. Reads the token contract only.
   No literal colour, font name or pixel value belongs in this file, with the
   one exception of the scoped token block below, which is where the values the
   contract has no name for are allowed to live. They are listed in
   md/README.md so nothing hides here. */

.assistant{
  --a-bubble:3.5rem;          /* 56px. The floating button.                  */
  --a-panel-w:22.5rem;        /* 360px. The panel from tablet up.            */
  --a-panel-h:70vh;           /* the tallest the panel ever gets             */
  --a-dim:0.6;                /* opacity of a screen already answered        */
  --a-travel:var(--space-4);  /* slide distance, panel and screens           */
  --a-edge:var(--space-4);    /* gap from the edge of the viewport           */
  --a-bar:0rem;               /* height of a sticky action bar, if any       */
  --a-reveal:500ms;           /* window the typed answer reveals over        */
  --a-think:700ms;            /* least time the dots stay up                 */

  position:fixed;
  right:var(--a-edge);
  bottom:calc(var(--a-edge) + var(--a-bar) + env(safe-area-inset-bottom, 0px));
  z-index:5;
  display:grid;
  justify-items:end;
  gap:var(--space-3);
  font-family:var(--font-body);
  font-size:var(--step-0);
  line-height:var(--lh-body);

  /* The closed panel still takes up its box, so this container is a 360 wide
     column standing over the page whether or not anything is showing in it.
     Without this it quietly swallows every click on whatever is underneath.
     The two things that are meant to be clickable opt back in. */
  pointer-events:none;
}

.assistant__bubble{pointer-events:auto}

/* Three things the engine builds are for screen readers only: the composer's
   label, the waiting message beside the dots, and the region the relay's
   answer is announced from. This lives here rather than in main.css so it
   travels with the component: on a host site with no utility of its own the
   label would otherwise paint as text and take a column of the composer grid
   with it. Hidden from sight, never from the accessibility tree. */
.assistant .vh{
  position:absolute;
  width:var(--border);height:var(--border);
  margin:calc(var(--border) * -1);
  padding:0;border:0;
  overflow:hidden;
  clip-path:inset(50%);
  white-space:nowrap;
}

/* The engine hides the Back control and the composer with the hidden
   attribute. An author rule setting display beats the browser's own
   [hidden]{display:none}, and both of those carry one, so the attribute has
   to be honoured here or it does nothing at all. Two classes, so it wins
   against every single class rule below whatever the order. */
.assistant [hidden]{display:none}

/* ---------- bubble ---------- */

/* Row order is set here rather than by document order, so the button can come
   first in the DOM, where a control that opens a dialog belongs. */
.assistant__bubble{grid-row:2}
.assistant__panel{grid-row:1}

.assistant__bubble{
  display:inline-flex;
  align-items:center;
  justify-content:center;
  gap:var(--space-2);
  height:var(--a-bubble);
  min-width:var(--a-bubble);
  padding-inline:var(--space-4);
  border:var(--border) solid transparent;
  border-radius:calc(var(--a-bubble) / 2);
  background:var(--accent);
  color:var(--accent-ink);
  font-family:var(--font-utility);
  font-size:var(--step-0);
  font-weight:600;
  line-height:1.2;
  cursor:pointer;
  transition:
    transform var(--dur-fast) var(--ease),
    opacity var(--dur-fast) var(--ease);
}
.assistant__bubble:hover{opacity:0.88}
.assistant__bubble:active{transform:scale(0.97)}

.assistant__icon{
  flex:0 0 auto;
  width:var(--space-5);
  height:var(--space-5);
  fill:none;
  stroke:currentColor;
  stroke-width:calc(var(--border) * 2);
  stroke-linecap:round;
  stroke-linejoin:round;
}

/* ---------- panel ---------- */

.assistant__panel{
  width:min(var(--a-panel-w), calc(100vw - var(--a-edge) * 2));
  max-height:var(--a-panel-h);
  display:grid;
  grid-template-rows:auto minmax(0,1fr) auto;
  overflow:hidden;
  border:var(--border) solid var(--rule-strong);
  border-radius:var(--radius);
  background:var(--surface);
  color:var(--ink);
  opacity:0;
  visibility:hidden;
  pointer-events:none;
  transform:translateY(var(--a-travel));
  transition:
    opacity var(--dur-base) var(--ease),
    transform var(--dur-base) var(--ease),
    visibility 0s linear var(--dur-base);
}

.assistant.is-open .assistant__panel{
  opacity:1;
  visibility:visible;
  pointer-events:auto;
  transform:none;
  transition:
    opacity var(--dur-base) var(--ease),
    transform var(--dur-base) var(--ease),
    visibility 0s linear 0s;
}

/* Three fixed columns rather than a flex row, so the title stays put when the
   Back button comes and goes. Each control is placed by hand, because a hidden
   button leaves its column empty rather than letting the others slide left. */
.assistant__head{
  display:grid;
  grid-template-columns:var(--tap) minmax(0,1fr) var(--tap);
  align-items:center;
  padding:var(--space-2);
  border-bottom:var(--border) solid var(--rule);
}

.assistant__title{
  grid-column:2;
  text-align:center;
  font-family:var(--font-utility);
  font-size:var(--step--1);
  font-weight:600;
  letter-spacing:0.08em;
  text-transform:uppercase;
  color:var(--muted);
}

.assistant__back,
.assistant__close{
  width:var(--tap);
  height:var(--tap);
  display:grid;
  place-items:center;
  border:0;
  border-radius:calc(var(--radius) / 2);
  background:none;
  color:var(--muted);
  font-size:var(--step-1);
  line-height:1;
  cursor:pointer;
  transition:color var(--dur-fast) var(--ease);
}
.assistant__back{grid-column:1}
.assistant__close{grid-column:3}
.assistant__back:hover,
.assistant__close:hover{color:var(--ink)}

/* ---------- thread ---------- */

.assistant__thread{
  position:relative;
  display:grid;
  align-content:start;
  gap:var(--space-6);
  padding:var(--space-5) var(--space-4) var(--space-4);
  overflow-y:auto;
  overscroll-behavior:contain;
  -webkit-overflow-scrolling:touch;
}

.assistant__screen{
  display:grid;
  justify-items:start;
  gap:var(--space-4);
  transition:
    opacity var(--dur-base) var(--ease),
    transform var(--dur-base) var(--ease);
}

/* Answered screens stay on the thread so the path is visible, dimmed so the
   live one is obvious. */
.assistant__screen[data-live="false"]{opacity:var(--a-dim)}

/* The newest screen is placed shifted and transparent, then released on the
   next frame. Transform and opacity only. */
.assistant__screen[data-enter="true"]{
  opacity:0;
  transform:translateX(var(--a-travel));
}

/* No bubbles. The panel is already a surface, and a box inside a box inside a
   box is what makes a widget feel like a widget. */
.assistant__text{width:100%}
.assistant__text:focus{outline:none}
.assistant__text:focus-visible{
  outline:calc(var(--border) * 2) solid var(--accent);
  outline-offset:var(--space-1);
}

.assistant__greeting{
  width:100%;
  color:var(--muted);
  font-size:var(--step--1);
}

/* What the visitor tapped, kept on the thread as their side of it. Quiet:
   they know what they tapped, it is there to show the path. */
.assistant__said{
  justify-self:end;
  max-width:100%;
  padding:var(--space-1) var(--space-3);
  border:var(--border) solid var(--rule);
  border-radius:calc(var(--radius) * 2);
  color:var(--muted);
  font-size:var(--step--1);
}

.assistant__options,
.assistant__fields{
  display:grid;
  gap:var(--space-2);
  width:100%;
  transition:
    opacity var(--dur-base) var(--ease),
    transform var(--dur-base) var(--ease);
}

.assistant__fields{gap:var(--space-4)}

/* Held back until the answer has finished arriving, then let go. */
.assistant__options[data-rise],
.assistant__fields[data-rise]{
  opacity:0;
  transform:translateY(var(--a-travel));
  pointer-events:none;
}

/* The one thing in the panel that keeps a border, because it is the one thing
   that has to read as tappable. --rule-strong is the 3:1 token, so it stays. */
.assistant__option{
  width:100%;
  min-height:var(--tap);
  padding:var(--space-3) var(--space-4);
  border:var(--border) solid var(--rule-strong);
  border-radius:var(--radius);
  background:var(--surface);
  font-family:var(--font-utility);
  font-size:var(--step--1);
  text-align:left;
  cursor:pointer;
  transition:
    border-color var(--dur-fast) var(--ease),
    transform var(--dur-fast) var(--ease);
}
.assistant__option:hover{border-color:var(--accent)}
.assistant__option:active{transform:scale(0.99)}

/* ---------- contact screen ---------- */

.assistant__screen--contact{width:100%;justify-items:stretch}

.assistant__field{display:grid;gap:var(--space-1);width:100%}

.assistant__label{
  font-family:var(--font-utility);
  font-size:var(--step--1);
  font-weight:600;
}
.assistant__note{font-weight:400;color:var(--muted)}

.assistant__input{
  width:100%;
  min-height:var(--tap);
  padding:var(--space-2) var(--space-3);
  border:var(--border) solid var(--rule-strong);
  border-radius:var(--radius);
  background:var(--surface);
  font-size:var(--step-0);
  transition:border-color var(--dur-fast) var(--ease);
}
.assistant__input:hover{border-color:var(--accent)}

.assistant__input--tall{
  min-height:calc(var(--tap) * 2);
  line-height:var(--lh-body);
  resize:vertical;
}

.assistant__send{width:100%;padding-inline:var(--space-4)}

.assistant__small{color:var(--muted);font-size:var(--step--1)}

/* ---------- typing, when the config carries a sort url ---------- */

.assistant__ask{
  display:grid;
  grid-template-columns:minmax(0,1fr) var(--tap);
  gap:var(--space-2);
  align-items:center;
  padding:var(--space-3);
  border-top:var(--border) solid var(--rule);
}

.assistant__askfield{
  min-width:0;
  min-height:var(--tap);
  padding:var(--space-2) var(--space-3);
  border:var(--border) solid var(--rule-strong);
  border-radius:var(--radius);
  background:var(--surface);
  font-size:var(--step--1);
  transition:border-color var(--dur-fast) var(--ease);
}
.assistant__askfield:hover{border-color:var(--accent)}
.assistant__askfield::placeholder{color:var(--muted);opacity:1}
.assistant__askfield:disabled{opacity:0.5}

.assistant__asksend{
  width:var(--tap);
  height:var(--tap);
  display:grid;
  place-items:center;
  border:0;
  border-radius:calc(var(--radius) / 2);
  background:none;
  color:var(--muted);
  font-size:var(--step-1);
  line-height:1;
  cursor:pointer;
  transition:color var(--dur-fast) var(--ease);
}
.assistant__asksend:hover{color:var(--ink)}
.assistant__asksend:disabled{opacity:0.5;cursor:not-allowed}

.assistant__asknote{
  grid-column:1 / -1;
  padding-top:var(--space-1);
  color:var(--muted);
  font-size:var(--step--1);
}

/* ---------- waiting on the relay ---------- */

/* Focus parks here while the input is disabled, so the ring wants to be around
   the dots rather than around the width of the panel. */
.assistant__screen[data-thinking]{justify-self:start;width:-moz-fit-content;width:fit-content}

.assistant__dots{
  display:flex;
  align-items:center;
  gap:var(--space-2);
  min-height:var(--space-5);
  padding-inline:var(--space-1);
}

.assistant__dot{
  width:var(--space-2);
  height:var(--space-2);
  border-radius:50%;
  background:var(--muted);
  opacity:0.3;
  animation:assistant-think calc(var(--dur-slow) * 2) var(--ease) infinite;
}
.assistant__dot:nth-child(2){animation-delay:calc(var(--dur-slow) / 3)}
.assistant__dot:nth-child(3){animation-delay:calc(var(--dur-slow) / 3 * 2)}

@keyframes assistant-think{
  0%,70%,100%{opacity:0.3}
  35%{opacity:1}
}

/* Reduced motion gets an ellipsis instead, written by the engine. */
.assistant__dots--still{
  color:var(--muted);
  font-size:var(--step-1);
  line-height:1;
}

/* ---------- the answer arriving ---------- */

.assistant__word{
  opacity:0;
  transition:opacity var(--dur-fast) var(--ease);
}
.assistant__text[data-revealed] .assistant__word{opacity:1}

/* Honeypot. Off screen rather than display:none so a bot still finds it. */
.assistant__hp{
  position:absolute;
  left:-100vw;
  width:var(--border);height:var(--border);
  opacity:0;
}

/* ---------- phone ---------- */

@media (max-width:767px){
  .assistant{--a-edge:var(--space-3);--a-panel-h:70dvh}

  /* Icon only. The button keeps its name through aria-label. */
  .assistant__bubble{width:var(--a-bubble);padding-inline:0}
  .assistant__label{display:none}

  /* Full width sheet. Out of the grid, so the bubble is free to step aside.
     Inline is excluded: it is part of the page, and a page does not become a
     sheet because the screen got narrower. */
  .assistant:not(.assistant--inline) .assistant__panel{
    position:fixed;
    left:0;right:0;bottom:0;
    width:auto;
    border-inline:0;
    border-bottom:0;
    border-radius:var(--radius) var(--radius) 0 0;
    padding-bottom:env(safe-area-inset-bottom, 0px);
  }

  /* The floating sheet covers the whole width, so the button steps aside.
     The stage keeps its button: the panel sits above it, and it is how the
     visitor closes and reopens the thing. */
  .assistant:not(.assistant--inline).is-open .assistant__bubble{visibility:hidden}

  /* A sticky action bar owns the bottom of the screen on a phone, so the
     bubble sits above it rather than on it. */
  body:has(.action-bar) .assistant{--a-bar:calc(var(--tap) + var(--space-3) * 2 + var(--border))}
}

/* ---------- reduced motion ---------- */

@media (prefers-reduced-motion:reduce){
  .assistant__panel,
  .assistant.is-open .assistant__panel,
  .assistant__screen,
  .assistant__bubble,
  .assistant__option{transition:none}

  .assistant__panel{transform:none}
  .assistant__screen[data-enter="true"]{transform:none}

  /* No pulse, no word by word, no rise. The engine also swaps the three dots
     for a plain ellipsis and drops the minimum hold, so the answer is simply
     there. */
  .assistant__dot{animation:none;opacity:1}
  .assistant__word{transition:none;opacity:1}
  .assistant__options,
  .assistant__fields{transition:none}
  .assistant__options[data-rise],
  .assistant__fields[data-rise]{opacity:1;transform:none;pointer-events:auto}
}

/* ---------- inline ---------- */

/* presentation: "inline". The page hands the component an element and it
   treats that element as a stage: the same button in the same corner, the
   same panel above it, opening and closing the same way, with everything
   measured against the stage instead of against the viewport.

   The only rules here are the ones that swap that frame of reference. The
   panel's own appearance and its open and close motion are the ones above,
   untouched, which is the point: it is the same panel. */

.assistant--inline{
  /* The one new scoped token. The column has no content of its own to give
     it a height, and a panel that grew with the conversation would move the
     whole section every time somebody tapped. Listed in md/README.md. */
  --a-inline-h:clamp(24rem, 60vh, 34rem);
  --a-edge:var(--space-4);

  position:relative;
  inset:auto;
  z-index:auto;
  display:block;
  height:100%;
  min-height:var(--a-inline-h);
  gap:0;
  background:var(--paper);
  pointer-events:auto;

  /* The panel belongs to the stage, including while it is sliding. */
  overflow:hidden;
}

.assistant--inline .assistant__bubble{
  position:absolute;
  right:var(--a-edge);
  bottom:var(--a-edge);
  z-index:2;
}

.assistant--inline .assistant__panel{
  grid-row:auto;
  position:absolute;
  right:var(--a-edge);
  bottom:calc(var(--a-edge) + var(--a-bubble) + var(--space-3));
  width:min(var(--a-panel-w), calc(100% - var(--a-edge) * 2));
  max-width:none;
  height:auto;

  /* As tall as the stage leaves it once the button has had its corner. */
  max-height:calc(100% - var(--a-bubble) - var(--space-3) - var(--a-edge) * 2);
}

@media (max-width:767px){
  .assistant--inline{--a-edge:var(--space-3)}

  /* The full width of the stage, the way the sheet takes the full width of
     the screen. */
  .assistant--inline .assistant__panel{
    left:0;
    right:0;
    width:auto;
  }
}

@media (prefers-reduced-motion:reduce){
  .assistant--inline .assistant__panel{transition:none}
}

/* ---------- tablet and phone: the panel sized down, full width ---------- */
@media (max-width: 1023px) {
  .flow__demo.assistant.assistant--inline {
    --a-inline-h: calc(29rem + var(--a-bubble) + var(--space-3) + var(--a-edge));
    max-width: none;
  }
  .flow__demo.assistant--inline .assistant__option { min-height: 46px; padding: 10px 18px; font-size: 14px; }
  .flow__demo.assistant--inline .assistant__options { gap: 8px; }
}

@media (max-width: 767px) {
  .flow__demo.assistant.assistant--inline {
    --a-inline-h: calc(31rem + var(--a-bubble) + var(--space-3) + var(--a-edge));
  }
}
