/* ALY chat surface — the capability row, the calm composer, the conversation's
   rhythm and its motion. Linked after aly-composer.css. Alyssiun tokens only
   (--glass, --hair, --jade, --surface…), so LUX and NEO both come for free. */

/* --- Capability row -------------------------------------------------------
   One horizontal track. Touch swipes and trackpads scroll it natively; a mouse
   wheel is turned sideways in aly-starter-row.js. The fades are masks that
   only appear at an end with more beyond it (has-before / has-after). */
.aly-starters {
  --fade: 44px;
  display: flex; gap: 10px; width: 100%;
  margin-top: 34px; padding: 4px 2px 10px;
  overflow-x: auto; overflow-y: hidden;
  overscroll-behavior-x: contain;
  scroll-snap-type: x proximity; scroll-padding-inline: 2px;
  scrollbar-width: none; -webkit-overflow-scrolling: touch;
  touch-action: pan-x pan-y;
}
.aly-starters::-webkit-scrollbar { display: none; }
.aly-starters.has-after {
  -webkit-mask-image: linear-gradient(to right, #000 calc(100% - var(--fade)), transparent);
  mask-image: linear-gradient(to right, #000 calc(100% - var(--fade)), transparent);
}
.aly-starters.has-before {
  -webkit-mask-image: linear-gradient(to right, transparent, #000 var(--fade));
  mask-image: linear-gradient(to right, transparent, #000 var(--fade));
}
.aly-starters.has-before.has-after {
  -webkit-mask-image: linear-gradient(to right, transparent, #000 var(--fade), #000 calc(100% - var(--fade)), transparent);
  mask-image: linear-gradient(to right, transparent, #000 var(--fade), #000 calc(100% - var(--fade)), transparent);
}

.aly-starter {
  flex: 0 0 196px; scroll-snap-align: start;
  display: flex; flex-direction: column; align-items: flex-start; gap: 4px;
  min-height: 132px; padding: 16px 16px 15px;
  text-align: left; font: inherit; color: var(--text); cursor: pointer;
  border: 1px solid var(--hair); border-radius: 16px;
  background: var(--glass);
  -webkit-backdrop-filter: blur(14px) saturate(1.2); backdrop-filter: blur(14px) saturate(1.2);
  transition: border-color .22s ease, background .22s ease, transform .22s ease;
}
.aly-starter:hover { border-color: var(--hair-2); background: var(--glass-2); transform: translateY(-1px); }
.aly-starter:focus-visible { outline: 0; border-color: var(--text); background: var(--glass-2); }
.aly-starter:active { transform: translateY(0); }
.aly-starter-glyph {
  display: inline-grid; place-items: center; width: 34px; height: 34px; margin-bottom: 14px;
  border-radius: 10px; color: var(--jade);
  background: color-mix(in srgb, var(--jade) 11%, transparent);
}
.aly-starter-glyph svg { display: block; }
.aly-starter-title { font-size: 14px; font-weight: 550; letter-spacing: -0.005em; line-height: 1.3; }
.aly-starter-blurb { font-size: 12.5px; line-height: 1.45; color: var(--muted); }

@media (max-width: 640px) {
  .aly-starters { --fade: 28px; gap: 8px; margin-top: 26px; }
  .aly-starter { flex-basis: 164px; min-height: 124px; padding: 14px 14px 13px; }
}

/* --- Composer (main chat only) -------------------------------------------
   The region's wash turns solid early enough that the disclaimer never sits
   over scrolled-away text. */
.aly-composer-region { background: linear-gradient(to top, var(--void) 80%, transparent); }

   One calm field that starts at a single line and grows as the person types
   (aly-composer.js sets its height). The Project workspace's composer shares
   the row's chrome; these rules are scoped to the main chat's form. */
.aly-composer .dock-composer-actions {
  gap: 6px; padding: 7px 7px 7px 10px; border-radius: 22px;
  border-color: var(--hair-2); background: var(--surface);
  box-shadow: 0 18px 40px -30px rgb(0 0 0 / 0.35);
  transition: border-color .2s ease, box-shadow .2s ease;
}
.aly-composer .dock-composer-actions:focus-within {
  border-color: color-mix(in srgb, var(--jade) 40%, var(--hair-2));
  box-shadow: 0 0 0 4px color-mix(in srgb, var(--jade) 9%, transparent), 0 18px 40px -30px rgb(0 0 0 / 0.35);
}
.aly-composer .dock-composer-actions .dock-input {
  min-height: 24px; padding: 7px 6px; font-size: 15px; line-height: 1.55;
  max-height: calc(8 * 1.55em + 14px);
}
.aly-composer .dock-composer-actions .dock-icon { min-width: 36px; min-height: 36px; border-radius: 12px; color: var(--muted); }
.aly-composer .dock-composer-actions .dock-icon:hover { color: var(--text); }
.aly-composer .dock-send { width: 36px; height: 36px; border-radius: 12px; }

/* --- Conversation ---------------------------------------------------------- */
.aly-messages { gap: 28px; padding-top: 30px; }
.aly-message-role { font-size: 10px; letter-spacing: 0.16em; opacity: 0.6; }
.aly-message.is-user .aly-message-role { display: none; }
.aly-message.is-user .aly-message-body {
  max-width: min(82%, 560px);
  background: color-mix(in srgb, var(--jade) 7%, var(--glass-2));
  border: 1px solid var(--hair);
  border-radius: 20px 20px 6px 20px; padding: 11px 16px;
  font-size: 15px; line-height: 1.6;
}
/* A shared chat labels somebody else's turns by name — keep that label. */
.aly-message.is-user[data-author] .aly-message-role { display: block; }
.aly-message.is-aly .aly-message-body { letter-spacing: -0.003em; }

/* Soft entrance for every new turn. Short, eased, no overshoot. */
.aly-message { animation: aly-rise .34s cubic-bezier(.2, .7, .2, 1) both; }
@keyframes aly-rise { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }

/* Typing: while ALY's reply is still empty, the hairline cursor becomes one
   breathing accent dot — calm presence, not a spinner. */
.aly-message-body > .aly-cursor:only-child {
  width: 8px; height: 8px; border-radius: 50%; vertical-align: middle; margin: 6px 0 0;
  background: var(--jade); animation: aly-breathe 1.6s ease-in-out infinite;
}
@keyframes aly-breathe { 0%, 100% { opacity: .35; transform: scale(.8); } 50% { opacity: 1; transform: scale(1); } }

@media (prefers-reduced-motion: reduce) {
  .aly-message, .aly-message-body > .aly-cursor:only-child { animation: none; }
  .aly-starter { transition: none; }
}

/* ---- ALY's presence -----------------------------------------------------------
   The orb (orb/aly-orb.js) is the face of ALY and carries its own light, lean
   and breath. Around it only a one-shot ring when a reply arrives — transform +
   opacity on a pseudo-element, so it runs on the compositor. */
.aly-sphere-mount.has-sphere { position: relative; isolation: isolate; }
.aly-sphere-mount.has-sphere::after {
  content: ""; position: absolute; inset: 8%; border-radius: 50%; pointer-events: none;
  border: 1px solid var(--aly-accent-line); opacity: 0;
}
.aly-sphere-mount.is-rippling::after { animation: aly-ripple 1.1s cubic-bezier(0.2, 0.7, 0.2, 1) 1; }
@keyframes aly-ripple {
  0% { opacity: 0.75; transform: scale(0.92); }
  100% { opacity: 0; transform: scale(1.55); }
}

/* During a conversation ALY floats on the header's bottom edge: aly-home.css. */
.aly-topbar { position: relative; }

@media (prefers-reduced-motion: reduce) {
  .aly-sphere-mount.is-rippling::after { animation: none; }
}
