/*
 * Aria panel — Sands Dynamics.
 *
 * Two jobs: the hero layout that keeps the panel inside one viewport next to
 * the copy column, and the chat skin itself. Loaded only by index.html.
 */

/* ---------- hero layout ---------- */
.stage-grid-talk {
  /* Vertical room the hero has between the header and the footer. */
  --aria-avail-h: calc(100dvh - 74px - 36px - 2 * clamp(28px, 4.2vh, 54px));

  /* Ditto renders a 1:1 frame now, so the square is what sizes this hero: it
     sets the portrait column's width and, through that, the panel's height.
     The source is a close head-and-shoulders crop with margin on all four
     sides, so it is shown whole — squeezing it into a taller box would cut
     into her hair. Sizing is led by width rather than by the viewport because
     a square stretched to the height the old 624x912 frame used would be half
     again as wide as that frame was and would starve the copy column. */
  --aria-portrait-w: min(clamp(200px, 24vw, 500px), calc(var(--aria-avail-h) - 27px));

  /* How much of that square is actually shown. The top band is masked off — see
     the .aria-portrait rule below for why it exists and why it is hidden here
     rather than cut out of the files. */
  --aria-portrait-shown: .86;

  /* The chat's own parts do not compress: the header, the composer, and enough
     transcript to read an answer in. This is the floor under them. Browser zoom
     takes both axes away at once, and a window that is only 768px tall is
     already past the point where the square can set a workable height — without
     this the chat ends up shorter than its own header and composer, and the
     transcript is pushed out of the box and clipped. Below the floor the
     portrait keeps its width and stops driving the height. */
  --aria-chat-min-h: 290px;
  --aria-chat-h: max(calc(var(--aria-portrait-w) * var(--aria-portrait-shown)), var(--aria-chat-min-h));

  align-items: center;
  gap: clamp(28px, 4vw, 64px);
}

/* Wide desktops only: hand the transcript a fixed width beside the square so
   the copy column keeps everything left over. Below 1360px the stage grid's own
   columns split the room instead — there is not enough of it to give the
   transcript a fixed share without starving the copy. */
@media (min-width: 1360px) {
  .stage-grid-talk {
    /* Wide enough that the composer placeholder stays on one line. */
    --aria-transcript-w: clamp(344px, 24.5vw, 396px);

    grid-template-columns: minmax(0, 1fr) calc(var(--aria-portrait-w) + var(--aria-transcript-w));
  }

  /* The panel still takes real width here, so the headline is set a size down
     from the other heroes to keep the copy column inside one viewport. */
  .stage-grid-talk h1 { font-size: clamp(2.1rem, 3.3vw, 3.6rem); }
}

/* Between the mobile stack and the wide-desktop breakpoint the panel's width
   comes from the stage grid's generic columns, and there is not much of it: 551px
   at 1280, 437px at 1024. A portrait sized off the viewport claims 304px of that
   and leaves the transcript too narrow to hold its own header, so it takes a
   smaller share of the viewport here. Sizing it off the panel instead is not
   available — the panel's height is what gives the portrait its width, so the
   two cannot both follow each other. */
@media (min-width: 901px) and (max-width: 1359.98px) {
  .stage-grid-talk {
    --aria-portrait-w: min(clamp(190px, 20vw, 280px), calc(var(--aria-avail-h) - 27px));
  }
}

.talkhead-panel {
  display: grid;
  grid-template-rows: auto minmax(0, 1fr);
  gap: 10px;
  min-height: 0;
}

@media (min-width: 901px) {
  /* The chat is the sized thing and the eyebrow sits above it, so a line that
     wraps on a narrower window lengthens the panel rather than stealing the
     room from the transcript. */
  .stage-grid-talk .aria-chat { height: var(--aria-chat-h); }

  .stage-grid-talk .stage-copy {
    max-height: 100%;
  }

  /* The portrait column is the square's width and the transcript keeps whatever
     is left. That width used to be read back out of the chat's height through
     the square's ratio, which gave the same number — but only while the height
     is the square's to set. Once the floor takes over it is not, and the width
     has to be stated outright, or the frame would widen with the box and starve
     the transcript. The extra height goes to the backdrop band above her hair,
     which is the one direction the frame can give in. Handing the column a
     percentage instead is the thing to avoid: it squeezes the frame to a
     vertical sliver through her face on narrow screens. */
  .stage-grid-talk .aria-chat { grid-template-columns: minmax(0, 1fr) auto; }
  .stage-grid-talk .aria-portrait { width: var(--aria-portrait-w); }
}

