/* ═══════════════════════════════════════════════════════════════════════
   Product showcase - app mockup + "Everything connected" bento
   ═══════════════════════════════════════════════════════════════════════
   Same material language as the hero: obsidian ground, hairline borders,
   light pooling rather than boxes stacked on boxes. The mockup is the one
   place on the page where the product speaks for itself, so it gets real
   numbers and real hierarchy instead of grey placeholder blocks.
   ═════════════════════════════════════════════════════════════════════ */

/* ── App window ────────────────────────────────────────────────────── */

.app-shell {
  --app-bg:    #0B0A12;
  --app-panel: #121020;
  --app-line:  rgba(238, 237, 255, .07);
  --app-ice:   #EEEDFF;
  --app-mute:  rgba(238, 237, 255, .44);
  --app-lilac: #A78BFA;

  display: flex;
  flex-direction: column;
  border-radius: 14px 14px 0 0;
  background: var(--app-bg);
  overflow: hidden;
  font-size: 11px;
  line-height: 1.45;
  text-align: left;
  color: var(--app-ice);
}

/* Top chrome */
.app-top {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 11px 14px;
  border-bottom: 1px solid var(--app-line);
  background: rgba(238, 237, 255, .015);
}

.app-brand {
  display: flex;
  align-items: center;
  gap: 7px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: -.01em;
  flex-shrink: 0;
}

