/*
 * Aria — Charles King Consulting.
 *
 * Three jobs: the rail that keeps Aria beside the page wherever the visitor
 * scrolls, the chat skin itself, and the marks her tools leave on the page.
 * The site's own stylesheet is untouched; everything Aria adds is here, and
 * the colours are the site's tokens from styles.css.
 */

/* ---------- page layout ---------- */
/* Wide screens give Aria a column of her own down the right-hand side. The page
   and its fixed header give up that width rather than sliding under her, so the
   page's own centring still works on what is left. */
@media (min-width: 1200px) {
  :root { --aria-rail-w: clamp(360px, 27vw, 430px); }

  body { padding-right: var(--aria-rail-w); }
  .site-header { right: var(--aria-rail-w); }

  .aria-rail {
    top: 0;
    right: 0;
    bottom: 0;
    width: var(--aria-rail-w);
    padding: 14px;
    border-left: 1px solid var(--line);
  }
}

/* Narrower screens have no column to spare, so she docks along the bottom
   instead. The page is padded by the dock's height so the footer can still be
   reached, and scrolling to something keeps it clear of the dock. It is tall
   enough for the microphone row under the composer to leave the transcript a
   few lines of its own. */
@media (max-width: 1199.98px) {
  :root { --aria-dock-h: clamp(270px, 45vh, 390px); }

  html { scroll-padding-bottom: var(--aria-dock-h); }
  body { padding-bottom: var(--aria-dock-h); }

  .aria-rail {
    right: 0;
    bottom: 0;
    left: 0;
    height: var(--aria-dock-h);
    padding: 8px;
    border-top: 1px solid var(--line);
  }
}

@media (max-width: 600px) {
  :root { --aria-dock-h: clamp(320px, 56vh, 480px); }
}

/* Under the header (100) and the phone menu (101), over the page. */
.aria-rail {
  position: fixed;
  z-index: 90;
  display: grid;
  background: var(--paper-deep);
}

/* ---------- panel shell ---------- */
.aria-chat {
  --aria-panel: #17263a;
  --aria-panel-2: #213247;
  --aria-composer: #1d2d42;
  --aria-line: rgba(255, 253, 248, .14);
  --aria-text: #fffdf8;
  --aria-muted: #bfc7d1;
  --aria-accent: #c85635;
  --aria-accent-2: #a73f24;

  /* How much of the portrait's 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;

  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr) min(38%, calc(var(--aria-dock-h, 300px) - 16px));
  grid-template-rows: minmax(0, 1fr) auto;
  min-height: 0;
  overflow: hidden;
  border: 1px solid var(--aria-line);
  border-radius: 18px;
  background: var(--aria-panel);
  color: var(--aria-text);
  box-shadow: 0 24px 70px rgba(21, 33, 50, .22);
  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;
}

/* Docked, the header and transcript share the text column with the composer
   below them, and the portrait runs the full height beside both. */
.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);
}

.aria-composer-wrap {
  grid-column: 1;
  grid-row: 2;
}

/* In the rail, and on phones, she stands above the conversation instead. */
@media (min-width: 1200px) {
  .aria-chat {
    --aria-portrait-h: min(calc((var(--aria-rail-w) - 28px) * var(--aria-portrait-shown)), 40vh);

    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: var(--aria-portrait-h) minmax(0, 1fr) auto;
  }
}

@media (max-width: 600px) {
  .aria-chat {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: minmax(88px, 25%) minmax(0, 1fr) auto;
  }
}

@media (min-width: 1200px), (max-width: 600px) {
  .aria-conversation { grid-row: 2; }
  .aria-composer-wrap { grid-row: 3; }
}

/* ---------- header ---------- */
/* Fixed height whatever the column does: the description gives way instead of
   wrapping and swelling the header past the height the whole chat has to work
   with. Too narrow to 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: 10px 16px;
  border-bottom: 1px solid var(--aria-line);
}

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

.aria-head strong {
  display: block;
  font-family: var(--serif);
  font-size: 18px;
  font-weight: 400;
  line-height: 1.3;
}

.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: 330px) {
  .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);
  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, 253, 248, .2) transparent;
}

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

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

/* The darker of the two accents: white on the lighter one is under 4.5:1. */
.aria-message.user {
  align-self: flex-end;
  border-bottom-right-radius: 5px;
  background: var(--aria-accent-2);
  color: var(--aria-text);
  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 14px 12px;
  border-top: 1px solid var(--aria-line);
}