/* Once the visitor starts talking, the pitch has done its job. The copy column
   steps aside, the panel takes the whole stage, and Aria is as large as the
   viewport allows with the transcript beside her and the composer running the
   full width underneath both. Nothing has to choose between side-by-side and
   stacked any more: there is only ever one column on the stage. */
@media (min-width: 901px) {
  .stage-grid-talk.aria-focus {
    /* The panel is the container, so its width is knowable here, and the
       portrait is sized from whichever runs out first — the width left after
       the transcript keeps a readable column, or the height on offer. */
    --aria-focus-panel-w: min(calc(100vw - 44px), var(--content, 1440px));
    --aria-focus-transcript-w: 400px;
    --aria-focus-composer-h: 110px;
    --aria-focus-portrait-w: max(
      min(
        calc(var(--aria-focus-panel-w) - var(--aria-focus-transcript-w)),
        calc((var(--aria-avail-h) - 27px - var(--aria-focus-composer-h)) / var(--aria-portrait-shown))
      ),
      160px
    );

    /* The same floor the hero has, less the composer that sits below this row:
       whatever height is left, the header and a readable transcript come first
       and the portrait takes what remains. */
    --aria-focus-row-h: max(
      calc(var(--aria-focus-portrait-w) * var(--aria-portrait-shown)),
      calc(var(--aria-chat-min-h) - var(--aria-focus-composer-h))
    );

    grid-template-columns: minmax(0, 1fr);
  }

  .stage-grid-talk.aria-focus .stage-copy { display: none; }

  /* The panel is no longer sized off the hero: it is as tall as the portrait it
     now contains. That portrait is measured from the room between header and
     footer, so the panel lands inside the viewport on its own — capping it here
     as well would only cut the composer off the bottom of the chat on the
     screens where the floors above take over. */
  .stage-grid-talk.aria-focus .talkhead-panel {
    height: auto;
  }

  .stage-grid-talk.aria-focus .aria-chat {
    grid-template-columns: minmax(0, 1fr) var(--aria-focus-portrait-w);
    grid-template-rows: var(--aria-focus-row-h) auto;
  }

  .stage-grid-talk.aria-focus .aria-chat { height: auto; }
  .stage-grid-talk.aria-focus .aria-portrait { grid-row: 1; width: auto; }
  .stage-grid-talk.aria-focus .aria-composer-wrap { grid-column: 1 / -1; }
}

.capability-strip {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 9px;
  margin-top: clamp(16px, 2.4vh, 26px);
}

.capability-strip article {
  padding: 11px 13px;
  border: 1px solid var(--line-light, rgba(255, 255, 255, .12));
  border-radius: 12px;
  background: rgba(15, 18, 25, .42);
}

.capability-strip strong {
  display: block;
  color: #fff;
  font-size: .84rem;
}

.capability-strip span {
  display: block;
  margin-top: 3px;
  color: #adb2bc;
  font-size: .73rem;
  line-height: 1.35;
}

.talkhead-panel .eyebrow { margin: 0; }

.stage-grid-talk .ownership-strip { margin-top: 11px; }
.stage-grid-talk .actions { margin-top: clamp(16px, 2.4vh, 26px); }
.stage-grid-talk .lede { margin-top: 18px; }

/* ---------- panel shell ---------- */
.aria-chat {
  --aria-bg: #0f1219;
  --aria-panel: #171b24;
  --aria-panel-2: #1d222d;
  --aria-line: rgba(255, 255, 255, .12);
  --aria-text: #fafaf6;
  --aria-muted: #b9bdc5;
  --aria-accent: #e8b830;
  --aria-accent-2: #b98513;

  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(260px, 36%);
  grid-template-rows: minmax(0, 1fr) auto;
  min-height: 0;
  overflow: hidden;
  border: 1px solid var(--aria-line);
  border-radius: 22px;
  background: var(--aria-panel);
  color: var(--aria-text);
  box-shadow: 0 28px 80px rgba(15, 18, 25, .38);
  font-size: 14px;
}