.app-brand-mark {
  width: 17px;
  height: 17px;
  border-radius: 5px;
  background: linear-gradient(135deg, #7C3AED, #4F46E5);
  display: flex;
  align-items: center;
  justify-content: center;
  color: #fff;
}

.app-search {
  flex: 1;
  max-width: 260px;
  display: flex;
  align-items: center;
  gap: 7px;
  height: 25px;
  padding: 0 10px;
  border: 1px solid var(--app-line);
  border-radius: 7px;
  background: rgba(238, 237, 255, .03);
  color: rgba(238, 237, 255, .3);
  font-size: 10px;
}

.app-top-right {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 12px;
  color: var(--app-mute);
}

.app-user { display: flex; align-items: center; gap: 8px; }

.app-avatar {
  width: 24px;
  height: 24px;
  border-radius: 50%;
  background: linear-gradient(135deg, #A78BFA, #4F46E5);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 9px;
  font-weight: 700;
  color: #fff;
}

.app-user-name { font-size: 10px; font-weight: 600; line-height: 1.25; }
.app-user-role { font-size: 9px; color: var(--app-mute); line-height: 1.25; }

/* Body: rail + main */
.app-body { display: flex; min-height: 0; }

.app-rail {
  width: 42px;
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 5px;
  padding: 12px 0;
  border-right: 1px solid var(--app-line);
  background: rgba(238, 237, 255, .012);
}

.app-rail-btn {
  width: 26px;
  height: 26px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 7px;
  color: rgba(238, 237, 255, .3);
}

.app-rail-btn.is-active {
  background: rgba(124, 58, 237, .22);
  color: var(--app-lilac);
  box-shadow: inset 0 0 0 1px rgba(167, 139, 250, .28);
}

.app-rail-btn svg { width: 13px; height: 13px; }

.app-main { flex: 1; min-width: 0; padding: 16px 18px 20px; }

.app-crumb {
  margin: 0 0 8px;
  font-size: 9px;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: rgba(238, 237, 255, .3);
}

.app-greet {
  margin: 0 0 3px;
  font-size: 15px;
  font-weight: 600;
  letter-spacing: -.02em;
}

.app-sub { margin: 0 0 16px; font-size: 10.5px; color: var(--app-mute); }

/* KPI row */
.app-kpis {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 10px;
  margin-bottom: 14px;
}

.app-kpi {
  padding: 11px 12px;
  border: 1px solid var(--app-line);
  border-radius: 10px;
  background: var(--app-panel);
}

.app-kpi-top {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 9px;
}

.app-kpi-ico {
  width: 22px;
  height: 22px;
  border-radius: 6px;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}

.app-kpi-ico svg { width: 11px; height: 11px; }
.app-kpi-ico.v { background: rgba(167, 139, 250, .16); color: #C4B5FD; }
.app-kpi-ico.b { background: rgba(96, 165, 250, .16); color: #93C5FD; }
.app-kpi-ico.g { background: rgba(52, 211, 153, .16); color: #6EE7B7; }
.app-kpi-ico.a { background: rgba(251, 191, 36, .16); color: #FCD34D; }

.app-kpi-lbl { font-size: 9.5px; color: var(--app-mute); }
.app-kpi-val { font-size: 15px; font-weight: 700; letter-spacing: -.02em; }
.app-kpi-delta { margin-top: 5px; font-size: 9px; color: #6EE7B7; }
.app-kpi-delta span { color: rgba(238, 237, 255, .28); }

/* Chart + orders */
.app-grid {
  display: grid;
  grid-template-columns: 1.55fr 1fr;
  gap: 10px;
}

.app-panel {
  border: 1px solid var(--app-line);
  border-radius: 10px;
  background: var(--app-panel);
  padding: 12px;
}

.app-panel-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 10px;
}

.app-panel-title { font-size: 10.5px; font-weight: 600; }

.app-chip {
  font-size: 9px;
  padding: 2px 8px;
  border: 1px solid var(--app-line);
  border-radius: 100px;
  color: var(--app-mute);
}

.app-link { font-size: 9.5px; color: var(--app-lilac); text-decoration: none; }

.app-chart { width: 100%; height: 108px; display: block; }

.app-chart-axis {
  display: flex;
  justify-content: space-between;
  margin-top: 6px;
  font-size: 8.5px;
  color: rgba(238, 237, 255, .22);
}

/* Orders list */
.app-order {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 7px 0;
  border-bottom: 1px solid var(--app-line);
}

.app-order:last-child { border-bottom: none; }
.app-order-id { font-size: 9.5px; font-weight: 600; }
.app-order-item { font-size: 9px; color: var(--app-mute); }
.app-order-amt { margin-left: auto; font-size: 10px; font-weight: 600; }

.app-dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  flex-shrink: 0;
  background: #FBBF24;
}

.app-dot.ok { background: #34D399; }

@media (max-width: 900px) {
  .app-kpis { grid-template-columns: repeat(2, 1fr); }
  .app-grid { grid-template-columns: 1fr; }
  .app-search { display: none; }
}

/* ═══════════════════════════════════════════════════════════════════════
   "Everything connected" - tabs + bento
   ═════════════════════════════════════════════════════════════════════ */

.sync-tabs {
  display: flex;
  justify-content: center;
  flex-wrap: wrap;
  gap: 4px;
  margin: 36px 0 30px;
  padding-bottom: 2px;
}

.sync-tab {
  position: relative;
  padding: 9px 16px;
  border: none;
  background: none;
  font-family: inherit;
  font-size: .8125rem;
  font-weight: 500;
  letter-spacing: -.005em;
  color: rgba(238, 237, 255, .42);
  cursor: pointer;
  transition: color .25s ease;
}

.sync-tab:hover { color: rgba(238, 237, 255, .76); }
.sync-tab.is-active { color: var(--ob-ice, #EEEDFF); }

/* The active marker is the hero's hairline again, not a filled pill. */
.sync-tab.is-active::after {
  content: '';
  position: absolute;
  left: 16px;
  right: 16px;
  bottom: -2px;
  height: 1px;
  background: linear-gradient(90deg, transparent, #A78BFA, transparent);
}

.sync-tab:focus-visible {
  outline: 2px solid #A78BFA;
  outline-offset: 2px;
  border-radius: 6px;
}

.sync-panel { display: none; }
.sync-panel.is-active { display: block; animation: sync-in .45s cubic-bezier(.16,1,.3,1) both; }

@keyframes sync-in {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: none; }
}

.sync-bento {
  display: grid;
  grid-template-columns: 1.35fr 1fr 1fr;
  gap: 14px;
}

.sb-card {
  position: relative;
  padding: 20px;
  border: 1px solid rgba(238, 237, 255, .08);
  border-radius: 16px;
  background: linear-gradient(180deg, rgba(238, 237, 255, .035), rgba(238, 237, 255, .012));
  transition: border-color .35s ease, background .35s ease;
}

.sb-card:hover {
  border-color: rgba(167, 139, 250, .26);
  background: linear-gradient(180deg, rgba(238, 237, 255, .06), rgba(238, 237, 255, .02));
}

/* The lead card spans two rows so the grid reads as a composition rather
   than a row of equal boxes. */
.sb-lead { grid-row: span 2; }

.sb-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 4px;
}

.sb-title {
  margin: 0;
  font-size: 1.0625rem;
  font-weight: 600;
  letter-spacing: -.015em;
  color: #EEEDFF;
}

.sb-desc {
  margin: 0 0 18px;
  font-size: .875rem;
  line-height: 1.6;
  color: rgba(238, 237, 255, .5);
}

.sb-ico {
  width: 34px;
  height: 34px;
  flex-shrink: 0;
  border-radius: 9px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px solid rgba(167, 139, 250, .2);
  background: rgba(167, 139, 250, .08);
  color: #A78BFA;
}

.sb-ico svg { width: 16px; height: 16px; }

/* Stat pairs */
.sb-stats {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 12px;
  margin-top: auto;
}

.sb-stat-lbl {
  font-size: .6875rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: rgba(238, 237, 255, .32);
  margin-bottom: 4px;
}

.sb-stat-val {
  font-size: 1.25rem;
  font-weight: 600;
  letter-spacing: -.02em;
  color: #EEEDFF;
}

/* Mini table inside the lead card */
.sb-table { margin-top: 16px; }

.sb-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 9px 0;
  border-bottom: 1px solid rgba(238, 237, 255, .06);
  font-size: .8125rem;
}

.sb-row:last-child { border-bottom: none; }
.sb-rank { width: 16px; color: rgba(238, 237, 255, .28); font-size: .75rem; }
.sb-name { color: rgba(238, 237, 255, .82); }
.sb-qty { margin-left: auto; color: rgba(238, 237, 255, .4); font-size: .75rem; }
.sb-amt { width: 76px; text-align: right; font-weight: 600; color: #EEEDFF; }

.sb-tiles {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 10px;
  margin-bottom: 4px;
}

.sb-tile {
  padding: 13px 14px;
  border: 1px solid rgba(238, 237, 255, .06);
  border-radius: 11px;
  background: rgba(238, 237, 255, .02);
}

.sb-tile-val { font-size: 1.125rem; font-weight: 600; letter-spacing: -.02em; }
.sb-tile-lbl { font-size: .6875rem; color: rgba(238, 237, 255, .38); margin-top: 2px; }
.sb-tile-val.warn { color: #FCD34D; }

@media (max-width: 1000px) {
  .sync-bento { grid-template-columns: repeat(2, 1fr); }
  .sb-lead { grid-row: auto; grid-column: span 2; }
}

@media (max-width: 640px) {
  .sync-bento { grid-template-columns: 1fr; }
  .sb-lead { grid-column: auto; }
  .sync-tabs { justify-content: flex-start; overflow-x: auto; flex-wrap: nowrap; }
  .sync-tab { white-space: nowrap; }
}

@media (prefers-reduced-motion: reduce) {
  .sync-panel.is-active { animation: none; }
  .sb-card, .sync-tab { transition: none; }
}

/* ═══════════════════════════════════════════════════════════════════════
   Hero mockup in 3D
   ═══════════════════════════════════════════════════════════════════════
   The window sits in perspective rather than flat-on, so it reads as an
   object in the same space as the light behind it instead of a screenshot
   pasted onto the page. It also drifts a few degrees toward the pointer,
   which makes the surface feel physical without becoming a toy.
   ═════════════════════════════════════════════════════════════════════ */

.hero-product {
  perspective: 2000px;
  perspective-origin: 50% 42%;
}

.hero-stage {
  position: relative;
  transform-style: preserve-3d;
  /* Set by script on pointer move; these are the resting angles. */
  --rx: 5deg;
  --ry: -13deg;
  transform: rotateX(var(--rx)) rotateY(var(--ry)) rotateZ(.6deg);
  transition: transform .5s cubic-bezier(.16, 1, .3, 1);
  will-change: transform;
}

/* Violet bloom behind the glass, sitting further back in Z so the tilt
   separates it from the window itself. */
.hero-stage::before {
  content: '';
  position: absolute;
  inset: -12% -8% -4%;
  transform: translateZ(-140px);
  background: radial-gradient(55% 55% at 50% 45%, rgba(124, 58, 237, .5), transparent 72%);
  filter: blur(46px);
  pointer-events: none;
}

.hero-product .app-shell {
  border: 1px solid rgba(167, 139, 250, .2);
  border-radius: 16px;
  box-shadow:
    0 0 0 1px rgba(255, 255, 255, .04) inset,
    0 1px 0 rgba(255, 255, 255, .09) inset,
    0 60px 120px -30px rgba(0, 0, 0, .85),
    0 0 80px -20px rgba(124, 58, 237, .45);
}

@media (max-width: 900px) {
  /* Perspective on a narrow screen costs legibility for no gain. */
  .hero-stage { --rx: 0deg; --ry: 0deg; transform: none; }
  .hero-stage::before { transform: none; }
}

@media (prefers-reduced-motion: reduce) {
  .hero-stage { transition: none; }
}

/* ── Sidebar with labels ───────────────────────────────────────────── */

.app-side {
  width: 118px;
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
  gap: 1px;
  padding: 12px 8px;
  border-right: 1px solid var(--app-line);
  background: rgba(238, 237, 255, .012);
}

.app-nav {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 8px;
  border-radius: 7px;
  font-size: 9.5px;
  color: rgba(238, 237, 255, .42);
}

.app-nav svg { width: 12px; height: 12px; flex-shrink: 0; }

.app-nav.is-active {
  background: rgba(124, 58, 237, .2);
  color: #C4B5FD;
  box-shadow: inset 0 0 0 1px rgba(167, 139, 250, .22);
}

/* Page title lives in the chrome, left of the search field. */
.app-page-title {
  font-size: 12.5px;
  font-weight: 600;
  letter-spacing: -.015em;
  flex-shrink: 0;
}

/* ── Chart with a value axis ───────────────────────────────────────── */

.app-plot { display: flex; gap: 8px; }

.app-yaxis {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  font-size: 8px;
  color: rgba(238, 237, 255, .24);
  text-align: right;
  flex-shrink: 0;
  padding: 1px 0 3px;
}

.app-plot .app-chart { flex: 1; }

@media (max-width: 900px) {
  .app-side { width: 44px; }
  .app-nav span { display: none; }
  .app-nav { justify-content: center; }
}

/* ═══════════════════════════════════════════════════════════════════════
   Mockup corrections
   ═════════════════════════════════════════════════════════════════════ */

/* An inline <svg> with no width/height scales to fill its container. The
   search and bell icons had no rule of their own and blew up to the height
   of the chrome. This is the safety net: every icon in the window gets a
   size, and the specific ones below opt into a different one. */
.app-shell svg {
  width: 12px;
  height: 12px;
  flex-shrink: 0;
}

.app-brand-mark svg { width: 11px; height: 11px; }
.app-kpi-ico svg    { width: 12px; height: 12px; }
.app-nav svg        { width: 12px; height: 12px; }
.app-search svg     { width: 11px; height: 11px; opacity: .7; }
.app-top-right > svg{ width: 14px; height: 14px; }

/* Keep the placeholder on one line - it was wrapping to two. */
.app-search {
  white-space: nowrap;
  overflow: hidden;
  min-width: 0;
}

/* The window is a floating object, so it is rounded on every corner; the
   hero mask fades its lower edge out rather than the flat crop it had. */
.hero-product .app-shell { border-radius: 16px; }

/* ── Proportion pass ───────────────────────────────────────────────── */
/* Everything below is relative to .app-shell's font-size, so the whole
   mockup scales from that one value. */

.app-top { padding: 9px 12px; gap: 12px; }
.app-page-title { font-size: 12px; }
.app-search { height: 24px; max-width: 230px; font-size: 9.5px; }
.app-user-name { font-size: 9.5px; }
.app-user-role { font-size: 8.5px; }
.app-avatar { width: 22px; height: 22px; font-size: 8.5px; }

.app-side { width: 112px; padding: 10px 7px; }
.app-nav { padding: 5.5px 8px; font-size: 9px; gap: 7px; }

.app-main { padding: 14px 15px 16px; }
.app-greet { font-size: 14px; }
.app-sub { font-size: 9.5px; margin-bottom: 13px; }

.app-kpis { gap: 9px; margin-bottom: 12px; }
.app-kpi { padding: 10px 11px; }
.app-kpi-top { gap: 7px; margin-bottom: 7px; }
.app-kpi-ico { width: 20px; height: 20px; border-radius: 5px; }
.app-kpi-lbl { font-size: 9px; }
.app-kpi-val { font-size: 14px; }
.app-kpi-delta { font-size: 8.5px; margin-top: 4px; }

.app-panel { padding: 11px; }
.app-panel-title { font-size: 10px; }
.app-order { padding: 6px 0; }
.app-order-id { font-size: 9px; }
.app-order-item { font-size: 8.5px; }
.app-order-amt { font-size: 9.5px; }

/* ── Chart: grid lines so the plot has a frame to read against ─────── */

.app-chart { height: 96px; }
.app-yaxis { font-size: 7.5px; }

.app-grid-line {
  stroke: rgba(238, 237, 255, .06);
  stroke-width: 1;
  vector-effect: non-scaling-stroke;
}

/* ═══════════════════════════════════════════════════════════════════════
   AI section - the conversation
   ═══════════════════════════════════════════════════════════════════════
   This is where the blob dissolves into the page, so the section is built
   to receive it: no solid panel background competing with the bloom behind
   it, just glass and hairlines with the light coming through.
   ═════════════════════════════════════════════════════════════════════ */

#ai .ai-inner {
  display: grid;
  grid-template-columns: 1fr 1.05fr;
  gap: clamp(32px, 6vw, 72px);
  align-items: center;
}

#ai h2 { font-weight: 300; }
#ai .gradient-text { font-weight: 600; }

#ai .ai-bullets {
  list-style: none;
  padding: 0;
  margin: 26px 0 30px;
  display: flex;
  flex-direction: column;
  gap: 11px;
}

#ai .ai-bullets li {
  position: relative;
  padding-left: 26px;
  font-size: .9375rem;
  color: rgba(238, 237, 255, .62);
}

/* A hairline tick rather than an emoji check - same restraint as the rest. */
#ai .ai-bullets li::before {
  content: '';
  position: absolute;
  left: 2px;
  top: .52em;
  width: 11px;
  height: 6px;
  border-left: 1.5px solid #A78BFA;
  border-bottom: 1.5px solid #A78BFA;
  transform: rotate(-45deg);
}

/* ── Conversation ──────────────────────────────────────────────────── */

#ai .chat-box {
  position: relative;
  padding: 18px;
  border: 1px solid rgba(238, 237, 255, .09);
  border-radius: 18px;
  background: linear-gradient(180deg, rgba(238, 237, 255, .05), rgba(238, 237, 255, .015));
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
  box-shadow: 0 40px 90px -30px rgba(0, 0, 0, .7);
  display: flex;
  flex-direction: column;
  gap: 10px;
}

#ai .chat-head {
  display: flex;
  align-items: center;
  gap: 9px;
  padding-bottom: 13px;
  margin-bottom: 4px;
  border-bottom: 1px solid rgba(238, 237, 255, .07);
  font-size: .8125rem;
  font-weight: 600;
  color: #EEEDFF;
}

#ai .chat-bubble {
  position: relative;
  max-width: 84%;
  padding: 11px 14px;
  border-radius: 14px;
  font-size: .8438rem;
  line-height: 1.6;
  opacity: 0;
  transform: translateY(10px);
  transition: opacity .45s cubic-bezier(.16, 1, .3, 1),
              transform .45s cubic-bezier(.16, 1, .3, 1);
}

#ai .chat-bubble.is-in { opacity: 1; transform: none; }

#ai .chat-bubble.ai {
  align-self: flex-start;
  border-bottom-left-radius: 5px;
  background: rgba(238, 237, 255, .05);
  border: 1px solid rgba(238, 237, 255, .07);
  color: rgba(238, 237, 255, .82);
}

