/*
 * 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 eyebrow line plus the panel's row gap sit above the chat. */
  --aria-panel-h: calc(var(--aria-portrait-w) * var(--aria-portrait-shown) + 27px);

  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) {
  .talkhead-panel {
    height: var(--aria-panel-h);
  }

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

  /* The portrait is as tall as the chat, so an auto track resolves to exactly
     its width and the transcript keeps whatever is left. The ratio is the square
     with its masked top band taken off, which lands the column back on exactly
     --aria-portrait-w: the chat is --aria-portrait-w * --aria-portrait-shown
     tall, and dividing that by the same fraction gives the width back. This
     holds at every desktop width: a fixed-percentage portrait column would
     squeeze 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 { aspect-ratio: 1 / var(--aria-portrait-shown); }
}

.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%);
  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;
}

.aria-conversation {
  min-width: 0;
  min-height: 0;
  display: grid;
  grid-template-rows: auto minmax(0, 1fr) auto;
}

/* ---------- header ---------- */
.aria-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 12px 16px;
  border-bottom: 1px solid var(--aria-line);
}

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

.aria-head span {
  display: block;
  color: var(--aria-muted);
  font-size: 12px;
  line-height: 1.35;
}

.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 {
  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: --aria-portrait-shown makes it shorter than the
   square, and anchoring the 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: 0;
  width: 100%;
  height: 100%;
  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);
  }

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

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