.aria-chat [hidden] { display: none !important; }

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

/* Header and transcript. The composer left this column when it grew to the
   panel's full width, so the placement below is what puts the three regions
   back together: text column and portrait share row 1, composer owns row 2. */
.aria-conversation {
  grid-column: 1;
  grid-row: 1;
  /* The header's own column, which is what decides whether its description
     fits — the viewport says nothing useful about it. */
  container-type: inline-size;
  min-width: 0;
  min-height: 0;
  display: grid;
  grid-template-rows: auto minmax(0, 1fr);
}

/* Until the visitor starts a conversation the portrait still runs the panel's
   full height and the composer stays over the transcript, exactly as before. */
.aria-composer-wrap {
  grid-column: 1;
  grid-row: 2;
}

/* ---------- header ---------- */
/* Fixed height whatever the column does: the description gives way instead of
   wrapping to three lines and swelling the header past the height the whole
   chat has to work with. Narrow enough that it cannot be read whole and it is
   dropped rather than ellipsised — "AI guid…" beside her name says nothing. */
.aria-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  min-width: 0;
  padding: 12px 16px;
  border-bottom: 1px solid var(--aria-line);
}

.aria-head > div { min-width: 0; }

.aria-head strong {
  display: block;
  font-size: 15px;
  letter-spacing: .01em;
}

.aria-head span {
  display: block;
  overflow: hidden;
  color: var(--aria-muted);
  font-size: 12px;
  line-height: 1.35;
  white-space: nowrap;
  text-overflow: ellipsis;
}

@container (max-width: 372px) {
  .aria-head span { display: none; }
}

.aria-ghost {
  flex: none;
  padding: 6px 11px;
  border: 1px solid var(--aria-line);
  border-radius: 999px;
  background: transparent;
  color: var(--aria-muted);
  font: inherit;
  font-size: 12px;
  cursor: pointer;
}

.aria-ghost:hover:not(:disabled) {
  border-color: var(--aria-accent-2);
  color: var(--aria-text);
}

.aria-ghost:disabled { opacity: .45; cursor: default; }

/* ---------- transcript ---------- */
.aria-transcript {
  min-height: 0;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 9px;
  padding: 14px 16px;
  scrollbar-width: thin;
  scrollbar-color: rgba(255, 255, 255, .18) transparent;
}

.aria-transcript::-webkit-scrollbar { width: 6px; }
.aria-transcript::-webkit-scrollbar-thumb {
  border-radius: 999px;
  background: rgba(255, 255, 255, .18);
}

.aria-message {
  max-width: 88%;
  padding: 9px 13px;
  border-radius: 15px;
  line-height: 1.5;
}

.aria-message-body { white-space: pre-wrap; }

.aria-message.assistant {
  align-self: flex-start;
  border: 1px solid var(--aria-line);
  border-bottom-left-radius: 5px;
  background: var(--aria-panel-2);
}

.aria-message.user {
  align-self: flex-end;
  border-bottom-right-radius: 5px;
  background: linear-gradient(135deg, var(--aria-accent), var(--aria-accent-2));
  color: #0f1219;
  font-weight: 500;
}

.aria-message.streaming .aria-message-body::after {
  content: '';
  display: inline-block;
  width: 7px;
  height: 7px;
  margin-left: 4px;
  border-radius: 50%;
  background: var(--aria-accent);
  animation: aria-pulse 1.1s ease-in-out infinite;
}

@keyframes aria-pulse {
  0%, 100% { opacity: .25; }
  50% { opacity: 1; }
}

/* ---------- composer ---------- */
.aria-composer-wrap {
  padding: 0 16px 14px;
  border-top: 1px solid var(--aria-line);
}

.aria-status {
  margin: 9px 2px;
  color: var(--aria-muted);
  font-size: 12px;
  line-height: 1.35;
  min-height: 1.35em;
}