#ai .chat-bubble.user {
  align-self: flex-end;
  border-bottom-right-radius: 5px;
  background: rgba(124, 58, 237, .3);
  border: 1px solid rgba(167, 139, 250, .32);
  color: #F2EFFF;
}

/* Caret while a line is being written, removed once it settles. */
#ai .chat-bubble.is-typing::after {
  content: '';
  display: inline-block;
  width: 2px;
  height: 1em;
  margin-left: 2px;
  vertical-align: text-bottom;
  background: #A78BFA;
  animation: ai-caret .8s step-end infinite;
}

@keyframes ai-caret { 0%, 100% { opacity: 1 } 50% { opacity: 0 } }

#ai .chat-typing {
  align-self: flex-start;
  display: flex;
  gap: 4px;
  padding: 12px 14px;
  border-radius: 14px;
  border-bottom-left-radius: 5px;
  background: rgba(238, 237, 255, .05);
  border: 1px solid rgba(238, 237, 255, .07);
  opacity: 0;
  transition: opacity .3s ease;
}

#ai .chat-typing.is-in { opacity: 1; }

#ai .chat-dot {
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: rgba(238, 237, 255, .5);
  animation: ai-dot 1.2s infinite;
}

#ai .chat-dot:nth-child(2) { animation-delay: .15s; }
#ai .chat-dot:nth-child(3) { animation-delay: .3s; }

