.portfolio-guide-launcher {
  position: fixed;
  right: max(20px, env(safe-area-inset-right));
  bottom: max(20px, env(safe-area-inset-bottom));
  z-index: 900;
  display: inline-flex;
  align-items: center;
  gap: 9px;
  min-height: 44px;
  padding: 0 16px;
  border: 1px solid color-mix(in srgb, var(--text-primary, #f0ead9) 20%, transparent);
  border-radius: 999px;
  background: var(--text-primary, #f0ead9);
  color: var(--bg, #14120d);
  box-shadow: 0 12px 35px rgb(0 0 0 / 24%);
  font: 600 13px/1 'Helvetica Neue', Helvetica, Arial, sans-serif;
  cursor: pointer;
}

.portfolio-guide-launcher::before {
  content: '';
  flex: none;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: #54c98a;
  box-shadow: 0 0 0 3px color-mix(in srgb, #54c98a 25%, transparent);
}
.portfolio-guide-launcher.is-slow::before {
  background: #e0a23a;
  box-shadow: 0 0 0 3px color-mix(in srgb, #e0a23a 25%, transparent);
}
.portfolio-guide-launcher.is-degraded::before {
  background: #e0554a;
  box-shadow: 0 0 0 3px color-mix(in srgb, #e0554a 25%, transparent);
}

.portfolio-guide-panel {
  position: fixed;
  right: max(20px, env(safe-area-inset-right));
  bottom: calc(max(20px, env(safe-area-inset-bottom)) + 56px);
  z-index: 901;
  display: grid;
  /* head / banner / log / composer -- four rows for four direct children (each
     given an explicit grid-row below, not left to auto-placement: the banner
     is display:none by default and CSS Grid excludes display:none items from
     placement entirely, so when it's hidden only 3 real items exist, and
     auto-placement would fill tracks 1-3 -- shifting log and composer up a row
     -- while a naive fixed track-count-only fix broke the instant the banner
     became visible again, since a 3-track grid was one short for 4 real items:
     banner landed in the log's flexible 1fr track, log got pushed into what
     was the composer's auto track, composer spilled into an implicit row, and
     the log's own row collapsed near-zero with the banner's un-clipped text
     visually spilling into the log's space. Explicit grid-row makes placement
     correct in both states. */
  grid-template-rows: auto auto minmax(0, 1fr) auto;
  width: min(410px, calc(100vw - 32px));
  height: min(650px, calc(100dvh - 110px));
  overflow: hidden;
  border: 1px solid color-mix(in srgb, var(--text-primary, #f0ead9) 18%, transparent);
  border-radius: 18px;
  background: var(--bg-card, var(--bg, #14120d));
  color: var(--text-primary, #f0ead9);
  box-shadow: 0 24px 70px rgb(0 0 0 / 35%);
  font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
}

.portfolio-guide-panel[hidden] { display: none; }

.portfolio-guide-head {
  grid-row: 1;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 15px 16px;
  border-bottom: 1px solid color-mix(in srgb, currentColor 13%, transparent);
}

.portfolio-guide-title { flex: 1; min-width: 0; }
.portfolio-guide-title strong { display: block; font-size: 15px; }
.portfolio-guide-title span { display: block; margin-top: 3px; color: var(--text-secondary, #c9c0a8); font: 400 12px/1.4 'Helvetica Neue', Helvetica, Arial, sans-serif; }

/* Availability is useful context, not the main event. Keep it inset and neutral;
   the small status light carries severity without turning the panel into an
   amber or red error screen. */
.portfolio-guide-banner {
  grid-row: 2;
  display: none;
  gap: 9px;
  align-items: center;
  margin: 10px 12px 0;
  padding: 8px 10px;
  border: 1px solid color-mix(in srgb, currentColor 14%, transparent);
  border-radius: 10px;
  background: color-mix(in srgb, var(--text-primary, #f0ead9) 4%, transparent);
  color: var(--text-secondary, #c9c0a8);
  font-size: 11.5px;
  line-height: 1.4;
  font-weight: 500;
}
.portfolio-guide-banner.is-visible { display: flex; }
.portfolio-guide-banner::before {
  content: '';
  flex: none;
  width: 7px;
  height: 7px;
  border-radius: 50%;
}
.portfolio-guide-banner.is-slow {
  border-color: color-mix(in srgb, #e0a23a 32%, transparent);
}
.portfolio-guide-banner.is-slow::before { background: #e0a23a; box-shadow: 0 0 0 3px color-mix(in srgb, #e0a23a 18%, transparent); }
.portfolio-guide-banner.is-degraded {
  border-color: color-mix(in srgb, #e0554a 32%, transparent);
}
.portfolio-guide-banner.is-degraded::before { background: #e0554a; box-shadow: 0 0 0 3px color-mix(in srgb, #e0554a 18%, transparent); }

.portfolio-guide-icon-btn {
  display: grid;
  width: 36px;
  height: 36px;
  place-items: center;
  border: 1px solid color-mix(in srgb, currentColor 16%, transparent);
  border-radius: 50%;
  background: transparent;
  color: inherit;
  font-size: 19px;
  cursor: pointer;
}

.portfolio-guide-log {
  grid-row: 3;
  overflow-y: auto;
  padding: 16px;
  overscroll-behavior: contain;
}

.portfolio-guide-message { max-width: 88%; margin: 0 0 13px; }
.portfolio-guide-message.is-user { margin-left: auto; }
.portfolio-guide-bubble { padding: 11px 13px; border: 1px solid color-mix(in srgb, currentColor 13%, transparent); border-radius: 14px 14px 14px 4px; background: color-mix(in srgb, var(--text-primary, #f0ead9) 6%, transparent); font-size: 14px; line-height: 1.55; white-space: pre-wrap; }
/* Formatted answers (see renderRich in portfolio-guide.js). pre-wrap would add
   stray gaps around the block elements, so rich bubbles lay out normally. */
.portfolio-guide-bubble.is-rich { white-space: normal; }
.portfolio-guide-bubble.is-rich p { margin: 0; }
.portfolio-guide-bubble.is-rich > * + * { margin-top: 8px; }
.portfolio-guide-bubble.is-rich ul,
.portfolio-guide-bubble.is-rich ol { margin-bottom: 0; padding-left: 18px; }
.portfolio-guide-bubble.is-rich li + li { margin-top: 3px; }
.portfolio-guide-bubble.is-rich li > ul,
.portfolio-guide-bubble.is-rich li > ol { margin-top: 3px; padding-left: 16px; list-style-type: circle; }
.portfolio-guide-bubble.is-rich strong { font-weight: 700; }
.portfolio-guide-bubble.is-rich a { color: inherit; text-decoration: underline; text-underline-offset: 2px; }
.portfolio-guide-bubble.is-rich a:hover { color: var(--accent, currentColor); }
.portfolio-guide-message.is-user .portfolio-guide-bubble { border-radius: 14px 14px 4px 14px; background: var(--text-primary, #f0ead9); color: var(--bg, #14120d); }
.portfolio-guide-typing { display: inline-flex; align-items: center; gap: 4px; padding: 2px; }
.portfolio-guide-typing span { width: 6px; height: 6px; border-radius: 50%; background: currentColor; opacity: .35; }
@media (prefers-reduced-motion: no-preference) {
  .portfolio-guide-typing span { animation: portfolio-guide-bounce 1.1s ease-in-out infinite; }
  .portfolio-guide-typing span:nth-child(2) { animation-delay: .15s; }
  .portfolio-guide-typing span:nth-child(3) { animation-delay: .3s; }
}
@keyframes portfolio-guide-bounce {
  0%, 60%, 100% { opacity: .35; transform: translateY(0); }
  30% { opacity: .9; transform: translateY(-3px); }
}

.portfolio-guide-sources { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 7px; }
.portfolio-guide-sources a { padding: 4px 7px; border: 1px solid color-mix(in srgb, currentColor 16%, transparent); border-radius: 999px; color: inherit; font: 500 11px/1.3 'Helvetica Neue', Helvetica, Arial, sans-serif; text-decoration: none; }

.portfolio-guide-suggestions { display: grid; gap: 7px; margin: 4px 0 14px; }
.portfolio-guide-suggestions button { padding: 9px 11px; border: 1px solid color-mix(in srgb, currentColor 14%, transparent); border-radius: 10px; background: transparent; color: inherit; text-align: left; font: inherit; font-size: 12px; line-height: 1.35; cursor: pointer; }

.portfolio-guide-composer { grid-row: 4; padding: 12px; border-top: 1px solid color-mix(in srgb, currentColor 13%, transparent); }
.portfolio-guide-form { display: flex; align-items: flex-end; gap: 8px; }
.portfolio-guide-input { flex: 1; min-height: 42px; max-height: 110px; resize: none; padding: 10px 11px; border: 1px solid color-mix(in srgb, currentColor 18%, transparent); border-radius: 10px; outline: none; background: color-mix(in srgb, var(--text-primary, #f0ead9) 5%, transparent); color: inherit; font: 14px/1.45 'Helvetica Neue', Helvetica, Arial, sans-serif; }
.portfolio-guide-input:focus { border-color: color-mix(in srgb, currentColor 50%, transparent); }
.portfolio-guide-send { min-width: 62px; height: 42px; border: 0; border-radius: 10px; background: var(--text-primary, #f0ead9); color: var(--bg, #14120d); font: 600 12px/1 'Helvetica Neue', Helvetica, Arial, sans-serif; letter-spacing: .02em; cursor: pointer; }
.portfolio-guide-send:disabled, .portfolio-guide-input:disabled { opacity: .55; cursor: wait; }
.portfolio-guide-notice { margin: 9px 2px 0; color: var(--text-secondary, #c9c0a8); font-size: 10px; line-height: 1.4; }
.portfolio-guide-status { min-height: 15px; margin: 0 2px 7px; color: var(--text-secondary, #c9c0a8); font: 500 10px/1.4 'JetBrains Mono', ui-monospace, monospace; }
.portfolio-guide-turnstile { min-height: 0; margin-bottom: 8px; }

@media (max-width: 600px) {
  .portfolio-guide-launcher { right: 12px; bottom: max(12px, env(safe-area-inset-bottom)); }
  .portfolio-guide-panel { inset: 0; width: 100%; height: 100dvh; max-width: none; border: 0; border-radius: 0; }
  /* The script pins the panel to the visual viewport, but iOS 26 leaves the
     strip behind Safari's floating address bar and the keyboard's accessory
     bar outside it, and reports the new viewport only after the keyboard
     animation settles, so the page showed through around the panel. Rather
     than chase that geometry, the page itself goes blank while the full-screen
     chat is open: the root takes the panel's colour and every other body child
     is made transparent. opacity, not visibility -- descendants that set
     visibility: visible (the mobile menu, reveal states) would reappear. */
  .portfolio-guide-panel { box-shadow: none; }
  html.portfolio-guide-open,
  html.portfolio-guide-open body { background: var(--bg-card, var(--bg, #14120d)); transition: none; }
  /* !important: Astro's scoped nav styles carry an attribute selector and
     outrank this, which left the fixed nav bar showing through. */
  html.portfolio-guide-open body > :not(.portfolio-guide-panel) { opacity: 0 !important; transition: none !important; }
  body.portfolio-guide-open { overflow: hidden; }

  /* Everything below reads noticeably small on a phone at the desktop sizes tuned
     for the 410px floating panel. The input specifically must stay >=16px --
     anything smaller makes iOS Safari zoom the whole page in on focus. */
  .portfolio-guide-title span { font-size: 13px; }
  .portfolio-guide-banner { margin: 9px 12px 0; font-size: 12px; }
  .portfolio-guide-bubble { font-size: 15px; }
  .portfolio-guide-sources a { font-size: 12px; }
  .portfolio-guide-suggestions button { font-size: 13.5px; }
  .portfolio-guide-input { font-size: 16px; }
  .portfolio-guide-send { font-size: 13px; }
  .portfolio-guide-notice { font-size: 11px; }
  .portfolio-guide-status { font-size: 11px; }
}

@media (prefers-reduced-motion: no-preference) {
  .portfolio-guide-launcher { transition: transform .18s ease, box-shadow .18s ease, translate .2s ease; }
  .portfolio-guide-launcher:hover { transform: translateY(-2px); box-shadow: 0 15px 40px rgb(0 0 0 / 30%); }
  .portfolio-guide-launcher::before { animation: portfolio-guide-blink 2.6s ease-in-out infinite; }
  .portfolio-guide-launcher.is-degraded::before { animation-duration: 1.1s; }
}
/* The floating panel rises out of the launcher instead of popping in. Not on
   phones: there the panel is full screen and the page behind it is blanked,
   so a fade would show the site through it. Closing stays instant. */
@media (min-width: 601px) and (prefers-reduced-motion: no-preference) {
  .portfolio-guide-panel:not([hidden]) {
    transform-origin: 100% 100%;
    animation: portfolio-guide-open 240ms cubic-bezier(0.22, 1, 0.36, 1);
  }
}
@keyframes portfolio-guide-open {
  from { opacity: 0; transform: translateY(10px) scale(0.97); }
}
@keyframes portfolio-guide-blink {
  0%, 100% { opacity: 1; }
  50% { opacity: .4; }
}