.aria-status.error { color: #f0a58a; }

.aria-composer {
  min-height: 52px;
  display: flex;
  align-items: flex-end;
  gap: 8px;
  padding: 7px 7px 7px 14px;
  border: 1px solid var(--aria-line);
  border-radius: 16px;
  background: #1a1d25;
}

.aria-composer:focus-within {
  border-color: var(--aria-accent);
  box-shadow: 0 0 0 3px rgba(232, 184, 48, .18);
}

.aria-composer textarea {
  flex: 1;
  /* flex: 1 is flex-basis: 0%, and a percentage basis against an indefinite
     width falls back to the item's content size while the browser is working
     out how narrow this row can go. A bare textarea's content size is its
     default twenty columns, so without these the composer reports a minimum of
     about 320px, refuses to shrink past it, and pushes Send out under the
     portrait on a narrow panel. Zero on both makes the textarea give way and
     lets the mic and Send set the real floor. */
  width: 0;
  min-width: 0;
  max-height: 110px;
  padding: 8px 0;
  border: 0;
  background: transparent;
  color: var(--aria-text);
  font: inherit;
  line-height: 1.45;
  resize: none;
  outline: none;
}

.aria-composer textarea::placeholder { color: rgba(185, 189, 197, .7); }
.aria-composer textarea:disabled { opacity: .55; }

.aria-mic {
  flex: none;
  width: 38px;
  height: 38px;
  display: grid;
  place-items: center;
  border: 1px solid var(--aria-line);
  border-radius: 50%;
  background: transparent;
  color: var(--aria-accent);
  cursor: pointer;
}

.aria-mic svg { width: 17px; height: 17px; }

.aria-mic:hover:not(:disabled) { border-color: var(--aria-accent); }

.aria-mic.active {
  border-color: var(--aria-accent);
  background: linear-gradient(135deg, var(--aria-accent), var(--aria-accent-2));
  color: #0f1219;
}

.aria-mic:disabled { opacity: .4; cursor: default; }

/* Aria spends the walkthrough asking the visitor to press this button, so it
   flashes for as long as she is saying it. The walkthrough's own ring is too
   quiet on a 38px circle, so this one fills the button gold, flips the icon
   dark and swells as well as throwing the halo. It stops when she finishes, and
   stops early if they press it while she is still talking, since .active is the
   on state. */
.aria-mic.prompting:not(.active) {
  border-color: var(--aria-accent);
  animation: aria-mic-flash 1s ease-in-out infinite;
}

@keyframes aria-mic-flash {
  0%, 100% {
    background-color: rgba(232, 184, 48, 0);
    color: var(--aria-accent);
    box-shadow: 0 0 0 0 rgba(232, 184, 48, .9);
    transform: scale(1);
  }
  50% {
    background-color: rgba(232, 184, 48, 1);
    color: #0f1219;
    box-shadow: 0 0 0 16px rgba(232, 184, 48, 0);
    transform: scale(1.12);
  }
}

.aria-send,
.aria-stop {
  flex: none;
  height: 38px;
  padding: 0 17px;
  border: 0;
  border-radius: 999px;
  font: inherit;
  font-weight: 600;
  cursor: pointer;
}

.aria-send {
  background: linear-gradient(135deg, var(--aria-accent), var(--aria-accent-2));
  color: #0f1219;
}

.aria-send:disabled {
  opacity: .4;
  cursor: default;
}

.aria-stop {
  border: 1px solid var(--aria-line);
  background: transparent;
  color: var(--aria-text);
}

/* ---------- portrait ---------- */
.aria-portrait {
  grid-column: 2;
  grid-row: 1 / -1;
  position: relative;
  min-width: 0;
  overflow: hidden;
  background: #1c1920;
  border-left: 1px solid var(--aria-line);
  isolation: isolate;
}

/* The square carries a band of empty backdrop above her hair: the region Ditto
   animates is 2.0x her face box, and the source frame has to contain the whole
   of it. That band is the renderer's working room, not composition. Taking it
   out of the files is not an option — the still, the idle loop and the copy of
   the same picture the render box animates from all have to stay identical, or
   her hairline jumps the moment she starts speaking. So the files are left
   exactly as they are and the band is masked off here, at display time.

   The mask is the box itself: the box is shorter than the square the media
   draws, and anchoring that media to the bottom edge means the whole of the
   hidden part comes off the top. Nothing is scaled, so she is the same size on
   screen as before and the bottom of the frame — her neckline and shoulders —
   stays fully visible. Measured on the source, her hair's topmost pixel is row
   218 of 1224, so hiding the top 14% clears the ceiling and still leaves a few
   rows of headroom above her.

   The still, the idle loop and the spoken video share this rule, so all three
   sit identically and nothing shifts when she begins to talk. */
.aria-portrait img,
.aria-portrait video {
  position: absolute;
  inset: auto 0 0 0;
  width: 100%;
  aspect-ratio: 1;
  object-fit: cover;
  object-position: 50% 100%;
}

.aria-portrait::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(15, 18, 25, 0) 55%, rgba(15, 18, 25, .72) 100%);
  pointer-events: none;
}