@keyframes ai-dot {
  0%, 60%, 100% { opacity: .3; transform: translateY(0); }
  30%           { opacity: 1;  transform: translateY(-4px); }
}

@media (max-width: 880px) {
  #ai .ai-inner { grid-template-columns: 1fr; }
}

@media (prefers-reduced-motion: reduce) {
  #ai .chat-bubble { transition: none; opacity: 1; transform: none; }
  #ai .chat-bubble.is-typing::after,
  #ai .chat-dot { animation: none; }
}

/* ── AI section: live conversation controls ────────────────────────── */

#ai .chat-avatar {
  width: 30px; height: 30px; flex-shrink: 0;
  border-radius: 9px;
  background: linear-gradient(135deg, #A78BFA, #4F46E5);
  box-shadow: 0 0 18px -4px rgba(124, 58, 237, .8);
}

#ai .chat-name { font-size: .8438rem; font-weight: 600; color: #EEEDFF; }
#ai .chat-status { font-size: .6875rem; color: rgba(238, 237, 255, .4); }

#ai .chat-online {
  margin-left: auto;
  display: inline-flex; align-items: center; gap: 6px;
  font-size: .6875rem; font-weight: 500; color: rgba(238, 237, 255, .5);
}
#ai .chat-online::before {
  content: ''; width: 6px; height: 6px; border-radius: 50%;
  background: #34D399; box-shadow: 0 0 0 3px rgba(52, 211, 153, .16);
}