.aria-status {
  margin: 8px 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: var(--aria-composer);
}

.aria-composer:focus-within {
  border-color: var(--aria-accent);
  box-shadow: 0 0 0 3px rgba(200, 86, 53, .28);
}

.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 of the panel.
     Zero on both makes the textarea give way and lets 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(191, 199, 209, .75); }
.aria-composer textarea:disabled { opacity: .55; }

.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: var(--aria-accent-2);
  color: var(--aria-text);
}

.aria-send:hover:not(:disabled) { background: #8f3520; }

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

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

/* ---------- microphone ---------- */
/* One talk button and the setting that decides what it does: held, it records
   until it is let go; hands-free, it turns listening on and off. The mode sits
   beside the button rather than above it, and the microphone's own status line
   takes the rest of the row where there is room, so the cluster costs the
   transcript as little height as it can. */
.aria-voice {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px 14px;
  margin-top: 8px;
}

.aria-voice-button {
  flex: 1 1 150px;
  max-width: 250px;
  min-height: 38px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 0 16px;
  border: 1px solid var(--aria-line);
  border-radius: 999px;
  background: transparent;
  color: var(--aria-text);
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  /* Held like a key: a long press must not select the label, open the touch
     callout, or scroll the page instead of recording. */
  user-select: none;
  -webkit-user-select: none;
  -webkit-touch-callout: none;
  touch-action: none;
}

.aria-voice-button svg {
  flex: none;
  width: 16px;
  height: 16px;
  color: var(--aria-accent);
}

.aria-voice-button:hover:not(:disabled) { border-color: var(--aria-accent); }
.aria-voice-button:disabled { opacity: .45; cursor: default; }
.aria-voice-button:focus-visible { outline: 3px solid var(--aria-accent); outline-offset: 3px; }

.aria-voice-button[aria-pressed="true"] {
  border-color: var(--aria-accent);
  background: rgba(200, 86, 53, .2);
}

.aria-voice-button[data-capture-state="recording"] svg { animation: aria-pulse 1.1s ease-in-out infinite; }

/* A setting, not a pair of buttons: two plain radios, stacked to the height of
   the button they configure. */
.aria-mic-modes {
  flex: none;
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
  margin: 0;
  padding: 0;
  border: 0;
}

.aria-mic-modes label {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  color: var(--aria-muted);
  font-size: 12px;
  line-height: 1.35;
  cursor: pointer;
}

.aria-mic-modes input {
  width: 14px;
  height: 14px;
  margin: 0;
  accent-color: var(--aria-accent);
  cursor: pointer;
}

.aria-mic-modes label:has(:checked) { color: var(--aria-text); }
.aria-mic-modes:disabled label { opacity: .45; cursor: default; }
.aria-mic-modes input:focus-visible { outline: 3px solid var(--aria-accent); outline-offset: 2px; }

.aria-mic-state {
  flex: 1 1 200px;
  margin: 0;
  color: var(--aria-muted);
  font-size: 12px;
  line-height: 1.35;
}

.aria-mic-state.error { color: #f0a58a; }

/* ---------- 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;
}

/* In the rail and on phones she takes the top row instead. This has to follow the
   rule above: at equal specificity the later rule wins, and the docked column-2
   placement would otherwise leave her in a zero-width column. */
@media (min-width: 1200px), (max-width: 600px) {
  .aria-portrait {
    grid-column: 1;
    grid-row: 1;
    border-left: 0;
    border-bottom: 1px solid var(--aria-line);
  }
}

/* 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 square is drawn from the box's height, anchored to its bottom edge and
   centred across it, so the whole of her fits whatever shape the box is: the
   hidden top 14% comes off above her hair, a wide box shows the backdrop to
   either side, and a narrow one trims the backdrop rather than 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;
  bottom: 0;
  left: 50%;
  width: auto;
  height: calc(100% / var(--aria-portrait-shown));
  aspect-ratio: 1;
  object-fit: cover;
  object-position: 50% 100%;
  transform: translateX(-50%);
}

.aria-portrait::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(16, 29, 46, 0) 55%, rgba(16, 29, 46, .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(16, 29, 46, .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: #f3b39f;
}

/* ---------- what Aria shows on the page ---------- */
/* A section she brings into view has its heading ringed for a moment, so the
   visitor can tell where the page went and why. */
.aria-highlight {
  outline: 2px solid transparent;
  outline-offset: 10px;
  animation: aria-highlight 3s ease-out;
}

.approach .aria-highlight,
.contact .aria-highlight { --aria-highlight: rgba(255, 253, 248, .85); }

@keyframes aria-highlight {
  0%, 50% { outline-color: var(--aria-highlight, var(--accent)); }
  100% { outline-color: transparent; }
}

/* The card she is talking about is lifted the way hovering lifts it, and ringed;
   the other two step back while it is. */
.service-grid.has-spotlight .service-card:not(.is-spotlit) { opacity: .5; }

.service-card.is-spotlit {
  z-index: 1;
  background: var(--paper);
  box-shadow: var(--shadow), inset 0 0 0 2px var(--accent);
  transform: translateY(-8px);
}

.service-card.is-spotlit::after {
  opacity: .75;
  transform: scale(1.2);
}

.service-spotlight {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 18px;
  margin-top: 22px;
  padding: 14px 18px;
  border: 1px solid var(--line);
  border-left: 3px solid var(--accent);
  background: var(--paper);
  font-size: 14px;
}

.service-spotlight p {
  margin: 0;
  color: var(--ink-soft);
}

.aria-card-close {
  flex: none;
  padding: 7px 14px;
  border: 1px solid var(--ink);
  border-radius: 999px;
  background: transparent;
  color: var(--ink);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .04em;
  cursor: pointer;
}

.aria-card-close:hover,
.aria-card-close:focus-visible {
  background: var(--ink);
  color: var(--white);
}

/* The draft itself is in the form; this is the note beside it that says so and
   that nothing has been sent. */
.inquiry-draft {
  display: grid;
  justify-items: start;
  gap: 14px;
  max-width: 470px;
  margin-top: 34px;
  padding: 18px 20px;
  border: 1px solid rgba(255, 253, 248, .45);
  background: rgba(16, 29, 46, .16);
}

.inquiry-draft p {
  margin: 0;
  color: var(--white);
  font-size: 15px;
  line-height: 1.55;
}

.inquiry-draft .aria-card-close {
  border-color: rgba(255, 253, 248, .7);
  color: var(--white);
}

.inquiry-draft .aria-card-close:hover,
.inquiry-draft .aria-card-close:focus-visible {
  background: var(--white);
  color: var(--accent-dark);
}

/* Notices from the page's socket, centred over the page rather than over her. */
.overlay-zone {
  position: fixed;
  z-index: 95;
  top: 104px;
  left: 50%;
  display: grid;
  gap: 6px;
  width: min(380px, calc(100% - 32px));
  transform: translateX(-50%);
  pointer-events: none;
}

@media (min-width: 1200px) {
  .overlay-zone { left: calc((100% - var(--aria-rail-w)) / 2); }
}

.overlay-zone [data-sdui-notice] {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 9px 12px;
  border: 1px solid var(--line);
  background: rgba(255, 253, 248, .97);
  color: var(--ink);
  font-size: 13px;
  box-shadow: var(--shadow);
  pointer-events: auto;
}

.overlay-zone [data-sdui-part="text"] { flex: 1; }

.overlay-zone [data-sdui-part="dismiss"] {
  padding: 3px 8px;
  border: 1px solid var(--line);
  background: var(--white);
  color: var(--ink);
  font-size: 11px;
  cursor: pointer;
}

.overlay-zone [data-sdui-tone="warn"] { border-color: #d9bc5e; background: #fff8dc; }
.overlay-zone [data-sdui-tone="error"] { border-color: #d49a92; background: #fff0ed; color: #7b322c; }

@media (prefers-reduced-motion: reduce) {
  .aria-message.streaming .aria-message-body::after,
  .aria-voice-button[data-capture-state="recording"] svg { animation: none; }

  /* The ring still shows for as long as it would have; it just does not fade. */
  .aria-highlight {
    animation: none;
    outline-color: var(--aria-highlight, var(--accent));
  }
}