.aria-portrait-state {
  position: absolute;
  left: 12px;
  bottom: 12px;
  z-index: 1;
  padding: 4px 10px;
  border: 1px solid var(--aria-line);
  border-radius: 999px;
  background: rgba(15, 18, 25, .62);
  color: var(--aria-muted);
  font-size: 11px;
  letter-spacing: .04em;
  text-transform: uppercase;
}

.aria-portrait.speaking .aria-portrait-state,
.aria-portrait.processing .aria-portrait-state,
.aria-portrait.hearing .aria-portrait-state {
  border-color: var(--aria-accent);
  color: var(--aria-accent);
}

/* ---------- voice walkthrough ---------- */
.aria-onboarding {
  position: absolute;
  inset: 0;
  z-index: 2;
  display: grid;
  align-content: center;
  justify-items: center;
  gap: 11px;
  padding: clamp(18px, 3vw, 34px);
  text-align: center;
  background: rgba(15, 18, 25, .9);
  backdrop-filter: blur(6px);
}

.aria-onboarding h3 {
  margin: 0;
  font-size: clamp(17px, 1.5vw, 21px);
  line-height: 1.25;
}

.aria-onboarding p {
  margin: 0;
  max-width: 42ch;
  color: var(--aria-muted);
  line-height: 1.5;
}

.aria-onboarding-example {
  padding: 7px 13px;
  border: 1px solid var(--aria-line);
  border-radius: 999px;
  background: rgba(29, 34, 45, .8);
  color: var(--aria-text);
  font-style: italic;
}

.aria-onboarding-start {
  margin-top: 4px;
  padding: 11px 25px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, var(--aria-accent), var(--aria-accent-2));
  color: #0f1219;
  font: inherit;
  font-weight: 700;
  cursor: pointer;
  animation: aria-cta 1.4s ease-in-out infinite;
}

/* This is the one thing on the walkthrough overlay the visitor is meant to
   press, so it swells and throws a halo rather than just glowing faintly. It is
   already gold, so the punch has to come from size and brightness instead of the
   fill change the microphone button uses. */
@keyframes aria-cta {
  0%, 100% {
    box-shadow: 0 0 0 0 rgba(232, 184, 48, .9);
    transform: scale(1);
    filter: brightness(1);
  }
  50% {
    box-shadow: 0 0 0 20px rgba(232, 184, 48, 0);
    transform: scale(1.06);
    filter: brightness(1.18);
  }
}

.aria-onboarding-skip {
  border: 0;
  background: transparent;
  color: var(--aria-muted);
  font: inherit;
  font-size: 12px;
  text-decoration: underline;
  cursor: pointer;
}

@media (prefers-reduced-motion: reduce) {
  .aria-onboarding-start,
  .aria-mic.prompting:not(.active),
  .aria-message.streaming .aria-message-body::after {
    animation: none;
  }
}

/* ---------- narrow screens ---------- */
@media (max-width: 900px) {
  .aria-chat {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: minmax(180px, 30vh) minmax(0, 1fr) auto;
  }

  .aria-portrait {
    grid-column: 1;
    grid-row: 1;
    border-left: 0;
    border-bottom: 1px solid var(--aria-line);
  }

  /* Stacked, the band runs four times wider than it is tall, and a square drawn
     to that width stands four times taller than the band — bottom-anchored, all
     that is left of her is a chin. So here the square is drawn from the band's
     height instead and centred across it, with the same top strip masked off:
     the whole of her fits, and the backdrop the box already paints carries the
     width to either side. */
  .aria-portrait img,
  .aria-portrait video {
    left: 50%;
    right: auto;
    width: auto;
    height: calc(100% / var(--aria-portrait-shown, .86));
    transform: translateX(-50%);
  }

  .aria-conversation { grid-row: 2; }
  .aria-composer-wrap { grid-row: 3; }

  .capability-strip { grid-template-columns: minmax(0, 1fr); }
}