/* Fixed height so the panel doesn't jump as the conversation grows. */
#ai .chat-log {
  min-height: 232px;
  max-height: 300px;
  overflow-y: auto;
  display: flex; flex-direction: column; gap: 10px;
  padding-right: 4px;
  scrollbar-width: thin;
  scrollbar-color: rgba(238,237,255,.18) transparent;
}
#ai .chat-log::-webkit-scrollbar { width: 5px; }
#ai .chat-log::-webkit-scrollbar-thumb {
  background: rgba(238,237,255,.18); border-radius: 3px;
}

#ai .chat-bubble.err {
  align-self: flex-start;
  background: rgba(239,68,68,.1);
  border: 1px solid rgba(239,68,68,.25);
  color: #FCA5A5;
}

#ai .chat-chips { display: flex; flex-wrap: wrap; gap: 6px; }

#ai .chat-chip {
  padding: 6px 12px; border-radius: 100px; cursor: pointer;
  border: 1px solid rgba(238,237,255,.12);
  background: rgba(238,237,255,.03);
  color: rgba(238,237,255,.7);
  font: inherit; font-size: .75rem;
  transition: border-color .25s ease, color .25s ease;
}
#ai .chat-chip:hover { border-color: rgba(167,139,250,.45); color: #EEEDFF; }

#ai .chat-form { display: flex; gap: 8px; }

#ai .chat-input {
  flex: 1; min-width: 0; height: 42px; padding: 0 14px;
  border-radius: 11px;
  border: 1px solid rgba(238,237,255,.12);
  background: rgba(238,237,255,.04);
  color: #EEEDFF; font: inherit; font-size: .8438rem; outline: none;
  transition: border-color .25s ease;
}
#ai .chat-input:focus { border-color: rgba(167,139,250,.5); }
#ai .chat-input::placeholder { color: rgba(238,237,255,.32); }

#ai .chat-send {
  width: 42px; height: 42px; flex-shrink: 0; cursor: pointer;
  border: 0; border-radius: 11px; font-size: 16px;
  background: linear-gradient(180deg, #F4F2FF, #C9C3F5); color: #0B0A14;
  transition: transform .2s ease, opacity .2s ease;
}
#ai .chat-send:hover:not(:disabled) { transform: translateY(-1px); }
#ai .chat-send:disabled { opacity: .45; cursor: default; }

#ai .chat-foot { margin: 0; font-size: .625rem; color: rgba(238,237,255,.26); }

#ai .chat-input:focus-visible,
#ai .chat-chip:focus-visible,
#ai .chat-send:focus-visible { outline: 2px solid #A78BFA; outline-offset: 2px; }

/* ═══════════════════════════════════════════════════════════════════════
   Blob -> assistant: the cinematic handoff
   ═══════════════════════════════════════════════════════════════════════
   Three beats, the same ones Siri uses:
     1. the blob arrives and comes apart      (fluid-dots gather)
     2. it resolves into a listening waveform (wave)
     3. the waveform recedes and the chat is there
   Driven by scroll progress in ai-blob.js, so scrubbing back up plays it in
   reverse rather than replaying from the start.
   ═════════════════════════════════════════════════════════════════════ */

#ai .reveal.right { position: relative; }

.ai-stage {
  position: absolute;
  inset: 0;
  z-index: 3;
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;      /* never blocks the chat underneath */
}

.ai-siri {
  position: absolute;
  opacity: 0;
  /* Starts at the blob's footprint so the light appears to come out of it
     rather than switching on over the top. */
  transform: scale(.28);
  transition: opacity .55s cubic-bezier(.16, 1, .3, 1),
              transform .55s cubic-bezier(.16, 1, .3, 1);
  /* The canvas itself is transparent (alpha-enabled context, alpha driven
     by luminance), so no blend trick is needed - and the earlier one could
     not work: .ai-stage's z-index creates a stacking context, leaving
     nothing behind it to blend against. */
  will-change: opacity, transform;
}

.ai-siri canvas {
  background: transparent !important;
  border-radius: 24px;
}

.ai-stage.beat-dots .ai-siri-dots { opacity: 1; transform: scale(1); }
/* On the way out it collapses back toward the blob, not away from it. */
.ai-stage.beat-wave .ai-siri-dots { opacity: 0; transform: scale(1.25); }
.ai-stage.beat-wave .ai-siri-wave { opacity: 1; transform: scale(1.06); }

@media (prefers-reduced-motion: reduce) {
  .ai-siri { display: none; }
  #ai .chat-box { opacity: 1; transform: none; transition: none; }
}

/* ═══════════════════════════════════════════════════════════════════════
   The panel emerges from the blob
   ═══════════════════════════════════════════════════════════════════════
   A container morph, not a cross-fade. The blob travels to the panel's own
   position and grows to its size; the panel then unfolds out of that shape
   - starting blob-sized and blob-rounded, ending as the chat - while the
   blob dissolves into it. Scrolling back up runs --emerge down again, so
   the panel folds back into the blob rather than blinking out.

   --emerge is written by ai-blob.js each frame, so the shape morph is
   scrubbable rather than a fixed-duration animation.
   ═════════════════════════════════════════════════════════════════════ */

#ai .chat-box {
  --emerge: 0;
  transform-origin: center center;

  /* Starts at roughly the blob's footprint inside the panel's box. */
  transform: scale(calc(0.22 + 0.78 * var(--emerge)));

  /* Blob silhouette -> panel. The blob's radius is asymmetric, so the
     interpolation carries that asymmetry away as it opens. */
  border-radius: calc(46px - 24px * var(--emerge))
                 calc(46px - 24px * var(--emerge))
                 calc(40px - 18px * var(--emerge))
                 calc(40px - 18px * var(--emerge));

  opacity: var(--emerge);
  overflow: hidden;

  /* No transition: the value is driven per-frame from scroll, and a
     transition on top of that fights the scrub and lags behind it. */
  transition: none;
  will-change: transform, opacity, border-radius;
}

/* Contents appear only once the shell has opened enough to hold them,
   so you read "the shape became a panel" and then "it has a conversation
   in it" - rather than text scaling up from nothing. */
#ai .chat-box > * {
  opacity: calc((var(--emerge) - 0.55) / 0.45);
  transform: translateY(calc(10px * (1 - var(--emerge))));
}

/* The blob fades exactly as the panel takes over. */
.ai-blob { opacity: calc(var(--fade, 1) * 1); }
.ai-blob.is-ready { opacity: var(--fade, 1); }

@media (prefers-reduced-motion: reduce) {
  #ai .chat-box {
    --emerge: 1;
    transform: none;
    border-radius: 22px;
    opacity: 1;
  }
  #ai .chat-box > * { opacity: 1; transform: none; }
}

/* ── API example: language tabs ────────────────────────────────────── */
/* These were three styled <span>s with a single JavaScript block behind
   them: Python and PHP were labels for code that did not exist. */

.code-tabs {
  display: flex;
  border-bottom: 1px solid rgba(238, 237, 255, .08);
  background: rgba(238, 237, 255, .02);
}

.code-tab {
  position: relative;
  padding: 11px 18px;
  border: 0;
  background: none;
  cursor: pointer;
  font-family: var(--font-mono, ui-monospace, monospace);
  font-size: 12px;
  color: rgba(238, 237, 255, .42);
  transition: color .25s ease;
}

.code-tab:hover { color: rgba(238, 237, 255, .78); }
.code-tab.is-active { color: #C4B5FD; }

/* Same hairline marker as the module tabs, so the page has one idiom for
   "this is the selected one". */
.code-tab.is-active::after {
  content: '';
  position: absolute;
  left: 12px; right: 12px; bottom: -1px;
  height: 2px;
  background: linear-gradient(90deg, transparent, #A78BFA, transparent);
}

.code-tab:focus-visible { outline: 2px solid #A78BFA; outline-offset: -3px; }

.code-panel { display: none; }
.code-panel.is-active { display: block; }

@media (prefers-reduced-motion: reduce) { .code-tab { transition: none; } }

/* ═══════════════════════════════════════════════════════════════════════
   Ask-AI section: layout and surface
   ═══════════════════════════════════════════════════════════════════════
   The conversation is the subject of this section, so it gets the space:
   the copy column narrows and the panel becomes the dominant element,
   sitting on its own pool of violet light rather than on flat ground.
   ═════════════════════════════════════════════════════════════════════ */

#ai { position: relative; overflow: hidden; }

/* Ambient glow behind the whole section. */
#ai::before {
  content: '';
  position: absolute;
  top: -10%;
  left: 50%;
  width: 1200px;
  height: 720px;
  max-width: 150%;
  transform: translateX(-42%);
  pointer-events: none;
  z-index: 0;
  background:
    radial-gradient(42% 46% at 62% 42%, rgba(124, 58, 237, .34), transparent 70%),
    radial-gradient(34% 40% at 30% 62%, rgba(79, 70, 229, .22), transparent 72%);
  filter: blur(10px);
}

#ai .ai-inner {
  position: relative;
  z-index: 1;
  grid-template-columns: 1fr 1.05fr;
  gap: clamp(32px, 6vw, 72px);
}

/* ── Panel ─────────────────────────────────────────────────────────── */

#ai .chat-box {
  padding: 20px;
  /* border-radius is deliberately NOT set here: the blob->panel morph
     interpolates it per-frame, and a flat value declared after that rule
     would override the interpolation and flatten the whole effect. */
  border: 1px solid rgba(167, 139, 250, .16);
  background:
    linear-gradient(180deg, rgba(30, 24, 58, .72), rgba(14, 12, 26, .82));
  box-shadow:
    0 0 0 1px rgba(255, 255, 255, .02) inset,
    0 40px 110px -34px rgba(0, 0, 0, .85),
    0 0 90px -30px rgba(124, 58, 237, .55);
}

#ai .chat-avatar {
  display: flex; align-items: center; justify-content: center;
  color: #EEEDFF;
}
#ai .chat-avatar svg { width: 16px; height: 16px; }

#ai .chat-log { min-height: 232px; max-height: 300px; gap: 12px; }

/* ── Bubbles ───────────────────────────────────────────────────────── */

#ai .chat-bubble {
  max-width: 84%;
  padding: 12px 15px;
  border-radius: 14px;
  font-size: .875rem;
  line-height: 1.65;
}

/* Assistant lines carry the sparkle mark, as in the reference, so who is
   speaking is legible without reading the alignment. */
#ai .chat-bubble.ai {
  position: relative;
  margin-left: 40px;
  background: rgba(238, 237, 255, .045);
  border: 1px solid rgba(238, 237, 255, .06);
  color: rgba(238, 237, 255, .86);
}

#ai .chat-bubble.ai::before {
  content: '';
  position: absolute;
  left: -40px;
  top: 0;
  width: 28px;
  height: 28px;
  border-radius: 9px;
  background:
    radial-gradient(circle at 50% 50%, rgba(167, 139, 250, .3), rgba(124, 58, 237, .16)),
    rgba(238, 237, 255, .04);
  border: 1px solid rgba(167, 139, 250, .28);
  /* The same four-point sparkle, drawn as a mask so it needs no extra markup. */
  -webkit-mask: none;
  background-image:
    url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23C4B5FD' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 6.6c.7 3 2.7 5 5.4 5.4-2.7.4-4.7 2.4-5.4 5.4-.7-3-2.7-5-5.4-5.4 2.7-.4 4.7-2.4 5.4-5.4Z'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: center;
  background-size: 15px 15px;
}

#ai .chat-bubble.user {
  background: linear-gradient(180deg, rgba(124, 58, 237, .5), rgba(109, 40, 217, .42));
  border: 1px solid rgba(167, 139, 250, .34);
  color: #F4F1FF;
  box-shadow: 0 8px 24px -10px rgba(124, 58, 237, .7);
}

/* ── Composer ──────────────────────────────────────────────────────── */

#ai .chat-form {
  padding: 6px;
  border-radius: 14px;
  border: 1px solid rgba(167, 139, 250, .18);
  background: rgba(10, 9, 20, .6);
}

#ai .chat-input {
  height: 40px;
  border: 0;
  background: none;
  font-size: .875rem;
}
#ai .chat-input:focus { border: 0; }

#ai .chat-send {
  width: 38px; height: 38px;
  border-radius: 10px;
  background: linear-gradient(180deg, #8B5CF6, #6D28D9);
  color: #fff;
  box-shadow: 0 6px 18px -6px rgba(124, 58, 237, .9);
}

@media (max-width: 980px) {
  #ai .ai-inner { grid-template-columns: 1fr; }
  #ai .chat-bubble { max-width: 88%; }
}

/* ── Neural brain field ────────────────────────────────────────────── */
/* Real artwork rather than the generated node-graph that was here before.
   The source PNG is 2.17 MB, which is far too heavy for something purely
   decorative, so it ships as a 230 KB WebP: trimmed to its content bounds
   and resized to 900px, which still covers 2x displays at the size it
   renders. Its alpha channel is genuine, so it composites straight onto the
   section with no blend tricks. */

.brain-field {
  position: absolute;
  top: 50%;
  right: -120px;
  transform: translateY(-50%);
  width: 620px;
  max-width: 52vw;
  z-index: 0;
  pointer-events: none;
  opacity: .72;
  /* Dissolve the outer edges into the section so it reads as part of the
     page rather than a picture pasted on top of it. */
  -webkit-mask-image: radial-gradient(closest-side, #000 55%, transparent 100%);
  mask-image: radial-gradient(closest-side, #000 55%, transparent 100%);
  animation: brain-drift 14s ease-in-out infinite;
}

.brain-field img {
  width: 100%;
  height: auto;
  display: block;
}

@keyframes brain-drift {
  0%, 100% { transform: translateY(-50%) scale(1); }
  50%      { transform: translateY(-52%) scale(1.035); }
}

@media (max-width: 1180px) { .brain-field { right: -200px; opacity: .45; } }
@media (max-width: 980px)  { .brain-field { display: none; } }

@media (prefers-reduced-motion: reduce) { .brain-field { animation: none; } }
