/* Mistflow /create — screens-first flow.
   Built ON TOP of the landing chrome: styles.css tokens + nav.js + footer.js,
   so this page can replace the homepage first fold when we're ready. Local
   aliases below map the old create-page names onto landing tokens. Phone
   frames carry their own theme-pack palette via --p-* custom properties set
   by create.js. */

:root {
  --ink: var(--text, #111111);
  --dim: var(--text-muted, #6d6c6b);
  --line: var(--border, rgba(17, 17, 17, .10));
  --soft: var(--surface-soft, #F8FAFC);
  --glow: var(--accent-glow, oklch(0.62 0.16 245 / 0.18));
  --tint: var(--accent-tint, oklch(0.97 0.02 245));
  --blue: var(--accent-dark, oklch(0.55 0.18 245));
  --ok: #0E7C4A; --okbg: #E9F7EF;
}
body, body * { letter-spacing: 0 !important; }
button { font-family: inherit; cursor: pointer; }
input { font-family: inherit; }
#stage[hidden], #landing[hidden], #sheet[hidden], [hidden] { display: none !important; }

/* Nav is fixed (72px) on non-index pages — clear it. */
.create-main {
  max-width: 1240px; margin: 0 auto; padding: 108px 24px 72px;
  min-height: calc(100vh - 200px);
}
/* The prototype is a working studio, not a marketing content column. Give the
   editor + preview the available desktop width while the landing page keeps
   its tighter reading measure. */
.create-main:has(#stage:not([hidden])) { max-width: 1440px; padding-top: 32px; }

/* ---- first fold ---- */
#landing { padding-top: 4vh; }
#landing .kicker {
  text-align: center; font-size: 12px; font-weight: 600; letter-spacing: .08em;
  text-transform: uppercase; color: var(--blue); margin: 0 0 14px;
}
#landing h1 {
  font-family: var(--font-head, inherit);
  font-size: 60px; line-height: 1.02;
  margin: 0 0 16px; text-align: center; font-weight: 600; color: var(--ink);
  text-wrap: balance;
}
#landing .sub {
  color: var(--dim); text-align: center; font-size: 17px; line-height: 1.5;
  margin: 0 0 34px;
}
.boxwrap { max-width: 680px; margin: 0 auto; }
.create-home-shell {
  display: flex; flex-direction: column; gap: 28px;
}
#landing.create-home {
  padding-top: clamp(10px, 2.2vh, 24px);
}
.create-hero-grid {
  display: grid; grid-template-columns: minmax(0, 820px);
  justify-content: center;
}
.create-hero-copy {
  min-width: 0; max-width: 820px; padding-top: 0;
}
#landing .create-hero-copy .kicker,
#landing .create-hero-copy h1,
#landing .create-hero-copy .sub {
  text-align: center;
}
#landing .create-hero-copy .sub {
  max-width: 660px; margin: 0 auto 20px;
}
#landing .create-hero-copy .sub strong { color: var(--ink); font-weight: 600; }
#landing .create-hero-copy .boxwrap {
  max-width: min(720px, 100%); margin: 0 auto;
}
#landing .create-hero-copy .chips {
  justify-content: center;
}
.create-box-note {
  margin: 14px 0 0; font-size: 13px; line-height: 1.5; color: var(--dim);
  text-align: center;
}
.create-hero-copy .landing-error {
  margin: 16px auto 0; text-align: center;
}
.create-hero-copy > .kicker,
.create-hero-copy > h1,
.create-hero-copy > .sub,
.create-hero-copy > .boxwrap {
  animation: createHeroRise .72s cubic-bezier(.22, 1, .36, 1) both;
}
.create-hero-copy > h1 { animation-delay: 70ms; }
.create-hero-copy > .sub { animation-delay: 140ms; }
.create-hero-copy > .boxwrap { animation-delay: 210ms; }
/* The hero cinema is hero content, not a scroll-reveal: it animates in on
   load alongside the copy so the first fold never looks empty. The phones
   inside keep their own float animations. */
.create-hero-cinema {
  animation: createHeroRise .82s cubic-bezier(.22, 1, .36, 1) both;
  animation-delay: 280ms;
}
@keyframes createHeroRise {
  from { opacity: 0; transform: translateY(18px); }
  to { opacity: 1; transform: translateY(0); }
}
.create-motion-ready .create-reveal {
  opacity: 0; transform: translateY(24px);
  transition: opacity .72s cubic-bezier(.22, 1, .36, 1),
              transform .72s cubic-bezier(.22, 1, .36, 1);
  transition-delay: var(--reveal-delay, 0ms);
}
.create-motion-ready .create-reveal.is-visible {
  opacity: 1; transform: translateY(0);
}
.create-hero-cinema {
  width: 100%;
}
.create-cinema-stage {
  position: relative; overflow: hidden;
  min-height: 620px; padding: 44px 40px 30px;
  border-radius: 32px; border: 1px solid rgba(17, 17, 17, .08);
  background: linear-gradient(180deg, #dceaf7 0%, #c2d9ee 52%, #e7eef6 100%);
  box-shadow: 0 36px 70px -42px rgba(17, 17, 17, .28);
}
.create-cinema-stage::before {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background-image:
    linear-gradient(rgba(255, 255, 255, .28) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255, 255, 255, .2) 1px, transparent 1px);
  background-size: 24px 24px, 24px 24px;
  opacity: .28;
}
.create-cinema-stage::after {
  content: ""; position: absolute; inset: 14px; pointer-events: none;
  border-radius: 24px; border: 1px solid rgba(255, 255, 255, .36);
}
.create-cinema-glow {
  position: absolute; inset: auto 50% 78px; width: 520px; height: 260px;
  transform: translateX(-50%);
  background: radial-gradient(circle, rgba(255, 255, 255, .82) 0%, rgba(255, 255, 255, 0) 72%);
  filter: blur(10px); opacity: .9;
}
.create-cinema-phones {
  position: relative; z-index: 2;
  display: flex; align-items: flex-end; justify-content: center; gap: 22px;
  min-height: 532px;
}
.create-demo-phone {
  pointer-events: none;
  --p-display: 'Inter', -apple-system, 'SF Pro Display', system-ui, sans-serif;
  --p-display-style: normal;
  --p-display-weight: 700;
  --p-display-ls: -.03em;
  --p-body: 'Inter', -apple-system, 'SF Pro Display', system-ui, sans-serif;
  --p-label: 'IBM Plex Mono', ui-monospace, 'SF Mono', Menlo, monospace;
  --p-num-scale: 1;
  --p-tscale: 1;
  --p-density: 1;
  --p-cardborder: 1px;
  --p-bordercol: var(--p-border);
  will-change: transform;
}
.create-demo-phone .p-status { opacity: .74; }
.create-demo-phone .p-body { gap: 10px; }
.create-demo-phone .p-fab { margin-top: 4px; }
.create-demo-phone--left {
  transform: translateY(44px) rotate(-6deg) scale(.92);
  animation: createHeroFloatLeft 10s ease-in-out infinite;
}
.create-demo-phone--center {
  transform: translateY(0) scale(1.04);
  z-index: 3;
  animation: createHeroFloatCenter 9s ease-in-out infinite;
}
.create-demo-phone--right {
  transform: translateY(48px) rotate(6deg) scale(.94);
  animation: createHeroFloatRight 11s ease-in-out infinite;
}
@keyframes createHeroFloatLeft {
  50% { transform: translateY(34px) rotate(-7deg) scale(.93); }
}
@keyframes createHeroFloatCenter {
  50% { transform: translateY(-8px) scale(1.055); }
}
@keyframes createHeroFloatRight {
  50% { transform: translateY(40px) rotate(7deg) scale(.95); }
}
.create-demo-phone--center .p-notif {
  left: 12px; right: 12px; top: 10px;
  padding: 8px 10px;
}
.create-demo-phone--center .p-label {
  margin-top: 52px;
}
.create-demo-theme-sky {
  --p-page: #f6f8ff; --p-page-solid: #f6f8ff; --p-card: #ffffff;
  --p-fg: #142033; --p-cardfg: #142033; --p-muted: #edf2ff;
  --p-mutedfg: #667085; --p-border: rgba(20, 32, 51, .09);
  --p-primary: #4f6bff; --p-accent: #22c55e; --p-radius: 18px;
}
.create-demo-theme-coral {
  --p-page: #fff7f4; --p-page-solid: #fff7f4; --p-card: #ffffff;
  --p-fg: #17181d; --p-cardfg: #17181d; --p-muted: #ffe7df;
  --p-mutedfg: #8c6f6a; --p-border: rgba(23, 24, 29, .08);
  --p-primary: #ff6b57; --p-accent: #ffb36d; --p-radius: 20px;
}
.create-demo-theme-night {
  --p-page: #10141b; --p-page-solid: #10141b; --p-card: #171d26;
  --p-fg: #f3f6fb; --p-cardfg: #f3f6fb; --p-muted: #232b37;
  --p-mutedfg: #97a3b6; --p-border: rgba(255, 255, 255, .08);
  --p-primary: #7c9dff; --p-accent: #57d29a; --p-radius: 18px;
}
.create-cinema-notes {
  display: flex; flex-wrap: wrap; gap: 10px; margin-top: 14px; justify-content: center;
}
.create-cinema-note {
  display: inline-flex; align-items: center; min-height: 34px;
  padding: 0 14px; border-radius: 999px; border: 1px solid var(--line);
  background: rgba(255, 255, 255, .72); color: var(--ink);
  font: 600 12px/1 "IBM Plex Mono", ui-monospace, monospace;
  letter-spacing: .04em; text-transform: uppercase;
  backdrop-filter: blur(16px); -webkit-backdrop-filter: blur(16px);
}
.create-trust-strip {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 16px;
}
.create-trust-item {
  padding: 24px; border-radius: 22px; background: #fff; border: 1px solid var(--line);
  box-shadow: 0 20px 46px -34px rgba(17, 17, 17, .26);
}
.create-trust-label {
  margin: 0 0 10px; font: 600 11px/1.4 "IBM Plex Mono", ui-monospace, monospace;
  letter-spacing: .08em; text-transform: uppercase; color: var(--blue);
}
.create-trust-item h2 {
  margin: 0 0 10px; font-size: 24px; line-height: 1.08; letter-spacing: -.03em;
  font-weight: 600; color: var(--ink); text-wrap: balance;
}
.create-trust-item p:last-child {
  margin: 0; font-size: 14px; line-height: 1.55; color: var(--dim);
}
.create-band {
  margin-left: calc(50% - 50vw);
  margin-right: calc(50% - 50vw);
  padding-left: max(24px, calc(50vw - 620px));
  padding-right: max(24px, calc(50vw - 620px));
}
.create-mobile-proof {
  padding-top: 104px; padding-bottom: 112px;
  background: #f5f7f9; border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
}
.create-mobile-proof .section-header {
  max-width: 760px; margin: 0 auto 42px; text-align: center;
}
.create-mobile-gallery {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 18px; max-width: 1240px; margin: 0 auto;
}
.create-mobile-app {
  min-width: 0; color: var(--ink); text-decoration: none;
}
.create-mobile-art {
  aspect-ratio: 4 / 3; overflow: hidden; border-radius: 8px;
  background: #e8ebef; border: 1px solid rgba(17, 17, 17, .08);
  box-shadow: 0 24px 54px -38px rgba(17, 17, 17, .42);
}
.create-mobile-art img {
  display: block; width: 100%; height: 100%; object-fit: cover;
  transition: transform .55s cubic-bezier(.22, 1, .36, 1);
}
.create-mobile-meta {
  display: flex; align-items: flex-start; justify-content: space-between; gap: 18px;
  padding: 18px 2px 0;
}
.create-mobile-meta span:first-child {
  display: block; margin-bottom: 6px; color: var(--blue);
  font: 600 10px/1.3 "IBM Plex Mono", ui-monospace, monospace;
  letter-spacing: .08em; text-transform: uppercase;
}
.create-mobile-meta h3 {
  margin: 0; font-size: 20px; line-height: 1.22; font-weight: 600;
  letter-spacing: -.02em; text-wrap: balance;
}
.create-mobile-arrow {
  display: grid; place-items: center; flex: 0 0 36px; width: 36px; height: 36px;
  border-radius: 50%; border: 1px solid var(--line); background: #fff;
  transition: transform .25s cubic-bezier(.22, 1, .36, 1), background .25s, color .25s;
}
.create-mobile-app:hover .create-mobile-art img { transform: scale(1.025); }
.create-mobile-app:hover .create-mobile-arrow { transform: translateX(3px); background: var(--ink); color: #fff; }
.create-mobile-app:focus-visible { outline: 3px solid color-mix(in srgb, var(--blue) 40%, transparent); outline-offset: 6px; }
.create-mobile-proof-cta { display: flex; justify-content: center; margin-top: 44px; }
.create-mobile-proof-cta a {
  display: inline-flex; align-items: center; gap: 10px; min-height: 44px;
  color: var(--ink); font-size: 14px; font-weight: 600; text-decoration: none;
  border-bottom: 1px solid var(--ink);
}
.create-included {
  display: block; padding-top: 112px; padding-bottom: 120px;
  background: #111214; color: #fff; overflow: hidden;
}
.create-included-head {
  max-width: 1240px; margin: 0 auto 52px; display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(320px, .62fr);
  align-items: end; gap: clamp(36px, 8vw, 120px);
}
.create-included-label {
  margin: 0 0 14px; color: #8fc4ff;
  font: 600 11px/1.4 "IBM Plex Mono", ui-monospace, monospace;
  letter-spacing: .08em; text-transform: uppercase;
}
.create-included h2 {
  margin: 0; max-width: 760px; font-size: 60px; line-height: 1.02;
  font-weight: 600; letter-spacing: -.035em; text-wrap: balance;
}
.create-included-head > p:last-child {
  margin: 0 0 4px; max-width: 470px; color: rgba(255, 255, 255, .68);
  font-size: 17px; line-height: 1.62;
}

/* The homepage build animation is shared here unchanged: one visual language,
   one motion system, and no second imitation to drift out of sync. */
.create-stack-showcase {
  position: relative; max-width: 1240px; min-height: 570px; margin: 0 auto;
  display: grid; place-items: center; overflow: hidden;
  border: 1px solid rgba(255, 255, 255, .14); border-radius: 12px;
  background: radial-gradient(circle at 50% 48%, rgba(103, 173, 242, .15), transparent 36%), #f7f9fc;
  color: #17202a;
}
.create-original-animation-label {
  position: absolute; top: 28px; left: 30px; z-index: 3;
  display: inline-flex; align-items: center; gap: 9px; margin: 0;
  color: #557086; font: 600 9px/1.4 "IBM Plex Mono", ui-monospace, monospace;
  letter-spacing: .08em; text-transform: uppercase;
}
.create-original-animation-label > span {
  width: 7px; height: 7px; border-radius: 50%; background: #5c8ebb;
  box-shadow: 0 0 0 5px rgba(92, 142, 187, .12);
}
.create-stack-showcase #heroAnim {
  display: block; width: min(100%, 1080px); height: auto;
  overflow: visible; transform: translateY(14px) scale(1.03); transform-origin: center;
}

.create-included-list {
  max-width: 1240px; margin: 22px auto 0; padding: 0; display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 1px;
  list-style: none; background: rgba(255, 255, 255, .14); border: 1px solid rgba(255, 255, 255, .14);
}
.create-included-list li { min-width: 0; background: #111214; }
.create-included-card {
  position: relative; display: grid; grid-template-columns: 34px minmax(0, 1fr); gap: 12px;
  width: 100%; height: 100%; min-height: 142px; padding: 24px; border: 0;
  background: #15171a; color: #fff; text-align: left; cursor: pointer;
  transition: background .22s ease, box-shadow .22s ease;
}
.create-included-card::before {
  content: ""; position: absolute; left: 0; top: 0; right: 0; height: 2px;
  background: #8fc4ff; transform: scaleX(0); transform-origin: left;
  transition: transform .3s cubic-bezier(.22, 1, .36, 1);
}
.create-included-card:hover { background: #1b1e22; }
.create-included-card.is-selected { background: #1b2025; }
.create-included-card.is-selected::before { transform: scaleX(1); }
.create-included-card:focus-visible { z-index: 2; outline: 3px solid #8fc4ff; outline-offset: -3px; }
.create-included-card > span {
  color: #8fc4ff; font: 600 10px/1.5 "IBM Plex Mono", ui-monospace, monospace;
}
.create-included-card h3 { margin: 0 0 7px; font-size: 18px; line-height: 1.2; font-weight: 600; }
.create-included-card p { margin: 0; color: rgba(255, 255, 255, .6); font-size: 13px; line-height: 1.5; }

/* A product demonstration, not a process diagram. One static idea travels
   through the four moments that matter to a first-time app builder. */
.create-journey {
  padding-top: 112px; padding-bottom: 120px; background: #fff;
  border-bottom: 1px solid var(--line);
}
.create-journey-intro {
  max-width: 1240px; margin: 0 auto 56px; display: grid;
  grid-template-columns: minmax(0, .95fr) minmax(320px, .65fr);
  align-items: end; gap: clamp(36px, 8vw, 120px);
}
.create-journey-label {
  margin: 0 0 14px; color: var(--blue);
  font: 600 11px/1.4 "IBM Plex Mono", ui-monospace, monospace;
  text-transform: uppercase;
}
.create-journey-intro h2 {
  margin: 0; max-width: 720px; color: var(--ink);
  font-size: 64px; line-height: 1.02; font-weight: 600;
  text-wrap: balance;
}
.create-journey-intro > p {
  margin: 0 0 4px; color: var(--dim); font-size: 17px; line-height: 1.62;
}
.create-journey-stage {
  max-width: 1240px; min-height: 690px; margin: 0 auto; display: grid;
  grid-template-columns: minmax(0, .9fr) minmax(460px, 1.1fr);
  overflow: hidden; border: 1px solid #cbd9e7; border-radius: 8px;
  background: #edf5fd;
}
.create-journey-copy {
  display: flex; flex-direction: column; min-width: 0;
  padding: clamp(40px, 5vw, 70px); background: #f8fbfe;
  border-right: 1px solid #cbd9e7;
}
.create-journey-prompt {
  padding: 0 0 28px; border-bottom: 1px solid #cbd9e7;
}
.create-journey-prompt > span {
  display: block; margin-bottom: 12px; color: var(--blue);
  font: 600 10px/1.3 "IBM Plex Mono", ui-monospace, monospace;
  text-transform: uppercase;
}
.create-journey-prompt p {
  margin: 0; max-width: 470px; color: var(--ink);
  font-size: 25px; line-height: 1.42; font-weight: 500;
}
.create-journey-steps { margin-top: 22px; }
.create-journey-step {
  position: relative; display: grid; grid-template-columns: 34px minmax(0, 1fr);
  gap: 16px; width: 100%; min-height: 84px; padding: 17px 8px 17px 0;
  border: 0; border-bottom: 1px solid #d8e2ec; background: transparent;
  color: #667684; text-align: left; cursor: pointer;
  transition: color .25s ease, background .25s ease;
}
.create-journey-step::after {
  content: ""; position: absolute; left: 0; bottom: -1px; width: 100%; height: 2px;
  background: var(--blue); transform: scaleX(0); transform-origin: left;
}
.create-journey-step > span:first-child {
  padding-top: 3px; color: #7b91a5;
  font: 600 10px/1.4 "IBM Plex Mono", ui-monospace, monospace;
}
.create-journey-step > span:last-child { min-width: 0; }
.create-journey-step b {
  display: block; margin-bottom: 5px; color: inherit;
  font-size: 16px; line-height: 1.25; font-weight: 600;
}
.create-journey-step small {
  display: block; color: #73818d; font-size: 13px; line-height: 1.42;
}
.create-journey-step:hover { color: var(--ink); }
.create-journey-step[aria-selected="true"] { color: var(--ink); }
.create-journey-step[aria-selected="true"]::after {
  animation: createJourneyTimer 4.4s linear forwards;
}
.create-journey-step:focus-visible {
  outline: 3px solid color-mix(in srgb, var(--blue) 42%, transparent);
  outline-offset: 3px; border-radius: 4px;
}
@keyframes createJourneyTimer { to { transform: scaleX(1); } }
.create-journey-link {
  display: inline-flex; align-items: center; align-self: flex-start; gap: 10px;
  min-height: 44px; margin-top: auto; padding-top: 24px; color: var(--ink);
  border-bottom: 1px solid var(--ink); font-size: 14px; font-weight: 600;
  text-decoration: none;
}
.create-journey-link span { transition: transform .2s ease; }
.create-journey-link:hover span { transform: translateX(3px); }
.create-journey-link:focus-visible {
  outline: 3px solid color-mix(in srgb, var(--blue) 42%, transparent);
  outline-offset: 5px;
}

.create-journey-visual {
  position: relative; display: grid; place-items: center; min-width: 0;
  min-height: 690px; overflow: hidden; background: #dceeff;
}
.create-journey-visual::before,
.create-journey-visual::after {
  content: ""; position: absolute; left: 0; right: 0; height: 1px;
  background: rgba(33, 77, 116, .12);
}
.create-journey-visual::before { top: 33.333%; }
.create-journey-visual::after { top: 66.666%; }
.create-journey-caption {
  position: absolute; top: 28px; left: 30px; z-index: 2;
  display: inline-flex; align-items: center; gap: 10px; color: #315f85;
  font: 600 10px/1.4 "IBM Plex Mono", ui-monospace, monospace;
  text-transform: uppercase;
}
.create-journey-caption span:first-child {
  display: grid; place-items: center; width: 26px; height: 26px;
  border: 1px solid rgba(49, 95, 133, .24); border-radius: 50%;
}
.create-journey-phone {
  position: relative; z-index: 1; width: 292px; height: 596px;
  overflow: hidden; border: 7px solid #111418; border-radius: 42px;
  background: #fff; box-shadow: 0 42px 80px -30px rgba(36, 75, 108, .45);
}
.create-journey-phone::before {
  content: ""; position: absolute; top: 9px; left: 50%; z-index: 6;
  width: 72px; height: 21px; border-radius: 999px;
  background: #111418; transform: translateX(-50%);
}
.create-journey-status {
  position: absolute; inset: 0 0 auto; z-index: 5; display: flex;
  justify-content: space-between; padding: 12px 19px 0;
  color: #1b2228; font-size: 9px; font-weight: 700;
}
.create-journey-screen {
  position: absolute; inset: 38px 0 18px; z-index: 1; padding: 22px 20px;
  overflow: hidden; background: #fff; color: #1d2329;
  opacity: 0; transform: translateY(14px); pointer-events: none;
  transition: opacity .42s cubic-bezier(.22, 1, .36, 1), transform .42s cubic-bezier(.22, 1, .36, 1);
}
.create-journey-screen.is-active {
  z-index: 2; opacity: 1; transform: none; pointer-events: auto;
}
.journey-appbar {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  margin-bottom: 24px; color: #24313c;
  font: 600 9px/1.4 "IBM Plex Mono", ui-monospace, monospace;
  text-transform: uppercase;
}
.journey-state {
  display: inline-flex; align-items: center; min-height: 24px; padding: 0 9px;
  border-radius: 999px; background: #e8f2ff; color: #326da3;
  font: 600 8px/1 "IBM Plex Mono", ui-monospace, monospace;
}
.journey-state.live { background: #e2f6e9; color: #247644; }
.create-journey-screen h3 {
  margin: 0 0 7px; color: #151a1e; font-size: 27px; line-height: 1.08; font-weight: 700;
}
.journey-muted { margin: 0 0 22px; color: #71808c; font-size: 11px; line-height: 1.5; }
.journey-days { display: grid; grid-template-columns: repeat(5, 1fr); gap: 5px; margin-bottom: 18px; }
.journey-days span {
  padding: 8px 2px; border: 1px solid #e2e7ec; border-radius: 10px;
  color: #86929c; font-size: 7px; line-height: 1.7; text-align: center;
}
.journey-days b { color: #293038; font-size: 10px; }
.journey-days .active { border-color: #5e74f3; background: #5e74f3; color: rgba(255,255,255,.8); }
.journey-days .active b { color: #fff; }
.journey-class {
  display: grid; grid-template-columns: 42px 1fr auto; gap: 9px; align-items: center;
  padding: 13px 0; border-top: 1px solid #e7ebef;
}
.journey-class > span { color: #7e8b96; font-size: 8px; }
.journey-class div { min-width: 0; }
.journey-class div b { display: block; color: #28313a; font-size: 10px; line-height: 1.3; }
.journey-class div small { display: block; margin-top: 3px; color: #8a96a0; font-size: 8px; }
.journey-class i {
  padding: 4px 6px; border-radius: 999px; background: #ecefff; color: #4f64d8;
  font-size: 7px; font-style: normal; font-weight: 700;
}
.journey-class i.open { background: #e6f6eb; color: #267844; }
.journey-streak { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; margin-top: 18px; }
.journey-streak > span { padding: 13px; border-radius: 14px; background: #f5f7f9; }
.journey-streak b { display: block; margin-bottom: 3px; font-size: 19px; }
.journey-streak small { color: #7c8993; font-size: 7px; text-transform: uppercase; }

.journey-palette { display: flex; gap: 8px; margin-bottom: 18px; }
.journey-palette span {
  width: 35px; height: 35px; border-radius: 50%; background: var(--swatch);
  border: 3px solid #fff; box-shadow: 0 0 0 1px rgba(17,17,17,.12);
}
.journey-moods {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 4px; padding: 4px;
  margin-bottom: 18px; border-radius: 12px; background: #f1f2f4;
}
.journey-moods span { padding: 8px 3px; border-radius: 9px; color: #7b858e; font-size: 8px; text-align: center; }
.journey-moods .active { background: #fff; color: #242a2f; box-shadow: 0 2px 8px rgba(17,17,17,.08); }
.journey-style-card { padding: 17px; border-radius: 16px; background: #fff1ea; }
.journey-style-card > small { display: block; margin-bottom: 10px; color: #c05240; font-size: 7px; }
.journey-style-card > b { display: block; margin-bottom: 5px; font-size: 15px; }
.journey-style-card > span { display: block; color: #86675f; font-size: 9px; }
.journey-style-card .journey-style-button {
  display: block; width: 100%; box-sizing: border-box; margin-top: 18px; padding: 10px;
  border-radius: 10px; background: #f06e59; color: #fff; font-size: 9px;
  font-weight: 700; text-align: center;
}
.journey-change {
  margin-top: 18px; padding: 12px 14px; border-left: 2px solid #f06e59;
  background: #faf7f5; color: #785f58; font-size: 9px; line-height: 1.45;
}

.journey-build-list { margin-top: 10px; }
.journey-build-list div {
  display: flex; justify-content: space-between; gap: 16px; padding: 15px 0;
  border-top: 1px solid #e5e9ed; color: #4d5963; font-size: 10px;
}
.journey-build-list b { color: #277947; font-size: 9px; }
.journey-build-list .is-building b { color: #326da3; }
.journey-build-progress { height: 6px; margin-top: 20px; overflow: hidden; border-radius: 999px; background: #e8edf1; }
.journey-build-progress span {
  display: block; width: 82%; height: 100%; border-radius: inherit; background: #4f7fb0;
  transform-origin: left; animation: createJourneyBuild 2.4s ease-in-out infinite alternate;
}
@keyframes createJourneyBuild { from { transform: scaleX(.72); } to { transform: scaleX(1); } }
.journey-build-note { margin: 14px 0 0; color: #7c8993; font-size: 9px; line-height: 1.5; }

.journey-live-screen { text-align: center; }
.journey-live-screen .journey-appbar { text-align: left; }
.journey-live-mark {
  display: grid; place-items: center; width: 68px; height: 68px; margin: 38px auto 24px;
  border-radius: 50%; background: #e2f6e9; color: #247644; font-size: 28px; font-weight: 700;
}
.journey-live-screen h3 { font-size: 25px; }
.journey-live-screen .journey-muted { max-width: 210px; margin-left: auto; margin-right: auto; }
.journey-url { padding: 15px; border: 1px solid #dbe3e9; border-radius: 13px; text-align: left; }
.journey-url small { display: block; margin-bottom: 6px; color: #7a8893; font-size: 7px; }
.journey-url b { display: block; overflow: hidden; color: #2d3740; font-size: 10px; text-overflow: ellipsis; }
.journey-open {
  display: flex; align-items: center; justify-content: space-between; margin-top: 12px;
  padding: 13px 15px; border-radius: 12px; background: #171b1f; color: #fff;
  font-size: 10px; font-weight: 700;
}
.journey-live-note { margin: 18px auto 0; max-width: 210px; color: #7c8993; font-size: 9px; line-height: 1.5; }
.create-journey-home {
  position: absolute; left: 50%; bottom: 7px; z-index: 5; width: 90px; height: 4px;
  border-radius: 999px; background: #171b1f; transform: translateX(-50%);
}

/* The browser builder is the first act. This section makes the second act
   concrete without turning the hero back into an editor-install pitch. */
.create-handoff {
  padding-top: 112px; padding-bottom: 120px; background: #f2f0ec;
  border-bottom: 1px solid var(--line);
}
.create-handoff-inner {
  max-width: 1240px; margin: 0 auto; display: grid;
  grid-template-columns: minmax(0, .82fr) minmax(480px, 1.18fr);
  align-items: center; gap: clamp(52px, 9vw, 132px);
}
.create-handoff-label,
.create-studio-label {
  margin: 0 0 14px; color: var(--blue);
  font: 600 11px/1.4 "IBM Plex Mono", ui-monospace, monospace;
  text-transform: uppercase;
}
.create-handoff-copy h2 {
  margin: 0 0 22px; color: var(--ink); font-size: 60px; line-height: 1.01;
  font-weight: 600; text-wrap: balance;
}
.create-handoff-copy > p:not(.create-handoff-label) {
  margin: 0; max-width: 540px; color: var(--dim); font-size: 17px; line-height: 1.62;
}
.create-handoff-benefits {
  display: flex; flex-wrap: wrap; gap: 10px 18px; list-style: none;
  margin: 28px 0 30px; padding: 0;
}
.create-handoff-benefits li {
  display: inline-flex; align-items: center; gap: 8px; color: var(--ink);
  font-size: 13px; font-weight: 600;
}
.create-handoff-benefits li::before {
  content: "\2713"; display: grid; place-items: center; width: 20px; height: 20px;
  border-radius: 50%; background: #dff3e6; color: #187145; font-size: 11px;
}
.create-handoff-link {
  display: inline-flex; align-items: center; gap: 10px; min-height: 44px;
  color: var(--ink); border-bottom: 1px solid var(--ink); font-size: 14px;
  font-weight: 600; text-decoration: none;
}
.create-handoff-link span,
.create-studio-link span { transition: transform .22s cubic-bezier(.22, 1, .36, 1); }
.create-handoff-link:hover span,
.create-studio-link:hover span { transform: translateX(3px); }
.create-handoff-link:focus-visible,
.create-studio-link:focus-visible {
  outline: 3px solid color-mix(in srgb, var(--blue) 42%, transparent); outline-offset: 5px;
}
.create-handoff-visual {
  position: relative; min-width: 0; padding: 30px; overflow: hidden;
  border: 1px solid #d6d3ce; border-radius: 8px; background: #fff;
  box-shadow: 0 30px 70px -48px rgba(17, 17, 17, .46);
}
.create-handoff-visual::before {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background-image:
    linear-gradient(rgba(17, 17, 17, .035) 1px, transparent 1px),
    linear-gradient(90deg, rgba(17, 17, 17, .035) 1px, transparent 1px);
  background-size: 24px 24px; mask-image: linear-gradient(to bottom, #000, transparent 72%);
}
.create-handoff-project,
.create-handoff-context,
.create-handoff-path,
.create-handoff-editors,
.create-handoff-visual-note { position: relative; z-index: 1; }
.create-handoff-project {
  display: grid; grid-template-columns: auto minmax(0, 1fr) auto; align-items: center;
  gap: 13px; padding: 18px; border: 1px solid #d8dde2; border-radius: 8px; background: #fff;
}
.create-handoff-appmark,
.create-editor-mark {
  display: grid; place-items: center; flex: none; width: 42px; height: 42px;
  border-radius: 11px; background: #17191c; color: #fff; font-size: 15px; font-weight: 700;
}
.create-handoff-project small,
.create-handoff-project strong,
.create-handoff-editors small,
.create-handoff-editors strong { display: block; }
.create-handoff-project small,
.create-handoff-editors small {
  margin-bottom: 3px; color: #78818a; font-size: 9px; line-height: 1.3; text-transform: uppercase;
}
.create-handoff-project strong { color: #1e2429; font-size: 15px; line-height: 1.25; }
.create-handoff-ready {
  display: inline-flex; align-items: center; gap: 6px; padding: 7px 9px;
  border-radius: 999px; background: #e7f5eb; color: #237446; font-size: 9px; font-weight: 700;
}
.create-handoff-ready i { width: 6px; height: 6px; border-radius: 50%; background: currentColor; }
.create-handoff-context {
  display: grid; grid-template-columns: 1fr 1fr; gap: 8px; margin-top: 10px;
}
.create-handoff-context span {
  padding: 12px 13px; border: 1px solid #e0e3e6; border-radius: 7px;
  background: rgba(255, 255, 255, .92); color: #5f6972; font-size: 10px; font-weight: 600;
}
.create-handoff-context span::before {
  content: "\2713"; margin-right: 7px; color: #267b4b;
}
.create-handoff-path {
  display: grid; place-items: center; height: 82px;
}
.create-handoff-path::before {
  content: ""; position: absolute; top: 0; bottom: 0; left: 50%;
  border-left: 1px dashed #aeb5bc;
}
.create-handoff-path span {
  position: relative; padding: 7px 11px; border: 1px solid #d8dde2;
  border-radius: 999px; background: #fff; color: #59636c;
  font: 600 9px/1.2 "IBM Plex Mono", ui-monospace, monospace; text-transform: uppercase;
}
.create-handoff-editors { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.create-handoff-editors > div {
  display: flex; align-items: center; gap: 12px; min-width: 0; padding: 16px;
  border: 1px solid #cfd5da; border-radius: 8px; background: #f8fafb;
}
.create-editor-mark { width: 38px; height: 38px; border-radius: 10px; background: #111; font-size: 13px; }
.create-editor-mark--warm { background: #c76643; font-size: 10px; }
.create-handoff-editors p { min-width: 0; margin: 0; }
.create-handoff-editors strong { overflow: hidden; color: #20262b; font-size: 13px; text-overflow: ellipsis; white-space: nowrap; }
.create-handoff-visual-note {
  margin: 18px auto 0; max-width: 440px; color: #68727b; font-size: 12px;
  line-height: 1.5; text-align: center;
}

.create-studio {
  padding-top: 80px; padding-bottom: 80px; background: #f5f7f9;
  border-top: 1px solid var(--line);
}
.create-studio-card {
  max-width: 1240px; margin: 0 auto; display: grid;
  grid-template-columns: minmax(0, 1fr) auto; align-items: end; gap: 42px;
  padding: 42px 44px; border: 1px solid #cfd4da; border-radius: 8px;
  background: #fff; box-shadow: 0 24px 56px -44px rgba(17, 17, 17, .42);
}
.create-studio-card h2 {
  margin: 0 0 12px; color: var(--ink); font-size: 38px; line-height: 1.06;
  font-weight: 600; text-wrap: balance;
}
.create-studio-card p:last-child {
  max-width: 720px; margin: 0; color: var(--dim); font-size: 15px; line-height: 1.6;
}
.create-studio-link {
  display: inline-flex; align-items: center; justify-content: center; gap: 12px;
  min-height: 50px; padding: 0 22px; border-radius: 999px; background: var(--ink);
  color: #fff; font-size: 13px; font-weight: 600; text-decoration: none; white-space: nowrap;
}

.create-endcap {
  padding-top: 76px; padding-bottom: 84px; background: #111214; color: #fff;
}
.create-endcap-inner {
  max-width: var(--max-w, 1240px); margin: 0 auto;
  display: flex; align-items: flex-end; justify-content: space-between; gap: 28px;
}
.create-endcap-label {
  margin: 0 0 12px; font: 600 11px/1.4 "IBM Plex Mono", ui-monospace, monospace;
  letter-spacing: .08em; text-transform: uppercase; color: rgba(255, 255, 255, .7);
}
.create-endcap h2 {
  margin: 0 0 12px; font-family: var(--font-head, inherit);
  font-size: 46px; line-height: 1.02;
  font-weight: 600; text-wrap: balance;
}
.create-endcap p {
  margin: 0; max-width: 520px; font-size: 16px; line-height: 1.6; color: rgba(255, 255, 255, .72);
}
.create-endcap-actions {
  display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 14px;
}
.chatbox {
  display: flex; gap: 10px; background: #fff; border: 1px solid var(--line);
  border-radius: 16px; padding: 10px 10px 10px 22px; align-items: flex-end;
  box-shadow: var(--shadow-card, 0 1px 2px rgba(17,17,17,.04));
  transition: border-color .25s var(--ease, ease), box-shadow .25s var(--ease, ease); margin: 0;
}
.chatbox:focus-within {
  border-color: color-mix(in oklch, var(--blue) 45%, transparent);
  box-shadow: 0 18px 44px -14px var(--glow), var(--shadow-card, 0 1px 2px rgba(17,17,17,.04));
}
/* Autosized by JS up to a ceiling, then it scrolls. `resize: none` because the
   drag handle would fight the autosize and let someone shrink the box below the
   text it already holds. */
.chatbox textarea {
  flex: 1; background: none; border: none; outline: none; color: var(--ink);
  font-size: 16.5px; line-height: 1.45; padding: 15px 0; min-width: 0;
  font-family: inherit; resize: none; overflow-y: auto;
  /* Six whole lines. Counts the TOP padding only: in a scroll container the
     bottom padding sits after the last line and is not in view at scrollTop 0,
     so budgeting for both leaves a seventh line clipped through the middle of
     its glyphs — which reads as a rendering fault, not as "there is more
     below". Autosize reads this value back off the computed style; do not keep
     a second copy in JS. */
  max-height: calc(15px + 6 * 1.45em);
}
.chatbox textarea::placeholder { color: color-mix(in srgb, var(--dim) 75%, transparent); }
.chatbox button {
  background: var(--ink); border: none; color: #fff; font-weight: 600;
  font-size: 15px; padding: 15px 24px; border-radius: 11px; white-space: nowrap;
  box-shadow: 0 14px 30px -10px var(--glow), 0 4px 10px -2px rgba(17,17,17,.18);
  transition: transform .2s var(--ease, ease);
}
.chatbox button:hover { transform: translateY(-1px); }
.chatbox button:disabled { opacity: .6; cursor: wait; transform: none; }
.chips { display: flex; gap: 8px; flex-wrap: wrap; justify-content: center; margin-top: 16px; }
.chip {
  background: #fff; border: 1px solid var(--line); color: var(--dim);
  font-size: 13px; font-weight: 500; padding: 9px 16px; border-radius: 999px;
  transition: all .15s;
}
.chip:hover {
  border-color: color-mix(in oklch, var(--blue) 55%, transparent);
  color: var(--ink); box-shadow: 0 8px 20px -8px var(--glow);
}
.chip.magic { border-style: dashed; color: var(--blue); }
/* Composer pill — the ambient surface choice. Sits between the box and the
   starter chips; segmented so the active surface reads as "already decided,"
   not "pick one." Free, instant, undoable — the user rarely touches it. */
.composer-pill {
  display: flex; width: max-content; gap: 2px; margin: 12px auto 0; padding: 3px;
  background: color-mix(in srgb, var(--line) 45%, #fff);
  border: 1px solid var(--line); border-radius: 999px;
  opacity: 0; transform: translateY(-3px);
  transition: opacity .25s var(--ease, ease), transform .25s var(--ease, ease);
}
.composer-pill.show { opacity: 1; transform: none; }
.composer-pill[hidden] { display: none; }
.cpill-opt {
  display: inline-flex; align-items: center;
  font: 500 12.5px/1 var(--font-body, inherit); padding: 8px 15px;
  border: none; background: transparent; color: var(--dim);
  border-radius: 999px; cursor: pointer;
  transition: color .18s var(--ease, ease), background .18s var(--ease, ease);
}
.cpill-opt:hover { color: var(--ink); }
.cpill-opt[aria-checked="true"] {
  background: #fff; color: var(--ink); cursor: default;
  box-shadow: 0 1px 3px rgba(17,17,17,.10);
}
/* When the model (layer B) just moved the pill, pulse it once so the user
   notices the surface was re-guessed without it being a modal interruption. */
.composer-pill.auto-moved { animation: cpillPulse .5s var(--ease, ease); }
@keyframes cpillPulse {
  0% { box-shadow: 0 0 0 0 var(--glow); }
  60% { box-shadow: 0 0 0 5px transparent; }
  100% { box-shadow: 0 0 0 0 transparent; }
}
@media (prefers-reduced-motion: reduce) {
  .composer-pill, .cpill-opt { transition: none; }
  .composer-pill.auto-moved { animation: none; }
}
.landing-error {
  display: flex; align-items: center; justify-content: center; flex-wrap: wrap; gap: 10px 14px;
  max-width: 680px; margin: 18px auto 0; text-align: center; font-size: 13px;
  color: #B4231F; background: #FCEEED; border: 1px solid #F4CBC9;
  border-radius: 10px; padding: 10px 14px;
}
.landing-error-action {
  display: inline-flex; align-items: center; justify-content: center; min-height: 44px;
  padding: 0 14px; border-radius: 8px; background: #741f1b; color: #fff;
  font-size: 12px; font-weight: 700; text-decoration: none;
}
.landing-error-action:hover { background: #541512; }
.landing-error-action:focus-visible { outline: 3px solid rgba(180, 35, 31, .28); outline-offset: 3px; }

/* ---- takeover ----
   With a prototype on screen this page stops being a marketing page and becomes
   an editor. The marketing nav gives way to ONE app bar; stacking both put two
   competing headers above the work and cost ~130px before a screen appeared. */
body:has(#stage:not([hidden])) nav.site-nav { display: none; }

/* Full-bleed. .create-main is a padded, max-width:1440px column, so a bar laid
   out inside it floated with 54px gutters and 32px of page padding above —
   a strip, not a bar. Negative auto-margins pull it back to the viewport edge
   (width stays `auto`, so it never counts the scrollbar the way 100vw does),
   and the negative top cancels the container's own top padding. */
.appbar {
  position: sticky; top: 0; z-index: 40;
  margin: -32px calc(50% - 50vw) 20px;
  background: rgba(255, 255, 255, .93); backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--line);
}
/* Content still rides the same rail as the board below it, so the identity
   lines up with the rail and Build it lines up with the right edge of the
   screens rather than the browser window. */
/* Full width, matching the stage below. Capping this at 1440 while the work
   below runs edge to edge would put the logo and Build it on a different rail
   from the rail divider and the board they sit above. */
.ab-inner {
  padding: 0 24px;
  display: grid; grid-template-columns: 1fr auto 1fr; align-items: center;
  gap: 18px; height: 56px;
}
.ab-left { display: flex; align-items: center; gap: 13px; min-width: 0; }
.ab-right { display: flex; align-items: center; justify-content: flex-end; gap: 10px; min-width: 0; }
.ab-div { flex: none; width: 1px; height: 19px; background: var(--line); }
.ab-logo {
  flex: none; display: flex; align-items: center; gap: 7px;
  color: var(--ink); text-decoration: none; transition: opacity .15s;
}
.ab-logo b { font-size: 16px; font-weight: 700; letter-spacing: -.012em; font-family: var(--font-head, inherit); }
.ab-logo svg { flex: none; }
.ab-logo:hover { opacity: .62; }
.ab-back { flex: none; color: var(--dim); font-size: 13px; background: none; border: none; padding: 0; transition: color .15s; }
.ab-back:hover { color: var(--ink); }

/* Identity IS the comprehension check. Name + who it's for are the two facts
   the whole build rests on, so they live permanently in the bar and are one
   click from editable — instead of hiding behind a "Check what we understood"
   button that most people never pressed. */
/* Reads as a control at REST, not only on hover. Shipped first with no resting
   affordance beyond a small pencil, and the first person to use it could not
   find the confirmation at all — it is the only way in besides Build it, so an
   invisible entry point means the spec never gets checked. */
.ab-ident {
  display: flex; align-items: baseline; gap: 8px; min-width: 0;
  background: var(--soft); border: 1px solid var(--line);
  padding: 5px 11px; border-radius: 9px; text-align: left;
  transition: background .15s, border-color .15s;
}
.ab-ident:hover { background: #fff; border-color: var(--dim); }
.ab-ident:empty { display: none; }
.ab-ident .ab-name {
  font-size: 15px; font-weight: 700; letter-spacing: -.012em; color: var(--ink);
  white-space: nowrap; font-family: var(--font-head, inherit);
}
.ab-ident .ab-actor {
  font-size: 13px; color: var(--dim); min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.ab-ident .ab-pen { flex: none; font-size: 10.5px; color: #b9bbc0; }
.ab-ident:hover .ab-pen { color: var(--dim); }

.ab-tabs {
  display: flex; gap: 2px; padding: 3px; justify-self: center;
  background: var(--soft); border: 1px solid var(--line); border-radius: 999px;
}
.ab-tabs:empty { display: none; }
.ab-mktg { display: flex; align-items: center; gap: 15px; }
.ab-mktg a { color: var(--dim); font-size: 13px; text-decoration: none; white-space: nowrap; transition: color .15s; }
.ab-mktg a:hover { color: var(--ink); }
.ab-build {
  flex: none; display: flex; align-items: center; gap: 8px;
  background: var(--ink); color: #fff; border: none;
  font-size: 13.5px; font-weight: 700; padding: 9px 18px; border-radius: 9px;
  box-shadow: 0 10px 26px -14px var(--glow), 0 2px 6px -2px rgba(17,17,17,.18);
  transition: transform .18s var(--ease, ease), background .15s;
}
.ab-build:hover { transform: translateY(-1px); background: #000; }
.ab-build-arrow { font-size: 10px; opacity: .68; }

@media (max-width: 1080px) {
  /* Marketing links are the first thing to go when the bar tightens — the
     logo still carries "what is this", which is the job that matters to a
     stranger on a shared link. */
  .ab-mktg { display: none; }
  .ab-logo b, .ab-back { display: none; }
}
/* The rail used to be pinned at 332-348px at EVERY viewport, so it never grew
   no matter how much room the screen had, and the conversation competed with a
   style dock inside a column narrower than a phone. It now has a real floor and
   is allowed to breathe on large displays, while the board keeps the majority.
   The gap tightens as the rail widens so the board loses less than the rail
   gains. */
/* Full-bleed, like the bar above it. The chat is a docked panel, so it runs to
   the viewport edge with its own internal padding — laying it out inside
   .create-main's centred 1440px column left a gutter of page background to the
   left of the dock, which read as the panel having slipped off its edge. */
.stagegrid {
  display: grid;
  grid-template-columns: minmax(420px, 460px) minmax(0, 1fr);
  gap: clamp(28px, 3vw, 44px); align-items: start;
  margin-left: calc(50% - 50vw); margin-right: calc(50% - 50vw);
  padding-right: 24px;
}
@media (max-width: 1180px) {
  /* Below this the board cannot afford 460px; fall back to the old floor
     rather than squeezing the phones into strips. */
  .stagegrid { grid-template-columns: minmax(332px, 380px) minmax(0, 1fr); }
}
/* A conversation, not a card. The outer border made every message a box inside
   a box inside a panel; the rail now sits on the page ground with one dividing
   edge, and the messages carry themselves. */
.rail {
  min-width: 0; height: calc(100dvh - 96px); min-height: 520px;
  position: sticky; top: 76px; display: flex; flex-direction: column; overflow: hidden;
  background: transparent; border: none; border-right: 1px solid var(--line);
  border-radius: 0; box-shadow: none;
  /* Docked to the viewport edge; content is inset by the children's own
     padding (rail-scroll / railbrief / compose all carry 18px). */
  padding: 0 clamp(10px, 1vw, 18px) 0 6px;
}
/* The clamp CANNOT live on .railhead itself. It is a direct child of .rail,
   which is a flex container, and a flex item's display is blockified —
   `-webkit-box` computes to `flow-root`, so `-webkit-line-clamp` silently does
   nothing and `overflow: hidden` slices the third line through the middle of
   the glyphs. Clamp an inner element instead, which is not a flex item. */
.railhead { flex: none; padding: 15px 18px 9px; font-size: 12.5px; color: var(--dim); }
.rh-kicker { display: block; font-size: 11.5px; color: var(--dim); margin-bottom: 2px; }
.rh-quote {
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2;
  overflow: hidden; line-height: 1.45; color: var(--ink); font-weight: 600;
}
/* What we understood, in the rail. Replaces the "Changing / Whole app" chip,
   which said what the composer already says and read identically on almost
   every render. This slot now carries something that CHANGES with the app and
   that people were actively hunting for. */
.railbrief {
  flex: none; display: flex; flex-direction: column; gap: 4px;
  margin: 0 18px 10px; padding: 9px 12px 10px; width: calc(100% - 36px);
  border: 1px solid var(--line); border-radius: 11px; background: var(--soft);
  text-align: left; cursor: pointer; transition: background .15s, border-color .15s;
}
.railbrief:hover { background: #fff; border-color: var(--dim); }
.rb-head { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }
.rb-head b { font-size: 11px; font-weight: 700; letter-spacing: .05em; text-transform: uppercase; color: var(--dim); }
.rb-edit { font-size: 11.5px; font-weight: 600; color: var(--blue); white-space: nowrap; }
.rb-for {
  font-size: 12.5px; line-height: 1.45; color: var(--ink); font-weight: 600;
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden;
}
.rb-jobs { list-style: none; margin: 2px 0 0; padding: 0; display: flex; flex-direction: column; gap: 4px; }
.rb-jobs li {
  position: relative; padding-left: 13px; font-size: 12px; line-height: 1.45; color: var(--dim);
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden;
}
.rb-jobs li::before {
  content: ""; position: absolute; left: 2px; top: 7px;
  width: 4px; height: 4px; border-radius: 1px; background: var(--line-strong, #c9cbd1);
}
.rb-more { color: var(--faint, #a2a5ac); font-style: italic; }
.rb-more::before { display: none; }
.rail-scroll {
  flex: 1; min-height: 0; overflow-y: auto; overscroll-behavior: contain;
  padding: 0 18px 14px; scrollbar-gutter: stable;
}
.stage-generating .rail {
  height: auto; min-height: 0;
}
.stage-generating .railbrief,
.stage-generating .rail-compose { display: none; }
.stage-generating .rail-scroll {
  flex: none; min-height: 0; overflow: hidden; padding-bottom: 18px;
}
.stage-generating .msgs { margin-bottom: 0; }
.build-progress {
  display: flex; align-items: center; gap: 12px; padding: 13px;
  border: 1px solid var(--line); border-radius: 12px; background: var(--soft);
}
.build-progress-mark {
  width: 34px; height: 34px; flex: none; display: flex; align-items: center;
  justify-content: center; gap: 3px; border-radius: 10px; background: #fff;
  border: 1px solid var(--line);
}
.build-progress-mark i {
  width: 4px; height: 4px; border-radius: 50%; background: var(--blue);
  animation: buildProgressPulse 1.1s ease-in-out infinite;
}
.build-progress-mark i:nth-child(2) { animation-delay: .14s; }
.build-progress-mark i:nth-child(3) { animation-delay: .28s; }
.build-progress-copy { min-width: 0; display: flex; flex-direction: column; gap: 3px; }
.build-progress-copy b { font-size: 12.5px; color: var(--ink); }
.build-progress-copy small { font-size: 11px; line-height: 1.35; color: var(--dim); }
@keyframes buildProgressPulse {
  0%, 65%, 100% { opacity: .28; transform: translateY(0); }
  32% { opacity: 1; transform: translateY(-2px); }
}
.msgs { display: flex; flex-direction: column; gap: 12px; margin-bottom: 12px; }
.m { font-size: 13.5px; line-height: 1.55; padding: 10px 12px; border-radius: 11px; max-width: 96%; }
.m.ai { background: var(--soft); border: 1px solid var(--line); color: var(--ink); }
.m.me { background: var(--ink); color: #fff; align-self: flex-end; }
.m.nudge { border: 1px dashed color-mix(in oklch, var(--blue) 40%, transparent); background: var(--tint); color: var(--dim); }
.m.nudge b { color: var(--blue); }
.m.action { max-width: 100%; padding: 12px; margin: 2px 0; background: #fff; border: 1px solid var(--line); }
.m.action .action-head { display: flex; gap: 8px; align-items: center; font-weight: 700; }
.m.action .action-mark {
  width: 19px; height: 19px; border-radius: 50%; display: inline-flex;
  align-items: center; justify-content: center; flex: none; color: #fff;
  background: var(--blue); font-size: 10px;
}
.m.action.pending .action-mark { color: var(--blue); background: var(--tint); animation: actionPulse 1s ease-in-out infinite; }
.m.action.saved .action-mark { background: #19734b; }
.m.action.clarify .action-mark { background: #b26700; }
.m.action.error .action-mark { background: #b4231f; }
.m.action .action-detail { color: var(--dim); font-size: 11.5px; margin: 4px 0 0 27px; }
/* Reference shape proposal: what was read off the shot, then a real choice. */
.action-shapes { list-style: none; margin: 8px 0 0 27px; padding: 0; display: flex; flex-direction: column; gap: 3px; }
.action-shapes li { font-size: 12px; color: var(--ink); }
.action-shapes li span { color: var(--dim); }
.m.action .action-actions { display: flex; gap: 8px; margin: 10px 0 2px 27px; }
.m.action .action-actions .spec-btn { font-size: 12px; padding: 6px 12px; }
@keyframes actionPulse { 50% { opacity: .45; } }
.rail button:focus-visible,
.rail summary:focus-visible,
.rail input:focus-visible,
.rail textarea:focus-visible {
  outline: 3px solid color-mix(in oklch, var(--blue) 32%, transparent);
  outline-offset: 2px;
}
.rail textarea:focus-visible { outline-offset: 5px; }
.sugg { display: flex; gap: 6px; flex-wrap: wrap; margin-bottom: 12px; }
.sugg .chip { font-size: 11.5px; padding: 7px 10px; }
/* ---- style section — folded INSIDE the chat rail (one panel) ---- */
/* ---- design as a floating palette over the canvas ----
   The theme controls act on the screens, so they sit beside the screens.
   Freed the rail of a ~500px settings block; the conversation owns it again. */
.palette { position: fixed; right: 22px; bottom: 22px; z-index: 60; }
.palette-btn {
  display: flex; align-items: center; gap: 9px;
  background: #fff; border: 1px solid var(--line); border-radius: 999px;
  padding: 9px 17px 9px 10px; font-size: 13.5px; font-weight: 700; color: var(--ink);
  box-shadow: 0 12px 32px -10px rgba(17,17,17,.28), 0 2px 8px -2px rgba(17,17,17,.1);
  transition: transform .18s var(--ease, ease), border-color .15s, box-shadow .18s;
}
.palette-btn:hover {
  transform: translateY(-2px); border-color: var(--dim);
  box-shadow: 0 16px 40px -12px rgba(17,17,17,.34), 0 3px 10px -2px rgba(17,17,17,.12);
}
/* The disc IS the current theme: page colour one half, accent the other.
   Colours are set inline by syncPaletteDisc; `pop` replays a beat on change so
   applying a look is felt at the control, not only on the board. */
.palette-disc {
  width: 26px; height: 26px; border-radius: 999px; flex: none;
  border: 2px solid var(--line);
  background: linear-gradient(135deg, #fff 0 50%, var(--blue) 50% 100%);
}
.palette-disc.pop { animation: discPop .45s var(--ease, ease); }
@keyframes discPop {
  0% { transform: scale(1); }
  40% { transform: scale(1.28) rotate(14deg); }
  100% { transform: scale(1) rotate(0); }
}
.palette-panel {
  position: absolute; right: 0; bottom: calc(100% + 12px);
  width: 344px; max-height: min(72vh, 640px);
  display: flex; flex-direction: column;
  background: #fff; border: 1px solid var(--line); border-radius: 16px;
  box-shadow: 0 28px 70px -18px rgba(17,17,17,.35), 0 4px 16px -4px rgba(17,17,17,.12);
  transform-origin: bottom right;
  animation: paletteIn .26s cubic-bezier(.2, .9, .3, 1.15);
}
@keyframes paletteIn {
  from { opacity: 0; transform: scale(.9) translateY(10px); }
  to { opacity: 1; transform: scale(1) translateY(0); }
}
.palette-head {
  flex: none; display: flex; align-items: center; justify-content: space-between;
  padding: 13px 15px 11px; border-bottom: 1px solid var(--line-soft, var(--line));
}
.palette-head b { display: block; font-size: 13.5px; }
.palette-head small { display: block; margin-top: 1px; color: var(--dim); font-size: 11px; font-weight: 500; }
.palette-close {
  border: 0; background: none; color: var(--dim); font-size: 17px; line-height: 1;
  padding: 4px 7px; border-radius: 7px; cursor: pointer;
}
.palette-close:hover { color: var(--ink); background: var(--soft); }
.palette-body {
  flex: 1; min-height: 0; overflow-y: auto; overscroll-behavior: contain;
  padding: 13px 15px 15px; display: flex; flex-direction: column; gap: 14px;
}
/* Micro-interactions on the options themselves — scoped to the palette so the
   same renderers behave normally anywhere else. */
.palette-body .presetbtn, .palette-body .tokrow-controls > button {
  transition: transform .14s var(--ease, ease), border-color .14s, box-shadow .14s;
}
.palette-body .presetbtn:hover, .palette-body .tokrow-controls > button:hover {
  transform: translateY(-1px);
}
@media (prefers-reduced-motion: reduce) {
  .palette-panel, .palette-disc.pop { animation: none; }
  .palette-btn:hover, .palette-body .presetbtn:hover { transform: none; }
}
body.reviewing .palette, body.phoneview .palette,
.stage-generating .palette { display: none; }
.styleintro { margin: 0; color: var(--dim); font-size: 10.5px; line-height: 1.45; }
/* each group: label + a horizontal wrap of controls */
.tokrow { display: flex; flex-direction: column; align-items: stretch; gap: 7px; }
.tokrow > span { font-size: 9px; font-weight: 700; letter-spacing: .07em; text-transform: uppercase; color: var(--dim); }
.tokrow .tokrow-controls { display: flex; gap: 6px; flex-wrap: wrap; align-items: center; }
.presetgrid { display: grid !important; grid-template-columns: 1fr 1fr; }
.presetbtn {
  display: grid; grid-template-columns: 24px 1fr; gap: 8px; align-items: center;
  min-width: 0; border: 1px solid var(--line); border-radius: 9px; background: #fff;
  color: var(--ink); padding: 7px; text-align: left;
}
.presetbtn:hover { border-color: color-mix(in oklch, var(--blue) 45%, transparent); }
.presetbtn.sel { border-color: var(--ink); box-shadow: 0 0 0 1px var(--ink); }
.preset-swatch { width: 24px; height: 24px; border-radius: 7px; border: 1px solid rgba(17,17,17,.1); }
.presetbtn b { display: block; font-size: 10.5px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.presetbtn small { display: block; color: var(--dim); font-size: 9px; margin-top: 1px; }
.fontbtn { background: #fff; border: 1px solid var(--line); border-radius: 8px; min-width: 49px; height: 30px; padding: 0 7px; display: flex; align-items: center; justify-content: center; font-size: 11px; color: var(--ink); line-height: 1; transition: all .15s; }
.fontbtn:hover { border-color: color-mix(in oklch, var(--blue) 45%, transparent); }
.fontbtn.sel { border-color: var(--ink); box-shadow: 0 0 0 1px var(--ink); }
.bgsw { width: 26px; height: 26px; border-radius: 7px; border: 1px solid var(--line); padding: 0; transition: transform .15s; }
.bgsw:hover { transform: scale(1.12); }
.bgsw.sel { border-color: var(--ink); box-shadow: 0 0 0 1px var(--ink); }
.sizebtn { background: #fff; border: 1px solid var(--line); border-radius: 8px; min-width: 48px; height: 30px; padding: 0 8px; display: flex; align-items: center; justify-content: center; color: var(--ink); font-size: 10.5px; font-weight: 700; transition: all .15s; }
.sizebtn.sel { border-color: var(--ink); box-shadow: 0 0 0 1px var(--ink); }
.dot { width: 26px; height: 26px; border-radius: 13px; border: 2px solid transparent; box-shadow: inset 0 0 0 2px #fff; padding: 0; transition: transform .15s; }
.dot:hover { transform: scale(1.12); }
.dot.sel { border-color: var(--ink); }

/* ---- always-visible action composer ---- */
.vh {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0;
}
.rail-compose {
  flex: none; padding: 10px 18px 12px; border-top: 1px solid var(--line);
  background: rgba(255,255,255,.97); box-shadow: 0 -12px 24px rgba(17,17,17,.035);
}
.chatline { display: block; margin: 0; }
.chatline-in {
  display: flex; flex-direction: column; align-items: flex-start; gap: 4px;
  background: #fff; border: 1px solid var(--line); border-radius: 13px; padding: 5px 5px 5px 11px;
}
.chatline-in:focus-within { border-color: var(--blue); box-shadow: 0 0 0 3px color-mix(in oklch, var(--blue) 12%, transparent); }
.chatline-field { display: flex; align-items: flex-end; gap: 7px; width: 100%; }
/* Attach a reference image. Quiet by default — it is an occasional action next
   to the thing people do constantly (typing), so it must not compete with the
   send button for attention. Labelled rather than a bare glyph: an icon alone
   cannot say "one image, for colour and prices, never layout", and that is
   exactly what someone needs to know BEFORE they pick a file. */
.chatline-foot {
  display: flex; align-items: center; gap: 4px 8px; flex-wrap: wrap;
  width: 100%; padding: 2px 4px 1px 0;
}

/* Icon only. The label ("Add a reference") plus a standing sentence of
   explanation made an OPTIONAL action the loudest thing in the composer foot;
   the icon is the affordance, and the sentence survives as the title so it is
   there when someone hovers and gone when they do not. */
.attachref {
  flex: none; display: inline-flex; align-items: center; gap: 5px;
  height: 26px; padding: 0 9px 0 8px;
  border: 1px solid var(--line); border-radius: 999px; background: #fff;
  color: var(--dim); font-size: 12px; font-weight: 600; white-space: nowrap;
  cursor: pointer; transition: color .15s, border-color .15s, background .15s;
}
.attachref:hover { color: var(--ink); border-color: var(--dim); background: var(--soft); }
.attachref:disabled { opacity: .5; cursor: default; }
.attachref svg { flex: none; }
.boxwrap.dropping .chatbox {
  border-color: color-mix(in oklch, var(--blue) 55%, transparent);
  background: var(--tint);
}
/* Drop target feedback: the whole composer, since that is what people aim at. */
.rail-compose.dropping {
  outline: 2px dashed color-mix(in oklch, var(--blue) 55%, transparent);
  outline-offset: -4px; border-radius: 12px; background: var(--tint);
}
.edittarget {
  display: inline-flex; align-items: center; gap: 5px; flex-shrink: 0;
  background: var(--tint); color: var(--blue); border: 1px solid color-mix(in oklch, var(--blue) 35%, transparent);
  font-size: 11.5px; font-weight: 600; padding: 4px 6px 4px 9px; border-radius: 8px; white-space: nowrap;
}
.edittarget[hidden] { display: none; }
.edittarget b { font-weight: 700; }
.edittarget .x { cursor: pointer; font-size: 13px; line-height: 1; opacity: .7; padding: 0 2px; }
.edittarget .x:hover { opacity: 1; }
.chatline textarea {
  flex: 1; min-width: 0; min-height: 24px; max-height: 132px; resize: none;
  overflow-y: auto; background: none; border: none; color: var(--ink); font: inherit;
  font-size: 13.5px; line-height: 1.5; padding: 5px 0; outline: none;
}
.sendchange {
  flex: none; width: 32px; height: 32px; margin-bottom: 1px; border: none;
  border-radius: 50%; background: var(--ink); color: #fff;
  display: flex; justify-content: center; align-items: center;
  transition: transform .15s, opacity .15s;
}
.sendchange span { font-size: 16px; line-height: 1; }
.sendchange:hover { transform: translateY(-1px); }
.sendchange:disabled, .rail button:disabled { opacity: .48; cursor: wait; }
.editstatus { min-height: 13px; margin-top: 4px; color: var(--dim); font-size: 10.5px; }
.editstatus.busy { color: var(--blue); }
.colorfield {
  display: grid; grid-template-columns: 1fr 30px; align-items: center; gap: 5px 7px;
  flex: 1 1 124px; min-width: 0;
}
.colorfield > span { grid-column: 1 / -1; color: var(--dim); font-size: 10px; font-weight: 650; }
.colorfield input[type="color"] { width: 30px; height: 30px; border: 0; padding: 0; background: none; }
.colorfield input[type="text"] {
  width: 100%; min-width: 0; height: 30px; border: 1px solid var(--line); border-radius: 8px;
  padding: 0 8px; color: var(--ink); background: #fff; font: 600 10px/1 ui-monospace, monospace;
}
.colorfield input[type="text"]:focus { outline: 2px solid color-mix(in oklch, var(--blue) 25%, transparent); border-color: var(--blue); }
.stylefine { border-top: 1px solid var(--line); padding-top: 10px; }
.stylefine summary { color: var(--blue); cursor: pointer; font-size: 11px; font-weight: 700; }
.stylefine > div { display: flex; flex-direction: column; gap: 13px; padding-top: 12px; }

/* ---- share, now a dropdown in the app bar ---- */
.sharetools { position: relative; color: var(--dim); }
.sharetools summary {
  min-height: 34px; cursor: pointer; display: flex;
  align-items: center; gap: 8px; padding: 4px 11px 4px 7px; list-style: none; text-align: left;
  border: 1px solid var(--line); border-radius: 8px; background: #fff;
  transition: border-color .15s;
}
.sharetools summary::-webkit-details-marker { display: none; }
.sharetools summary:hover { border-color: var(--dim); }
.sharetools[open] summary { border-color: var(--dim); }
.sharemini { width: 20px; height: 20px; display: block; border: 1px solid var(--line); border-radius: 5px; overflow: hidden; background: #fff; }
.sharemini:empty { background: linear-gradient(135deg, #fff 50%, var(--soft) 50%); }
.sharemini svg { display: block; width: 20px; height: 20px; }
.sharecopy b { display: block; color: var(--dim); font-size: 13px; font-weight: 400; white-space: nowrap; }
.sharetools:hover .sharecopy b, .sharetools[open] .sharecopy b { color: var(--ink); }
.sharebody {
  position: absolute; right: 0; top: calc(100% + 7px); z-index: 50; width: 232px;
  padding: 12px 13px 13px; background: #fff;
  border: 1px solid var(--line); border-radius: 12px;
  box-shadow: 0 18px 40px -14px rgba(17,17,17,.28), 0 2px 8px -2px rgba(17,17,17,.1);
}
.sharehint { margin: 0 0 10px; font-size: 11px; line-height: 1.45; color: var(--dim); }
.sharelink { display: block; width: 100%; margin-top: 10px; background: none; border: 1px solid var(--line); color: var(--dim); font-size: 12.5px; padding: 9px; border-radius: 9px; transition: color .15s, border-color .15s; }
.sharelink:hover { color: var(--ink); border-color: rgba(17,17,17,.24); }
/* Sits under "Download PDF": the logo it sets is for the PDF's cover page and
   never leaves this browser. */
.sharelogo { display: block; margin-top: 8px; text-align: center; cursor: pointer; }
.sharelogo span { font-size: 11px; color: var(--dim); border-bottom: 1px dotted rgba(17,17,17,.28); }
.sharelogo:hover span { color: var(--ink); }
.canvas { flex: 1; min-width: 0; }

/* ---- narration (single crossfading line, no tick-tick chain) ---- */
.narrate { min-height: 22px; margin: 4px 0 10px; }
.nar-line {
  display: inline-block; font-size: 14px; color: var(--blue); font-weight: 600;
  opacity: 0; transform: translateY(5px); transition: opacity .28s ease, transform .28s ease;
}
.nar-line.show { opacity: 1; transform: none; }
.nar-line.done { color: var(--dim); font-weight: 500; }
.nar-bar {
  height: 2px; width: 190px; margin-top: 9px; border-radius: 1px; overflow: hidden;
  background: color-mix(in srgb, var(--blue) 14%, transparent); position: relative;
}
.nar-bar::after {
  content: ""; position: absolute; inset: 0; width: 40%;
  background: linear-gradient(90deg, transparent, var(--blue), transparent);
  animation: nar-sweep 1.15s infinite;
}
@keyframes nar-sweep { from { transform: translateX(-100%); } to { transform: translateX(260%); } }

/* ---- phones ---- */
/* styles.css also defines `.board` (column, overflow hidden) — override every
   property it sets, not just the ones we care about. */
/* Three phones across is the deliberate desktop rhythm. The stage sizing
   above guarantees the tracks fit, so centering can never pull the first
   phone back into the editor gutter. */
#phones .board {
  display: grid; grid-template-columns: repeat(auto-fit, 260px); gap: 26px 24px;
  justify-content: center; overflow: visible; min-height: 0;
}
/* Depth relationship is a per-phone caption ("Opens from Progress"), not a
   second section row — so the 5th screen stays in the same grid as the tabs. */
.opens-cap {
  font: 500 11.5px/1.35 var(--font-body, inherit); color: var(--dim);
  text-align: center; margin-top: -2px; max-width: 240px;
}

/* Screens / Try it toggle */
#phones { display: flex; flex-direction: column; align-items: stretch; }
/* The view switcher lives in the app bar now, so it is a segmented control
   inside .ab-tabs rather than a free-floating pill above the board. */
.bview {
  appearance: none; border: 0; background: transparent; cursor: pointer;
  padding: 6px 16px; border-radius: 999px;
  font: 500 13px/1 var(--font-body, inherit); color: var(--dim);
  transition: color .15s, background .15s;
}
.bview.on { background: var(--ink); color: #fff; font-weight: 600; }
.bview:hover:not(.on) { color: var(--ink); }

/* Single-phone walkthrough */
.walkthru {
  display: flex; flex-direction: column; align-items: center;
  gap: 14px; margin: 4px 0 28px; width: 100%;
}
.walk-caption {
  min-height: 1.4em; text-align: center; max-width: 320px;
  font: 500 14px/1.4 var(--font-body, inherit); color: var(--ink);
  padding: 0 12px;
}
.walk-stage { display: flex; justify-content: center; }
.walk-phone {
  width: 260px; height: 540px; position: relative; overflow: hidden;
}
.walk-controls {
  display: flex; flex-direction: column; align-items: center; gap: 8px;
}
.walk-play {
  appearance: none; border: 0; cursor: pointer;
  padding: 10px 22px; border-radius: 999px;
  background: var(--ink); color: #fff;
  font: 600 13px/1 var(--font-body, inherit);
}
.walk-play:hover { opacity: .9; }
.walk-hint {
  font: 500 11.5px/1.3 var(--font-body, inherit); color: var(--dim);
  text-align: center;
}

/* Walkthrough "not right? send it to…" */
.walk-retarget[hidden] { display: none !important; }
.walk-retarget {
  display: flex; flex-direction: column; align-items: center; gap: 8px;
  max-width: 340px; padding: 10px 12px; border-radius: 14px;
  background: color-mix(in oklch, var(--tint) 70%, #fff);
  border: 1px solid var(--line);
}
.walk-rt-label {
  font: 600 12px/1.3 var(--font-body, inherit); color: var(--ink);
}
.walk-rt-opts {
  display: flex; flex-wrap: wrap; justify-content: center; gap: 6px;
}
.walk-rt-opt {
  appearance: none; border: 1px solid var(--line); cursor: pointer;
  padding: 6px 12px; border-radius: 999px; background: #fff;
  font: 600 12px/1 var(--font-body, inherit); color: var(--ink);
}
.walk-rt-opt:hover { border-color: var(--ink); }
.walk-rt-opt.dim { color: var(--dim); font-weight: 500; }
.walk-rt-from {
  font: 500 11px/1.3 var(--font-body, inherit); color: var(--dim);
}

/* Flow map lanes (§5.3) — fixed columns, elbow connectors, horizontal scroll */
.fmap {
  display: flex; gap: 28px; align-items: flex-start;
  overflow-x: auto; padding: 8px 4px 28px; margin: 4px 0 12px;
  scroll-snap-type: x proximity;
}
.fmap-lane {
  flex: 0 0 auto; min-width: 140px; scroll-snap-align: start;
}
.fmap-lane.wide { min-width: 280px; }
.fmap-hlane {
  font: 700 11px/1.2 var(--font-body, inherit); letter-spacing: .04em;
  text-transform: uppercase; color: var(--dim); margin-bottom: 12px;
}
.fmap-body { display: flex; flex-direction: column; gap: 10px; }
.fmap-body.stack { gap: 14px; }
.fmap-row {
  display: flex; align-items: center; gap: 0; flex-wrap: nowrap;
}
.fmap-chip {
  flex: 0 0 auto; padding: 10px 14px; border-radius: 12px;
  border: 1px solid var(--line); background: #fff;
  box-shadow: 0 6px 18px -12px rgba(0,0,0,.25);
  max-width: 160px;
}
.fmap-chip.launch { border-color: color-mix(in oklch, var(--blue) 40%, var(--line)); }
.fmap-chip.depth { background: color-mix(in oklch, var(--tint) 55%, #fff); }
.fmap-chip.orphan { opacity: .85; }
.fmap-name {
  font: 600 13px/1.25 var(--font-body, inherit); color: var(--ink);
  display: block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.fmap-edge {
  display: flex; align-items: center; gap: 0; margin-left: 2px;
}
.fmap-elbow {
  width: 28px; height: 2px; background: var(--line);
  position: relative; flex: 0 0 auto;
}
.fmap-elbow::before {
  content: ""; position: absolute; right: -1px; top: -3px;
  width: 0; height: 0;
  border-top: 4px solid transparent; border-bottom: 4px solid transparent;
  border-left: 6px solid var(--line);
}
.fmap-empty { color: var(--dim); font: 500 12px/1.3 var(--font-body, inherit); }

/* Streaming slots: each screen swaps skeleton→phone independently. contents
   keeps the phone a direct flex item of .board while still giving the slot
   its own .pop-in scope (per-screen entrance, no nth-child stagger). */
.slot { display: contents; }
/* phone + its address caption ("2 · Check-ins") — tap to aim the next edit */
.phcol { display: flex; flex-direction: column; align-items: center; gap: 9px; }
.p-capt { background: none; border: 1px solid transparent; border-radius: 999px; padding: 4px 12px; font-size: 12px; font-weight: 600; color: var(--dim); transition: all .15s; }
.p-capt:hover { color: var(--ink); border-color: var(--line); }
.p-capt.sel { color: var(--blue); border-color: color-mix(in oklch, var(--blue) 45%, transparent); background: var(--tint); box-shadow: 0 6px 16px -8px var(--glow); }
.pop-in .phone { animation: pop .5s cubic-bezier(.2,.9,.3,1.2) both; }
.pop-in .phone:nth-child(2) { animation-delay: .1s; }
.pop-in .phone:nth-child(3) { animation-delay: .2s; }
.pop-in .phone:nth-child(4) { animation-delay: .3s; }
@keyframes pop { from { opacity: 0; transform: translateY(14px) scale(.97); } }
/* the hero lands last (bigger model) — give it a finale entrance */
.pop-hero .phone { animation: popHero .7s cubic-bezier(.2,.9,.25,1.18) both; }
@keyframes popHero {
  from { opacity: 0; transform: translateY(22px) scale(.9); filter: brightness(1.35); }
  60% { filter: brightness(1.12); }
  to { filter: brightness(1); }
}
/* hero slot shimmer: labeled so the wait reads as anticipation, not a miss */
.skph.hero { position: relative; }
.skherolbl { position: absolute; top: 46%; left: 0; right: 0; text-align: center; z-index: 2; font-size: 11px; font-weight: 700; color: var(--blue); animation: skheropulse 1.6s ease-in-out infinite; padding: 0 14px; }
@keyframes skheropulse { 50% { opacity: .45; } }
/* accent dot round-trip in flight: pulse the selection until the server settles */
#dots.busy .dot.sel { animation: dotbusy .7s ease-in-out infinite; }
.edit-busy .canvas button, .edit-busy .canvas [role="button"] { pointer-events: none; opacity: .68; }
@keyframes dotbusy { 50% { transform: scale(1.18); box-shadow: inset 0 0 0 2px #fff, 0 0 0 4px var(--glow); } }

/* ---- motion: the prototype feels ALIVE, not frozen ---- */
/* bars grow up on reveal */
.pop-in .p-bar { transform-origin: bottom; animation: mfGrow .8s cubic-bezier(.2,.7,.3,1) both; animation-delay: .25s; }
@keyframes mfGrow { from { transform: scaleY(.04); } }
/* line chart draws itself (pathLength=1 set in the renderer) */
.pop-in .p-line polyline { stroke-dasharray: 1; stroke-dashoffset: 1; animation: mfDraw 1.1s .25s cubic-bezier(.4,0,.2,1) forwards; }
@keyframes mfDraw { to { stroke-dashoffset: 0; } }
/* area fill + endpoint dot fade in after the line has drawn */
.pop-in .p-linefill, .pop-in .p-linedot { animation: mfShow .45s 1.15s cubic-bezier(.4,0,.2,1) backwards; }
@keyframes mfShow { from { opacity: 0; } }
/* hbars sweep in from the left, staggered (delay set inline per row) */
.pop-in .p-hbfill { transform-origin: left; animation: mfSweep .8s cubic-bezier(.2,.7,.3,1) backwards; }
@keyframes mfSweep { from { transform: scaleX(.04); } }
/* context menu pops like a real long-press */
.pop-in .p-menu { transform-origin: 50% 0; animation: mfMenuPop .38s .55s cubic-bezier(.2,.9,.3,1.15) backwards; }
@keyframes mfMenuPop { from { opacity: 0; transform: translate(-50%, 0) scale(.86); } }
/* push banner drops in from the top; payment sheet rises from the bottom */
.pop-in .p-notif { animation: mfNotifDrop .5s .7s cubic-bezier(.2,.9,.3,1.1) backwards; }
@keyframes mfNotifDrop { from { opacity: 0; transform: translateY(-16px); } }
.pop-in .p-paycard { animation: mfSheetUp .55s .5s cubic-bezier(.2,.9,.3,1.05) backwards; }
.pop-in .p-paysheet { animation: mfShow .4s .5s backwards; }
@keyframes mfSheetUp { from { transform: translateY(60%); } }
/* the active timeline dot breathes — the journey is IN PROGRESS */
.p-tlstep.active .p-tldot { animation: mfPulse 2.2s ease-in-out infinite; }
@keyframes mfPulse { 50% { box-shadow: 0 0 0 6px color-mix(in srgb, var(--p-primary) 12%, transparent); } }
/* loyalty stamps punch in one by one (delay set inline per stamp) */
.pop-in .p-stamp.on { animation: mfStampIn .32s cubic-bezier(.2,.9,.3,1.4) backwards; }
@keyframes mfStampIn { from { transform: scale(.2); opacity: 0; } }
/* heatcal cells cascade in by week column — time sweeping forward */
.pop-in .p-heatcal i { animation: mfShow .3s ease-out backwards; }
/* map routes march (dash offset loop) — the journey is happening NOW */
.pop-in .p-maphero polyline { animation: mfRouteMarch 1.1s linear infinite; }
@keyframes mfRouteMarch { to { stroke-dashoffset: -14; } }
/* photo backdrops drift slowly (Ken Burns) — imagery reads as alive */
.p-photohero .p-phimg { transform-origin: 62% 38%; }
.pop-in .p-photohero .p-phimg { animation: mfKenBurns 16s ease-in-out infinite alternate; }
@keyframes mfKenBurns { from { transform: scale(1.02) translate(0, 0); } to { transform: scale(1.1) translate(-1.6%, 1.4%); } }
/* anything that looks like a button presses like one */
.p-cta, .p-fab, .p-swbtn, .p-camdot, .p-send { transition: transform .12s ease; }
.p-cta:active, .p-fab:active, .p-swbtn:active, .p-camdot:active { transform: scale(.95); }
/* swipe card: draggable, with LIKE / NOPE stamps driven by drag */
.p-swcard { touch-action: none; cursor: grab; will-change: transform; }
.p-swcard.dragging { cursor: grabbing; transition: none; }
.p-swcard.settle { transition: transform .35s cubic-bezier(.2,.9,.3,1.2); }
.p-swcard.fly { transition: transform .3s ease-in, opacity .3s ease-in; }
.p-swstamp { position: absolute; top: 14px; font-size: 15px; font-weight: 800; letter-spacing: 1px; padding: 3px 10px; border: 2.5px solid; border-radius: 6px; opacity: 0; z-index: 4; background: rgba(255,255,255,.14); }
.p-swstamp.like { left: 12px; color: #34c759; border-color: #34c759; transform: rotate(-12deg); }
.p-swstamp.pass { right: 12px; color: #ff3b30; border-color: #ff3b30; transform: rotate(12deg); }
@media (prefers-reduced-motion: reduce) {
  .pop-in .p-bar, .pop-in .p-line polyline, .pop-in .phone,
  .pop-in .p-linefill, .pop-in .p-linedot, .pop-in .p-hbfill,
  .pop-in .p-menu, .pop-in .p-notif, .pop-in .p-paysheet,
  .pop-in .p-paycard, .p-tlstep.active .p-tldot,
  .pop-in .p-stamp.on, .pop-in .p-heatcal i,
  .pop-in .p-maphero polyline,
  .pop-in .p-photohero .p-phimg { animation: none !important; }
}

/* Shared frame. `.skph` is the loading placeholder — deliberately NOT `.phone`
   so tests and code can tell "still generating" from "real screens". */
.phone, .skph {
  width: 260px; height: 540px; border-radius: 40px; overflow: hidden;
  position: relative; flex-shrink: 0; display: flex; flex-direction: column;
}
.phone {
  background: var(--p-page); color: var(--p-fg); border: 1px solid var(--p-border);
  box-shadow: 0 30px 60px -20px rgba(0,0,0,.35), 0 10px 24px -10px rgba(0,0,0,.22);
  font-family: var(--p-body, 'Inter', -apple-system, sans-serif);
}

/* Cards can sit on a page with the opposite tone (forest-care uses a deep
   green page and white cards). Give text-on-card its own contrast-safe roles
   instead of reusing colors resolved for the page. */
.p-card, .p-stat, .p-tile, .p-swcard, .p-input, .p-notif, .p-paycard, .p-pass, .p-facepill {
  --p-mutedfg: var(--p-card-mutedfg);
  --p-primary-text: var(--p-card-primary-text);
  --p-accent-text: var(--p-card-accent-text);
}

/* Structured loading skeleton: looks like an app taking shape, not a gray slab. */
.skph {
  background: #FBFBFC; border: 1px solid var(--line);
  box-shadow: 0 18px 40px -18px rgba(17,17,17,.18);
  padding: 30px 16px 14px; gap: 12px;
}
.skph::before {
  content: "9:41"; position: absolute; top: 8px; left: 20px;
  font-size: 11px; font-weight: 600; color: #C6C8CD;
}
.skph i { display: block; background: #EEF0F3; border-radius: 8px; animation: skpulse 1.3s ease-in-out infinite; }
.skph .sk-title { height: 22px; width: 62%; border-radius: 7px; }
.skph .sk-chips { display: flex; gap: 6px; }
.skph .sk-chips i { height: 22px; width: 56px; border-radius: 12px; }
.skph .sk-card { border: 1px solid #EEF0F3; border-radius: 16px; overflow: hidden; }
.skph .sk-card i.sk-thumb { height: 52px; border-radius: 0; }
.skph .sk-card .sk-cardpad { padding: 10px; display: flex; flex-direction: column; gap: 7px; }
.skph .sk-line { height: 11px; border-radius: 5px; }
.skph .w80 { width: 80%; } .skph .w60 { width: 60%; } .skph .w40 { width: 40%; }
.skph .sk-row { display: flex; align-items: center; gap: 10px; }
.skph .sk-row i.sk-dot { width: 30px; height: 30px; border-radius: 15px; flex-shrink: 0; }
.skph .sk-row .sk-rowlines { flex: 1; display: flex; flex-direction: column; gap: 6px; }
.skph .sk-tabbar { margin-top: auto; display: flex; justify-content: space-around; padding: 10px 8px 4px; border-top: 1px solid #EEF0F3; }
.skph .sk-tabbar i { width: 20px; height: 20px; border-radius: 7px; }
.skph:nth-child(2) i { animation-delay: .18s; }
.skph:nth-child(3) i { animation-delay: .36s; }
.skph:nth-child(4) i { animation-delay: .54s; }
@keyframes skpulse { 0%, 100% { opacity: 1; } 50% { opacity: .45; } }

.p-status { height: 22px; display: flex; align-items: center; justify-content: space-between; padding: 8px 20px 0; font-size: 11px; font-weight: 600; opacity: .85; }
.p-home { position: absolute; bottom: 6px; left: 50%; transform: translateX(-50%); width: 96px; height: 4px; background: currentColor; opacity: .35; border-radius: 2px; }
.p-body { flex: 1; padding: 12px 16px 18px; display: flex; flex-direction: column; gap: 8px; overflow: hidden; position: relative; }
.p-title { font-family: var(--p-display); font-style: var(--p-display-style, normal); font-weight: var(--p-display-weight, 800); letter-spacing: var(--p-display-ls, -.4px); font-size: calc(21px * var(--p-tscale, 1)); line-height: 1.14; }
.p-label { font-family: var(--p-label); font-size: 9px; font-weight: 600; letter-spacing: 1px; text-transform: uppercase; color: var(--p-mutedfg); margin-top: 4px; }
.p-rows { display: flex; flex-direction: column; }
.p-row { display: flex; align-items: center; gap: 10px; padding: 9px 0; border-top: 1px solid var(--p-border); }
.p-row:first-child { border-top: none; }
.p-check { width: 18px; height: 18px; border-radius: 9px; border: 1.5px solid var(--p-border); flex-shrink: 0; }
.p-check.done { background: var(--p-accent); border-color: var(--p-accent); }
.p-rowlabel { flex: 1; min-width: 0; font-size: 12.5px; line-height: 1.3; display: flex; flex-direction: column; }
.p-rowlabel.done { color: var(--p-mutedfg); text-decoration: line-through; }
/* the meta line is the RECORD of the completed thing (steps, streak, time) —
   striking it through reads as cancelled data (vision-eval catch) */
.p-rowlabel.done .p-rowmeta { text-decoration: none; }
.p-rowmeta { font-size: 10px; color: var(--p-mutedfg); text-decoration: none; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.photocredit { margin-top: 14px; font-size: 11px; color: var(--dim); }
.photocredit a { color: var(--dim); text-decoration: underline; }
.photocredit a:hover { color: var(--ink); }
/* trailing value never squeezes the label out of the row or bleeds past the
   frame: fixed to its content, capped, ellipsis rather than overflow. */
.p-rowval { font-size: 12.5px; font-weight: 700; font-family: var(--p-display); font-variant-numeric: tabular-nums; flex-shrink: 0; max-width: 42%; text-align: right; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.p-chev { color: var(--p-mutedfg); font-size: 16px; }
.p-fab { margin-top: auto; align-self: flex-end; background: var(--p-primary); color: var(--p-onprimary); font-size: 12px; font-weight: 700; padding: 10px 14px; border-radius: 22px; box-shadow: 0 8px 20px -6px var(--p-primary); }
/* calendar_schedule: week strip + day slots (booked / open / blocked) */
.p-calweek { display: flex; gap: 4px; margin-top: 10px; }
.p-calday { flex: 1; display: flex; flex-direction: column; align-items: center; gap: 1px; padding: 6px 0 5px; border: 1px solid var(--p-border); border-radius: calc(var(--p-radius) * .6); }
.p-calday.active { background: var(--p-primary); border-color: var(--p-primary); box-shadow: 0 6px 16px -6px var(--p-primary); }
.p-caldow { font-family: var(--p-label); font-size: 7.5px; font-weight: 600; letter-spacing: .6px; text-transform: uppercase; color: var(--p-mutedfg); }
.p-caldate { font-size: 12px; font-weight: 700; }
.p-calday.active .p-caldow, .p-calday.active .p-caldate { color: var(--p-onprimary); }
.p-calslots { display: flex; flex-direction: column; gap: 7px; margin-top: 12px; }
.p-calslot { display: flex; align-items: stretch; gap: 8px; }
.p-caltime { width: 44px; flex-shrink: 0; font-family: var(--p-label); font-size: 9px; font-weight: 600; color: var(--p-mutedfg); padding-top: 9px; text-align: right; }
.p-calbody { flex: 1; background: var(--p-muted); border-left: 3px solid var(--p-primary); border-radius: calc(var(--p-radius) * .55); padding: 8px 10px; min-width: 0; }
.p-caltitle { font-size: 12px; font-weight: 600; line-height: 1.25; }
.p-calwho { font-size: 10.5px; color: var(--p-mutedfg); margin-top: 1px; }
.p-calslot.open .p-calbody { background: transparent; border: 1.5px dashed var(--p-border); border-left: 1.5px dashed var(--p-border); }
.p-calslot.open .p-caltitle { color: var(--p-primary-text); }
.p-calslot.blocked .p-calbody { border-left-color: var(--p-border); opacity: .55; }
/* calendar_schedule mode "pick" — the customer's time picker. Chips, not
   appointment cards: there is no `who` here by design, so a customer app can
   never render another customer's booking. */
.p-bookingfor { margin-top: 12px; padding: 9px 11px; background: var(--p-muted); border-left: 3px solid var(--p-primary); border-radius: calc(var(--p-radius) * .55); font-size: 11.5px; font-weight: 600; line-height: 1.3; }
.p-timegroups { display: flex; flex-direction: column; gap: 10px; margin-top: 12px; }
.p-timegroup { display: flex; flex-direction: column; gap: 5px; }
.p-timegrid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 5px; }
.p-timechip { font-size: 11px; font-weight: 600; padding: 7px 4px; border-radius: calc(var(--p-radius) * .55); border: 1px solid var(--p-border); text-align: center; }
.p-timechip.taken { opacity: .35; text-decoration: line-through; border-style: dashed; }
.p-timechip.sel { background: var(--p-primary); border-color: var(--p-primary); color: var(--p-onprimary); box-shadow: 0 6px 16px -6px var(--p-primary); }
.p-timegroups + .p-cta { margin-top: auto; }
.p-chips { display: flex; gap: 6px; flex-wrap: wrap; }
.p-chip { font-size: 10.5px; font-weight: 600; padding: 5px 11px; border-radius: 16px; border: 1px solid var(--p-border); color: var(--p-mutedfg); }
.p-chip.active { background: var(--p-primary); border-color: var(--p-primary); color: var(--p-onprimary); }
/* Cards must never squash to fit (mid-line text clipping): keep natural
   height and let the feed clip whole overflowing cards instead. */
.p-feed { display: flex; flex-direction: column; gap: 9px; overflow: hidden; }
.p-feed .p-card { flex-shrink: 0; }
/* "+N more" markers — appended when the render cap trims a list, so an item a
   user adds past the visible limit is never silently swallowed in the fixed-
   height preview. Deliberately muted: a hint that more exists, not a real row. */
.p-more {
  flex-shrink: 0; padding: 4px 2px 0; font-size: 10.5px; font-weight: 600;
  color: var(--p-mutedfg); opacity: .85;
}
.p-tile-more {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 0; min-height: 44px; background: transparent;
  border-style: dashed; color: var(--p-mutedfg);
}
.p-tile-more span { font-size: 15px; font-weight: 800; line-height: 1; }
.p-tile-more small { font-size: 9px; opacity: .8; }
.p-stat-more {
  flex: 0 0 auto; min-width: 30px; align-items: center; justify-content: center;
  border-style: dashed; color: var(--p-mutedfg);
  font-size: 12px; font-weight: 700;
}
.p-rows .p-row, .p-threads .p-thread { flex-shrink: 0; }
.p-card { background: var(--p-card); color: var(--p-cardfg, var(--p-fg)); border: var(--p-cardborder, 1px) solid var(--p-bordercol, var(--p-border)); border-radius: var(--p-radius); overflow: hidden; }
.p-thumb { height: 52px; }
.p-cardbody { padding: 8px 10px 9px; }
.p-cardtitle { font-size: 12.5px; font-weight: 700; display: flex; align-items: flex-start; gap: 6px; font-family: var(--p-display); }
.p-cardtt { flex: 1; min-width: 0; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; line-height: 1.2; }
/* Badge text takes the page tone so it contrasts with the accent fill on
   every pack (ink accents were rendering black-on-black). */
.p-badge { font-size: 8.5px; font-weight: 700; background: var(--p-accent); color: var(--p-onaccent); padding: 2px 6px; border-radius: 8px; text-transform: uppercase; letter-spacing: .4px; white-space: nowrap; flex-shrink: 0; margin-top: 1px; }
.p-cardsub { font-size: 10.5px; opacity: .62; margin-top: 2px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.p-cardmeta { font-size: 9.5px; color: var(--p-mutedfg); margin-top: 4px; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.p-av { border-radius: 50%; flex-shrink: 0; background: var(--p-muted); object-fit: cover; }
.p-threads { display: flex; flex-direction: column; }
.p-thread { display: flex; gap: 10px; align-items: center; padding: 9px 0; border-top: 1px solid var(--p-border); }
.p-thread:first-child { border-top: none; }
.p-threadmid { flex: 1; min-width: 0; }
.p-threadname { font-size: 12.5px; font-weight: 700; }
.p-threadprev { font-size: 11px; color: var(--p-mutedfg); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 130px; }
.p-threadright { display: flex; flex-direction: column; align-items: flex-end; gap: 4px; }
.p-threadtime { font-size: 9.5px; color: var(--p-mutedfg); }
.p-unread { min-width: 16px; height: 16px; border-radius: 8px; background: var(--p-primary); color: var(--p-onprimary); font-size: 9.5px; font-weight: 700; display: flex; align-items: center; justify-content: center; padding: 0 4px; }
.p-chathead { display: flex; gap: 8px; align-items: center; padding-bottom: 6px; border-bottom: 1px solid var(--p-border); }
.p-chatstatus { font-size: 9.5px; color: var(--p-accent-text); font-weight: 600; display: flex; align-items: center; gap: 4px; }
.p-presence { width: 6px; height: 6px; border-radius: 50%; background: #34c759; box-shadow: 0 0 0 2px color-mix(in srgb, #34c759 25%, transparent); }
/* Bottom-anchored like a real thread: when messages exceed the space, the
   hidden overflow eats the OLDEST rows at the top — never a half-clipped
   avatar/typing row at the bottom (visual-QA loop finding, 2026-07-17). */
.p-chat { flex: 1; display: flex; flex-direction: column; justify-content: flex-end; gap: 6px; overflow: hidden; padding-top: 4px; }
/* Day divider — a centered pill on a hairline, the iMessage/WhatsApp cue. */
.p-chatday { display: flex; align-items: center; gap: 8px; margin: 2px 0; }
.p-chatday::before, .p-chatday::after { content: ""; flex: 1; height: 1px; background: var(--p-border); }
.p-chatday span { font-size: 8.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .4px; color: var(--p-mutedfg); }
.p-msgrow { display: flex; gap: 6px; align-items: flex-end; }
.p-msgrow.me { justify-content: flex-end; }
.p-bubble { max-width: 75%; padding: 7px 10px; border-radius: 14px; font-size: 11.5px; line-height: 1.35; }
.p-bubble.them { background: var(--p-muted); }
.p-bubble.me { background: var(--p-primary); color: var(--p-onprimary); }
.p-msgtime { display: block; font-size: 8.5px; opacity: .6; margin-top: 3px; text-align: right; }
.p-msgrcpt { margin-left: 5px; font-weight: 700; opacity: .85; }
/* Typing indicator — three dots that pulse in sequence = the thread is alive. */
.p-typing { display: flex; gap: 3px; align-items: center; padding: 9px 11px; }
.p-typing i { width: 5px; height: 5px; border-radius: 50%; background: var(--p-mutedfg); opacity: .4; animation: p-typedot 1.2s infinite; }
.p-typing i:nth-child(2) { animation-delay: .18s; }
.p-typing i:nth-child(3) { animation-delay: .36s; }
@keyframes p-typedot { 0%, 60%, 100% { opacity: .35; transform: translateY(0); } 30% { opacity: 1; transform: translateY(-2px); } }
/* Quick-reply chips above the composer — the tap-to-answer affordance. */
.p-qrrow { display: flex; gap: 6px; flex-wrap: wrap; justify-content: flex-end; margin: 6px 0 2px; }
.p-quickreply { font-size: 10px; font-weight: 600; padding: 5px 10px; border-radius: 14px; border: 1px solid var(--p-primary); color: var(--p-primary-text); white-space: nowrap; }
.p-composer-actions { display: flex; gap: 6px; flex-wrap: wrap; margin: 6px 0 2px; }
.p-cmaction { font-size: 10px; font-weight: 600; padding: 5px 10px; border-radius: 14px; border: 1px solid var(--p-border); color: var(--p-fg); white-space: nowrap; background: var(--p-card); }
.p-composer { display: flex; align-items: center; gap: 8px; border: 1px solid var(--p-border); border-radius: 18px; padding: 8px 6px 8px 10px; font-size: 11px; color: var(--p-mutedfg); margin-top: 4px; }
.p-cmplus { font-size: 15px; color: var(--p-mutedfg); flex-shrink: 0; }
.p-cmtext { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.p-send { width: 24px; height: 24px; border-radius: 12px; background: var(--p-primary); color: var(--p-onprimary); font-size: 11px; display: flex; align-items: center; justify-content: center; flex-shrink: 0; }
.p-stats { display: flex; gap: 7px; }
.p-stat { flex: 1; background: var(--p-card); color: var(--p-cardfg, var(--p-fg)); border: var(--p-cardborder, 1px) solid var(--p-bordercol, var(--p-border)); border-radius: var(--p-radius); padding: calc(9px * var(--p-density, 1)) calc(8px * var(--p-density, 1)); display: flex; flex-direction: column; gap: 2px; }
.p-statval { font-size: calc(15px * var(--p-num-scale, 1) * var(--p-tscale, 1)); font-weight: 800; letter-spacing: -.3px; font-family: var(--p-display); font-variant-numeric: tabular-nums; line-height: .95; }
.p-statval.long { font-size: 11px; line-height: 1.25; font-weight: 700; letter-spacing: 0; }
.p-statlabel { font-family: var(--p-label); font-size: 8px; font-weight: 500; opacity: .6; text-transform: uppercase; letter-spacing: .5px; }
.p-statdelta { font-size: 9px; font-weight: 700; color: var(--p-accent-text); }
.p-formsub { font-size: 11px; color: var(--p-mutedfg); line-height: 1.4; }
.p-field { display: flex; flex-direction: column; gap: 4px; margin-top: 2px; }
.p-fieldlabel { font-family: var(--p-label); font-size: 9px; font-weight: 500; color: var(--p-mutedfg); text-transform: uppercase; letter-spacing: .6px; }
.p-input { border: 1px solid var(--p-border); background: var(--p-card); color: var(--p-cardfg, var(--p-fg)); border-radius: calc(var(--p-radius) - 6px); padding: 8px 10px; font-size: 12px; }
.p-cta { padding: 11px 16px; background: var(--p-primary); color: var(--p-onprimary); font-weight: 700; font-size: 13px; border-radius: var(--p-radius); text-align: center; }
.p-cta.secondary { background: transparent; color: var(--p-mutedfg); border: 1px solid var(--p-border); margin-top: 6px; }
.p-togglerow { display: flex; align-items: center; justify-content: space-between; padding: 9px 0; border-top: 1px solid var(--p-border); font-size: 12.5px; }
.p-togglerow:first-of-type { border-top: none; }
.p-toggle { width: 32px; height: 19px; border-radius: 10px; background: var(--p-mutedfg); position: relative; flex-shrink: 0; opacity: .4; }
.p-toggle.on { background: var(--p-accent); opacity: 1; }
.p-toggle::after { content: ""; position: absolute; top: 2px; left: 2px; width: 15px; height: 15px; background: var(--p-page-solid, #fff); border-radius: 8px; }
.p-toggle.on::after { left: 15px; }
.p-profhead { display: flex; flex-direction: column; align-items: center; gap: 5px; padding: 8px 0 4px; }
.p-profname { font-size: 16px; font-weight: 800; font-family: var(--p-display); }
.p-profsub { font-size: 10.5px; color: var(--p-mutedfg); }
.p-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.p-tile { background: var(--p-card); color: var(--p-cardfg, var(--p-fg)); border: var(--p-cardborder, 1px) solid var(--p-bordercol, var(--p-border)); border-radius: var(--p-radius); overflow: hidden; padding-bottom: 8px; }
.p-tileart { height: 44px; margin-bottom: 6px; }
.p-tiletitle { font-size: 11.5px; font-weight: 700; padding: 0 9px; }
.p-tilesub { font-size: 9.5px; opacity: .6; padding: 0 9px; margin-top: 1px; }
.p-obhero {
  height: 90px; border-radius: var(--p-radius);
  background: color-mix(in srgb, var(--p-primary) 18%, var(--p-card));
  box-shadow: inset 0 0 0 1px var(--p-border);
}
.p-obbullet { display: flex; gap: 9px; align-items: flex-start; margin-top: 7px; }
.p-obdot { width: 8px; height: 8px; border-radius: 4px; background: var(--p-accent); margin-top: 4px; flex-shrink: 0; }
.p-obtitle { font-size: 12px; font-weight: 700; }
.p-obsub { font-size: 10.5px; color: var(--p-mutedfg); }
/* swipe_deck — Tinder-style card stack */
.p-swstage { position: relative; flex: 1; margin: 6px 0 10px; min-height: 0; }
.p-swpeek { position: absolute; left: 50%; top: 8px; width: 86%; height: 92%; border-radius: 20px; background: var(--p-muted); transform: translateX(-50%); }
.p-swpeek1 { top: 14px; width: 80%; opacity: .5; }
.p-swpeek2 { top: 20px; width: 74%; opacity: .28; }
.p-swcard { position: absolute; inset: 0; background: var(--p-card); color: var(--p-cardfg, var(--p-fg)); border: 1px solid var(--p-border); border-radius: 20px; overflow: hidden; box-shadow: 0 12px 24px -12px rgba(0,0,0,.4); display: flex; flex-direction: column; }
.p-swphoto { height: 58%; flex-shrink: 0; }
.p-swbody { padding: 10px 12px; display: flex; flex-direction: column; gap: 4px; overflow: hidden; }
.p-swname { font-size: 16px; font-weight: 800; font-family: var(--p-display); }
.p-swsub { font-size: 11px; color: var(--p-mutedfg); }
.p-swtags { display: flex; gap: 5px; flex-wrap: wrap; margin: 2px 0; }
.p-swtag { font-size: 9px; font-weight: 700; padding: 3px 8px; border-radius: 10px; background: var(--p-muted); color: var(--p-mutedfg); }
.p-swblurb { font-size: 10.5px; line-height: 1.35; opacity: .75; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
/* Circle stays a fixed icon-only button; the themed label ('CAST A LIKE')
   sits BELOW it, free to wrap 1-2 lines without ever blowing out the circle. */
.p-swactions { display: flex; gap: 22px; justify-content: center; padding-bottom: 4px; }
.p-swact { display: flex; flex-direction: column; align-items: center; gap: 5px; width: 68px; }
.p-swbtn { width: 52px; height: 52px; border-radius: 26px; display: flex; align-items: center; justify-content: center; font-size: 20px; font-weight: 700; border: 1.5px solid var(--p-border); background: var(--p-card); flex-shrink: 0; }
.p-swlbl { font-size: 8px; font-weight: 700; text-transform: uppercase; letter-spacing: .3px; text-align: center; line-height: 1.2; color: var(--p-mutedfg); }
.p-swbtn.pass { color: #E5533C; }
.p-swbtn.like { color: var(--p-onprimary); background: var(--p-primary); border-color: var(--p-primary); }

/* hero_canvas layered primitives — a stage that layers board/gauge/chart with
   positioned sprite/pill/label overlays. skia-hero.js sharpens the base layers. */
/* overflow:hidden clips any overlay that a bad coordinate would push past the
   phone edge — the stage is the hard boundary, never the phone body. */
.p-canvstage { position: relative; flex: 1; min-height: 0; margin: 10px 0; overflow: hidden; }
/* scene3d: instant fallback (depth gradient + horizon grid + drifting stars)
   painted until three.js lazy-loads; then the WebGL canvas replaces it. */
.p-canvstage[data-scene3d] { border-radius: calc(var(--p-radius) - 4px); }
.p-s3dfall { background: linear-gradient(178deg, color-mix(in srgb, var(--p-page-solid) 82%, var(--p-primary)) 0%, var(--p-page-solid) 55%, color-mix(in srgb, var(--p-page-solid) 78%, var(--p-primary)) 100%); }
.p-s3dfall i { position: absolute; width: 3px; height: 3px; border-radius: 50%; background: var(--p-fg); opacity: .5; animation: s3dTwinkle 2.2s ease-in-out infinite; }
@keyframes s3dTwinkle { 50% { opacity: .15; transform: scale(.6); } }
.p-s3dhorizon { position: absolute; left: -20%; right: -20%; bottom: 0; height: 42%; background: repeating-linear-gradient(0deg, color-mix(in srgb, var(--p-primary) 35%, transparent) 0 1px, transparent 1px 12px), repeating-linear-gradient(90deg, color-mix(in srgb, var(--p-primary) 25%, transparent) 0 1px, transparent 1px 20px); transform: perspective(120px) rotateX(58deg); transform-origin: bottom; opacity: .5; }
.p-s3dcanvas { position: absolute; inset: 0; width: 100% !important; height: 100% !important; }
.p-canvstage.p-s3d-live .p-s3dfall { opacity: 0; transition: opacity .5s ease; }
@media (prefers-reduced-motion: reduce) { .p-s3dfall i { animation: none; } }

/* map hero — stylized brand map (code-drawn; no tiles) */
.p-maphero { border-radius: calc(var(--p-radius) - 4px); overflow: hidden; }
.p-maphero svg { position: absolute; inset: 0; width: 100%; height: 100%; }
.p-mapchip { position: absolute; transform: translate(-50%, -170%); z-index: 3; background: var(--p-card); color: var(--p-cardfg, var(--p-fg)); border: 1px solid var(--p-border); font-size: 8.5px; font-weight: 700; padding: 3px 8px; border-radius: 100px; white-space: nowrap; max-width: 46%; overflow: hidden; text-overflow: ellipsis; box-shadow: 0 2px 8px rgba(0,0,0,.14); }
.p-mapeta { position: absolute; top: 8px; right: 8px; z-index: 3; background: var(--p-primary); color: var(--p-onprimary); font-size: 9.5px; font-weight: 800; padding: 4px 10px; border-radius: 100px; box-shadow: 0 3px 10px -2px var(--p-primary); }
.p-maproute { position: absolute; bottom: 8px; left: 8px; z-index: 3; background: rgba(0,0,0,.55); color: #fff; font-size: 8.5px; font-weight: 700; padding: 3px 9px; border-radius: 100px; max-width: 60%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* photo hero — full-bleed image + scrim + display-type overlay */
.p-photohero { border-radius: calc(var(--p-radius) - 4px); overflow: hidden; }
.p-phimg { position: absolute; inset: 0; }
.p-phscrim { position: absolute; inset: 0; background: linear-gradient(180deg, rgba(0,0,0,0) 34%, rgba(0,0,0,.62) 100%); }
.p-phmeta { position: absolute; left: 12px; right: 12px; bottom: 11px; color: #fff; }
.p-phbadge { display: inline-block; background: var(--p-primary); color: var(--p-onprimary); font-size: 8.5px; font-weight: 800; letter-spacing: .4px; text-transform: uppercase; padding: 3px 8px; border-radius: 100px; margin-bottom: 6px; }
.p-phtitle { font-family: var(--p-display); font-style: var(--p-display-style); font-weight: var(--p-display-weight); letter-spacing: var(--p-display-ls); font-size: calc(21px * var(--p-tscale, 1)); line-height: 1.08; text-wrap: balance; text-shadow: 0 1px 10px rgba(0,0,0,.35); }
.p-phsub { font-size: 10.5px; opacity: .88; margin-top: 4px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* activity rings — concentric conic sweeps, one color per metric */
.p-rings { width: 138px; height: 138px; border-radius: 50%; display: flex; align-items: center; justify-content: center; }
.p-ring { width: 100%; height: 100%; border-radius: 50%; display: flex; align-items: center; justify-content: center; }
.p-ring .p-ring { width: calc(100% - 26px); height: calc(100% - 26px); box-shadow: 0 0 0 3px var(--p-page-solid); }
.p-ringcenter { width: calc(100% - 26px); height: calc(100% - 26px); border-radius: 50%; background: var(--p-card); display: flex; flex-direction: column; align-items: center; justify-content: center; box-shadow: 0 0 0 3px var(--p-page-solid); }
.p-ringcenter .p-dialval { font-size: 24px; }
.p-ringlegend { display: flex; gap: 12px; flex-wrap: wrap; justify-content: center; }
.p-ringkey { display: flex; align-items: center; gap: 5px; font-family: var(--p-label); font-size: 8.5px; font-weight: 600; text-transform: uppercase; letter-spacing: .5px; color: var(--p-mutedfg); }
.p-ringkey i { width: 8px; height: 8px; border-radius: 4px; }

/* calendar today-focus header */
.p-calbig { display: flex; align-items: baseline; gap: 8px; margin: 2px 0 4px; }
.p-calbig b { font-family: var(--p-display); font-style: var(--p-display-style); font-weight: var(--p-display-weight); font-size: calc(34px * var(--p-num-scale)); line-height: 1; letter-spacing: var(--p-display-ls); font-variant-numeric: tabular-nums; }
.p-calbig span { font-size: 13px; font-weight: 700; color: var(--p-primary-text); text-transform: uppercase; letter-spacing: .6px; }
.p-calbig i { font-style: normal; font-family: var(--p-label); font-size: 9px; color: var(--p-mutedfg); text-transform: uppercase; letter-spacing: .6px; margin-left: auto; }
.p-calslot .p-av { border-radius: 50%; flex-shrink: 0; align-self: center; }
.p-canvstage.square { flex: 0 1 auto; aspect-ratio: 1; }
.p-glayer { position: absolute; inset: 0; }
.p-canvstage.square .p-glayer.p-grid2 { position: relative; inset: auto; width: 100%; height: 100%; }
.p-gsprite { position: absolute; transform: translate(-50%,-50%); line-height: 1; z-index: 3; filter: drop-shadow(0 1px 2px rgba(0,0,0,.3)); }
/* Overlay pills/labels are spatial annotations: cap width and keep them inside
   the stage so a long string or high x% can't bleed off the frame. */
.p-gpill { position: absolute; transform: translate(-50%,-50%); z-index: 3; background: rgba(0,0,0,.5); color: #fff; font-size: 9.5px; font-weight: 700; padding: 3px 9px; border-radius: 100px; max-width: 62%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.p-glabel { position: absolute; transform: translateY(-50%); z-index: 3; color: var(--p-fg); font-weight: 700; font-family: var(--p-display); max-width: 60%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* hero_canvas — the app's signature screen (board / chart / dial) */
.p-gwrap { flex: 0 1 auto; display: flex; align-items: center; justify-content: center; min-height: 0; margin: 10px 0; }
.p-grid2 { display: grid; width: 100%; aspect-ratio: 1; border: 1.5px solid var(--p-border); border-radius: 8px; overflow: hidden; }
/* When Skia paints the stage background, the div BASE layers (board squares,
   gauge ring, chart bars) go transparent so the crisp Skia render shows — but
   glyphs, sprites, pills and labels stay ON TOP (system font has game unicode
   the default CanvasKit font lacks; overlays are positioned text). */
.p-canvstage.p-skia-lit .p-gcell { background: transparent !important; }
.p-canvstage.p-skia-lit .p-gcell.accent { color: #fff; }
.p-canvstage.p-skia-lit .p-dial { background: transparent !important; }
.p-canvstage.p-skia-lit .p-bar { background: transparent !important; }
.p-canvstage.p-skia-lit .p-line polyline { stroke: transparent !important; }
/* Board squares need real two-tone contrast on every theme (card/muted are
   often both near-white → invisible board). Light square = page tint, dark
   square = a color-mix toward the ink so the checker always reads. */
.p-gcell { display: flex; align-items: center; justify-content: center; font-size: 18px; line-height: 1; background: color-mix(in srgb, var(--p-primary) 5%, var(--p-card)); color: var(--p-fg); aspect-ratio: 1; }
.p-gcell.dk { background: color-mix(in srgb, var(--p-fg) 30%, var(--p-card)); }
.p-gcell.accent { background: var(--p-primary); color: var(--p-page-solid, #fff); }
.p-chartwrap { flex: 1; display: flex; flex-direction: column; justify-content: flex-end; min-height: 0; margin: 10px 0; }
.p-bars { display: flex; align-items: flex-end; gap: 8px; height: 100%; min-height: 120px; }
.p-barcol { flex: 1; display: flex; flex-direction: column; align-items: center; gap: 5px; height: 100%; justify-content: flex-end; }
.p-bar { width: 100%; background: var(--p-primary); border-radius: 5px 5px 0 0; min-height: 4px; }
.p-barlab { font-family: var(--p-label); font-size: 8px; color: var(--p-mutedfg); font-weight: 500; text-align: center; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 100%; }
.p-line { width: 100%; height: 130px; }
.p-chartlabs { display: flex; justify-content: space-between; margin-top: 6px; }
.p-chartlabs span { font-size: 8.5px; color: var(--p-mutedfg); font-weight: 600; }
.p-dialwrap { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 12px; min-height: 0; }
.p-dial { width: 150px; height: 150px; border-radius: 50%; display: flex; align-items: center; justify-content: center; }
.p-dialinner { width: 118px; height: 118px; border-radius: 50%; background: var(--p-card); display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px; }
.p-dialval { font-size: calc(30px * var(--p-num-scale, 1) * var(--p-tscale, 1)); font-weight: 800; font-family: var(--p-display); letter-spacing: -.02em; font-variant-numeric: tabular-nums; line-height: .9; }
.p-diallab { font-family: var(--p-label); font-size: 9px; color: var(--p-mutedfg); font-weight: 500; text-transform: uppercase; letter-spacing: .6px; }
.p-dialsub { font-size: 12px; color: var(--p-mutedfg); text-align: center; }
/* line-chart dressing: soft area fill under the stroke + endpoint dot */
.p-linefill { fill: var(--p-primary); opacity: .12; }

/* hbars — ranked horizontal bars (distributions: on-time stats, ratings mix,
   zone shares). Label | track | printed value; fill color set inline (verdict
   ramp or brand accent). */
.p-hbars { display: flex; flex-direction: column; justify-content: center; gap: 10px; padding: 6px 2px; }
.p-hbrow { display: flex; align-items: center; gap: 8px; }
.p-hblab { flex: 0 0 30%; font-family: var(--p-label); font-size: 9.5px; font-weight: 600; color: var(--p-fg); opacity: .78; text-align: right; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.p-hbtrack { flex: 1; height: 8px; border-radius: 4px; background: var(--p-muted); overflow: hidden; }
.p-hbfill { display: block; height: 100%; border-radius: 4px; min-width: 2px; }
.p-hbval { flex: 0 0 36px; font-size: 9.5px; font-weight: 700; color: var(--p-fg); font-variant-numeric: tabular-nums; }

/* stat band — headline numbers stacked with the hero stage (never floating) */
.p-statband { display: flex; gap: 8px; margin: 8px 0 2px; }
.p-sb { flex: 1; display: flex; flex-direction: column; gap: 1px; padding: 8px 10px; border-radius: calc(var(--p-radius) - 6px); background: var(--p-card); color: var(--p-cardfg, var(--p-fg)); }
.p-sbval { font-family: var(--p-display); font-size: calc(15px * var(--p-tscale, 1)); font-weight: 800; letter-spacing: -.02em; font-variant-numeric: tabular-nums; line-height: 1.1; }
.p-sblab { font-family: var(--p-label); font-size: 8px; color: var(--p-mutedfg); font-weight: 500; text-transform: uppercase; letter-spacing: .6px; }
.p-sbdelta { font-size: 8.5px; font-weight: 700; color: var(--p-primary-text); }

/* timeline — status-journey rail (order tracking, applications, trip legs) */
.p-timeline { display: flex; flex-direction: column; justify-content: center; padding: 6px 2px; }
.p-tlstep { position: relative; display: flex; align-items: flex-start; gap: 10px; padding: 8px 0; }
.p-tlstep::before { content: ""; position: absolute; left: 5px; top: 24px; bottom: -10px; width: 2px; background: var(--p-muted); }
.p-tlstep:last-child::before { display: none; }
.p-tldot { flex: 0 0 12px; height: 12px; margin-top: 2px; border-radius: 50%; background: var(--p-muted); z-index: 1; }
.p-tlstep.done .p-tldot { background: var(--p-primary); }
.p-tlstep.active .p-tldot { background: var(--p-page-solid, #fff); border: 3px solid var(--p-primary); box-shadow: 0 0 0 3px color-mix(in srgb, var(--p-primary) 22%, transparent); }
.p-tlbody { flex: 1; display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.p-tllab { font-size: 11px; font-weight: 700; color: var(--p-fg); }
.p-tlstep.todo .p-tllab { opacity: .5; font-weight: 600; }
.p-tlsub { font-size: 9px; color: var(--p-mutedfg); }
.p-tltrail { font-size: 9.5px; font-weight: 700; color: var(--p-primary-text); white-space: nowrap; font-variant-numeric: tabular-nums; }
.p-tlstep.todo .p-tltrail { color: var(--p-mutedfg); font-weight: 500; }

/* glass-on-imagery — backdrop photo/map with frosted cards floating over it.
   The premium composition: imagery gives atmosphere, glass gives depth, the
   lead number gives one dominant thing to look at. */
.p-canvstage.glassy { border-radius: calc(var(--p-radius) - 4px); }
.p-glstack { position: absolute; inset: 0; z-index: 2; display: flex; flex-direction: column; gap: 8px; padding: 11px; }
.p-glspace { flex: 1; }
.p-glass { border-radius: 14px; background: color-mix(in srgb, var(--p-page-solid) 52%, transparent); backdrop-filter: blur(14px) saturate(1.25); -webkit-backdrop-filter: blur(14px) saturate(1.25); border: 1px solid color-mix(in srgb, var(--p-fg) 10%, transparent); box-shadow: 0 10px 26px rgba(0,0,0,.28); padding: 10px 12px; }
/* base modules are absolute full-stage layers by default — inside a glass
   card they flow, sized by content */
.p-glass .p-glayer { position: relative; inset: auto; }
.p-glass .p-chartwrap { margin: 0; }
.p-glass .p-line { height: 74px; }
.p-glass .p-hbars { padding: 2px 0; gap: 8px; }
.p-glass .p-dialwrap { gap: 8px; }
.p-glass .p-dial { width: 108px; height: 108px; }
.p-glass .p-dialinner { width: 84px; height: 84px; }
.p-glstack .p-statband { margin: 0; }
.p-glstack .p-sb { background: color-mix(in srgb, var(--p-page-solid) 52%, transparent); backdrop-filter: blur(14px) saturate(1.25); -webkit-backdrop-filter: blur(14px) saturate(1.25); border: 1px solid color-mix(in srgb, var(--p-fg) 10%, transparent); box-shadow: 0 6px 16px rgba(0,0,0,.2); }
/* over imagery the lead reads white-on-scrim regardless of theme ink */
.p-glstack .p-sbleadval { color: #fff; text-shadow: 0 2px 14px rgba(0,0,0,.5); }
.p-glstack .p-sbleadlab { color: rgba(255,255,255,.85); text-shadow: 0 1px 8px rgba(0,0,0,.4); }
/* tiles run tighter over imagery so three abreast never crop their values */
.p-glstack .p-sb { padding: 7px 9px; min-width: 0; color: var(--p-fg); }
.p-glstack .p-sbval { font-size: calc(13.5px * var(--p-tscale, 1)); }
/* the glass cards own the bottom edge — the map's route label moves up top,
   opposite the lead so they never collide (eta already lives top-right) */
/* map backdrops need a top scrim like photos: the lead number is white-on-
   imagery, and a light pack's map (muted = near-white) leaves it unreadable
   (player QA catch, 2026-07-21). Mirrored in the RN player's MapHero. */
.glassy .p-maphero::after { content: ""; position: absolute; inset: 0; pointer-events: none; background: linear-gradient(180deg, rgba(0,0,0,.42) 0%, rgba(0,0,0,.10) 30%, rgba(0,0,0,0) 48%); }
.glassy .p-maproute { bottom: auto; top: 10px; left: auto; right: 10px; }
.glassy .p-mapeta { top: 10px; right: 10px; }
.glassy .p-mapeta + .p-maproute { top: 33px; }
/* backdrop photo: meta flips to the top (glass cards own the bottom) and the
   scrim darkens both edges so text and glass stay legible */
.glassy .p-phmeta { top: 12px; bottom: auto; }
.glassy .p-phscrim { background: linear-gradient(180deg, rgba(0,0,0,.5) 0%, rgba(0,0,0,.06) 34%, rgba(0,0,0,.02) 55%, rgba(0,0,0,.44) 100%); }

/* the lead money number — one huge figure, everything else recedes */
.p-sblead { display: flex; flex-direction: column; margin: 2px 0 4px; }
.p-sbleadval { font-family: var(--p-display); font-style: var(--p-display-style); font-weight: 800; letter-spacing: -.03em; font-size: calc(34px * var(--p-tscale, 1)); line-height: 1; font-variant-numeric: tabular-nums; }
.p-sbleadlab { font-family: var(--p-label); font-size: 9px; color: var(--p-mutedfg); font-weight: 600; text-transform: uppercase; letter-spacing: .7px; margin-top: 3px; }

/* video play affordance — a photo with play:true stands in for video */
.p-phplay { position: absolute; left: 50%; top: 44%; transform: translate(-50%, -50%); z-index: 2; width: 46px; height: 46px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 15px; padding-left: 4px; color: #fff; background: rgba(20,20,20,.42); backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px); border: 1.5px solid rgba(255,255,255,.55); box-shadow: 0 8px 22px rgba(0,0,0,.3); }

/* push banner — iOS notification dropped over the top of the screen */
.p-notif { position: absolute; top: 8px; left: 8px; right: 8px; z-index: 5; display: flex; gap: 9px; align-items: flex-start; padding: 9px 11px; border-radius: 14px; background: color-mix(in srgb, var(--p-card) 90%, transparent); backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px); box-shadow: 0 10px 28px rgba(0,0,0,.3), 0 2px 8px rgba(0,0,0,.15); }
.p-notifico { flex: 0 0 26px; height: 26px; border-radius: 7px; background: var(--p-primary); color: var(--p-onprimary); font-size: 13px; font-weight: 800; display: flex; align-items: center; justify-content: center; }
.p-notifbody { flex: 1; min-width: 0; }
.p-notiftop { display: flex; justify-content: space-between; align-items: baseline; gap: 6px; }
.p-notiftitle { font-size: 10.5px; font-weight: 800; color: var(--p-cardfg, var(--p-fg)); }
.p-notiftime { font-size: 8.5px; color: var(--p-mutedfg); flex-shrink: 0; }
.p-notiftext { font-size: 10px; color: var(--p-cardfg, var(--p-fg)); opacity: .82; line-height: 1.35; overflow: hidden; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; }

/* payment sheet — native checkout rising from the bottom (the money shot) */
.p-paysheet { position: absolute; inset: 0; z-index: 5; display: flex; flex-direction: column; justify-content: flex-end; background: linear-gradient(180deg, rgba(0,0,0,0) 30%, rgba(0,0,0,.34) 100%); border-radius: calc(var(--p-radius) - 4px); }
.p-paycard { margin: 0 6px 6px; border-radius: 16px; background: color-mix(in srgb, var(--p-card) 96%, transparent); backdrop-filter: blur(16px); -webkit-backdrop-filter: blur(16px); box-shadow: 0 -8px 32px rgba(0,0,0,.3); padding: 7px 13px 12px; }
.p-paygrab { width: 32px; height: 4px; border-radius: 2px; background: var(--p-muted); margin: 0 auto 9px; }
.p-payrow { display: flex; justify-content: space-between; align-items: baseline; gap: 8px; padding: 4px 0; }
.p-payrow.total { border-top: 1px solid var(--p-muted); margin-top: 3px; padding-top: 8px; }
.p-paylab { font-family: var(--p-label); font-size: 9px; color: var(--p-mutedfg); font-weight: 600; text-transform: uppercase; letter-spacing: .5px; }
.p-payval { font-size: 10.5px; font-weight: 600; color: var(--p-cardfg, var(--p-fg)); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.p-payamt { font-family: var(--p-display); font-size: 17px; font-weight: 800; color: var(--p-cardfg, var(--p-fg)); font-variant-numeric: tabular-nums; }
.p-paynote { font-size: 8.5px; color: var(--p-mutedfg); margin-top: 2px; }
.p-payconfirm { margin-top: 9px; display: flex; align-items: center; justify-content: center; gap: 6px; padding: 9px; border-radius: 11px; background: var(--p-fg); color: var(--p-page-solid, #fff); font-size: 10.5px; font-weight: 700; }
.p-payface { font-size: 12px; }

/* segmented control band — Day/Week/Month over a chart base */
.p-segband { display: flex; padding: 3px; border-radius: 10px; background: var(--p-muted); margin: 6px 0 2px; }
.p-seg { flex: 1; text-align: center; padding: 5px 0; font-size: 10px; font-weight: 600; color: var(--p-mutedfg); border-radius: 8px; }
.p-seg.on { background: var(--p-card); color: var(--p-cardfg, var(--p-fg)); font-weight: 700; box-shadow: 0 1px 4px rgba(0,0,0,.12); }
.p-glstack .p-segband { background: color-mix(in srgb, var(--p-page-solid) 40%, transparent); backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px); }

/* live chip — a stream/call in progress */
.p-phlive { position: absolute; top: 10px; left: 10px; z-index: 2; display: flex; align-items: center; gap: 5px; background: #d92d20; color: #fff; font-size: 9px; font-weight: 800; letter-spacing: .6px; padding: 4px 9px; border-radius: 100px; }
.p-phlive i { width: 6px; height: 6px; border-radius: 50%; background: #fff; animation: mfLivePulse 1.6s ease-in-out infinite; }
@keyframes mfLivePulse { 50% { opacity: .35; } }

/* facepill — avatar cluster + count ("+142 going") */
.p-facepill { position: absolute; transform: translate(-50%, 0); z-index: 3; display: flex; align-items: center; gap: 6px; background: var(--p-card); border: 1px solid var(--p-muted); padding: 3px 10px 3px 4px; border-radius: 100px; font-size: 9px; font-weight: 700; color: var(--p-cardfg, var(--p-fg)); box-shadow: 0 3px 10px rgba(0,0,0,.14); white-space: nowrap; }
.p-faces { display: flex; }
.p-faces .p-av { border-radius: 50%; border: 1.5px solid var(--p-card); margin-right: -7px; }
.p-faces .p-av:last-child { margin-right: 0; }

/* wallet pass — qr ticket / stamps loyalty card */
.p-passwrap { display: flex; align-items: center; justify-content: center; }
.p-pass { position: relative; width: 88%; border-radius: 16px; background: var(--p-card); color: var(--p-cardfg, var(--p-fg)); box-shadow: 0 14px 34px rgba(0,0,0,.22), 0 3px 10px rgba(0,0,0,.1); padding: 13px 14px; }
.p-passhead { margin-bottom: 9px; }
/* Every line in the pass is single-line on purpose: the card renders in a
   fixed hero-canvas box, so a wrap grows it past its bounds and the overflow
   is clipped. The 2026-08-04 vision run caught a title severed at the card's
   top edge and "7/10" cut off at the bottom. Truncating beats severing. */
.p-passtitle { font-family: var(--p-display); font-size: 15px; font-weight: 800; letter-spacing: -.01em; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.p-passsub { font-size: 9.5px; color: var(--p-mutedfg); margin-top: 1px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.p-passperf { border-top: 2px dashed var(--p-muted); margin: 0 -14px 11px; position: relative; }
.p-passperf::before, .p-passperf::after { content: ""; position: absolute; top: -7px; width: 14px; height: 14px; border-radius: 50%; background: var(--p-page-solid); }
.p-passperf::before { left: -7px; } .p-passperf::after { right: -7px; }
.p-qr { display: grid; grid-template-columns: repeat(11, 1fr); gap: 1.5px; width: 96px; margin: 0 auto; aspect-ratio: 1; }
.p-qr i { background: var(--p-muted); border-radius: 1px; }
.p-qr i.on { background: var(--p-fg); }
.p-passcode { text-align: center; font-family: ui-monospace, Menlo, monospace; font-size: 10px; font-weight: 700; letter-spacing: 2px; color: inherit; margin-top: 7px; }
.p-stampgrid { display: grid; grid-template-columns: repeat(5, 1fr); gap: 7px; padding: 2px 6px; }
.p-stamp { aspect-ratio: 1; border-radius: 50%; border: 2px dashed var(--p-muted); display: flex; align-items: center; justify-content: center; font-size: 11px; color: #fff; }
.p-stamp.on { background: var(--p-primary); border: 2px solid var(--p-primary); color: var(--p-onprimary); }
.p-passreward { text-align: center; font-size: 9.5px; font-weight: 700; color: var(--p-card-primary-text); margin-top: 9px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.p-passfields { display: flex; justify-content: space-between; gap: 8px; margin-top: 11px; }
/* flex:1 so the three columns share the width evenly and each truncates in
   its own third, instead of a long label claiming more than its share and
   pushing the last column off the card. */
.p-passfield { display: flex; flex-direction: column; gap: 1px; min-width: 0; flex: 1; }
/* "PROGRESS" in a third of the card wrapped to "PROGRE / SS", which pushed
   the value row down and off the card edge. */
.p-passflab { font-family: var(--p-label); font-size: 7.5px; color: var(--p-mutedfg); font-weight: 600; text-transform: uppercase; letter-spacing: .5px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.p-passfval { font-size: 10.5px; font-weight: 700; color: inherit; font-variant-numeric: tabular-nums; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* contribution heatmap — the streak year-view */
.p-heatwrap { display: flex; flex-direction: column; justify-content: center; gap: 6px; }
.p-heatcal { display: grid; grid-auto-flow: column; gap: 2.5px; width: 100%; }
.p-heatcal i { aspect-ratio: 1; border-radius: 2.5px; }
.p-heatcal .hc0 { background: var(--p-muted); }
.p-heatcal .hc1 { background: color-mix(in srgb, var(--p-primary) 30%, var(--p-muted)); }
.p-heatcal .hc2 { background: color-mix(in srgb, var(--p-primary) 55%, var(--p-muted)); }
.p-heatcal .hc3 { background: color-mix(in srgb, var(--p-primary) 78%, var(--p-muted)); }
.p-heatcal .hc4 { background: var(--p-primary); }
.p-heatmonths { display: flex; justify-content: space-between; }
.p-heatmonths span { font-size: 8px; color: var(--p-mutedfg); font-weight: 600; }

/* media_player — playback surface */
.p-mpart { position: relative; height: 148px; border-radius: 14px; overflow: hidden; margin-bottom: 10px; }
.p-mptitle { font-family: var(--p-display); font-size: 16px; font-weight: 800; letter-spacing: -.01em; }
.p-mpcreator { font-size: 10.5px; color: var(--p-mutedfg); margin-top: 1px; }
.p-mpcaption { font-size: 9.5px; color: var(--p-mutedfg); margin-top: 4px; font-style: italic; }
.p-scrub { position: relative; height: 4px; border-radius: 2px; background: var(--p-muted); margin-top: 10px; }
.p-scrub i { display: block; height: 100%; border-radius: 2px; background: var(--p-primary); }
.p-scrub b { position: absolute; top: 50%; transform: translate(-50%, -50%); width: 11px; height: 11px; border-radius: 50%; background: var(--p-primary); box-shadow: 0 1px 5px rgba(0,0,0,.3); }
.p-scrubtimes { display: flex; justify-content: space-between; margin-top: 4px; }
.p-scrubtimes span { font-size: 8.5px; color: var(--p-mutedfg); font-variant-numeric: tabular-nums; font-weight: 600; }
.p-transport { display: flex; align-items: center; justify-content: center; gap: 26px; margin: 8px 0 10px; font-size: 15px; color: var(--p-fg); }
.p-tplay { width: 40px; height: 40px; border-radius: 50%; background: var(--p-fg); color: var(--p-page-solid, #fff); display: flex; align-items: center; justify-content: center; font-size: 14px; }
.p-upthumb { width: 34px; height: 24px; border-radius: 6px; background: var(--p-muted); flex-shrink: 0; }

/* reel_feed — vertical short-video */
.p-reel { position: relative; flex: 1; min-height: 0; border-radius: 16px; overflow: hidden; }
.p-reelscrim { position: absolute; inset: 0; background: linear-gradient(180deg, rgba(0,0,0,.18) 0%, rgba(0,0,0,0) 30%, rgba(0,0,0,0) 55%, rgba(0,0,0,.62) 100%); }
.p-reelbadge { position: absolute; top: 10px; left: 10px; }
.p-reelrail { position: absolute; right: 9px; bottom: 14px; display: flex; flex-direction: column; gap: 13px; z-index: 2; }
.p-reelact { display: flex; flex-direction: column; align-items: center; gap: 1px; color: #fff; font-size: 15px; text-shadow: 0 1px 8px rgba(0,0,0,.5); }
.p-reelact b { font-size: 8.5px; font-weight: 700; }
.p-reelmeta { position: absolute; left: 11px; right: 52px; bottom: 12px; color: #fff; z-index: 2; }
.p-reelcreator { display: flex; align-items: center; gap: 6px; font-size: 11px; font-weight: 800; text-shadow: 0 1px 8px rgba(0,0,0,.5); }
.p-reelcreator .p-av { border-radius: 50%; border: 1.5px solid #fff; }
.p-reelcaption { font-size: 10px; line-height: 1.4; margin-top: 4px; text-shadow: 0 1px 8px rgba(0,0,0,.5); overflow: hidden; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; }
.p-reelsong { font-size: 9px; opacity: .9; margin-top: 3px; text-shadow: 0 1px 8px rgba(0,0,0,.5); }
.p-reelpeek { position: relative; height: 26px; border-radius: 12px 12px 4px 4px; overflow: hidden; margin-top: 7px; opacity: .75; }
.p-reelpeek span { position: absolute; left: 9px; top: 5px; color: #fff; font-size: 8.5px; font-weight: 700; text-shadow: 0 1px 6px rgba(0,0,0,.6); }

/* voice_call — realtime voice session (ChatGPT voice mode) */
.p-vchead { text-align: center; margin-top: 4px; }
.p-vctitle { font-family: var(--p-display); font-size: 17px; font-weight: 800; letter-spacing: -.01em; }
.p-vcstatus { display: flex; align-items: center; justify-content: center; gap: 5px; font-size: 10px; color: var(--p-mutedfg); font-weight: 600; margin-top: 3px; text-transform: capitalize; }
.p-vcdot { width: 7px; height: 7px; border-radius: 50%; background: var(--p-primary); }
.p-vcdot.listening { animation: mfLivePulse 1.4s ease-in-out infinite; }
.p-vcdot.connecting { background: var(--p-mutedfg); animation: mfLivePulse 0.8s ease-in-out infinite; }
.p-vcstage { flex: 1; min-height: 0; display: flex; align-items: center; justify-content: center; }
.p-vorb { position: relative; width: 104px; height: 104px; border-radius: 50%; background: radial-gradient(circle at 34% 28%, color-mix(in srgb, var(--p-primary) 68%, #fff) 0%, var(--p-primary) 55%, color-mix(in srgb, var(--p-primary) 62%, #000) 100%); box-shadow: 0 18px 44px color-mix(in srgb, var(--p-primary) 42%, transparent); }
.p-vorb i { position: absolute; inset: 0; border-radius: 50%; border: 1.5px solid color-mix(in srgb, var(--p-primary) 45%, transparent); animation: mfOrbRing 2.6s ease-out infinite; }
.p-vorb i:nth-child(2) { animation-delay: .85s; }
.p-vorb i:nth-child(3) { animation-delay: 1.7s; }
.p-vorb.speaking { animation: mfOrbTalk 1.1s ease-in-out infinite; }
.p-vorb.connecting { filter: saturate(.4); }
.p-vorb.connecting i { animation-duration: 1.2s; }
@keyframes mfOrbRing { from { transform: scale(1); opacity: .8; } to { transform: scale(1.55); opacity: 0; } }
@keyframes mfOrbTalk { 50% { transform: scale(1.06); } }
.p-vclines { display: flex; flex-direction: column; gap: 5px; margin: 8px 4px 0; }
.p-vcline { font-size: 11px; line-height: 1.45; color: var(--p-fg); }
.p-vcline.ai { opacity: .92; }
.p-vcline.me { color: var(--p-mutedfg); font-style: italic; }
.p-vcline:last-child { font-weight: 600; }
.p-vchint { text-align: center; font-size: 9px; color: var(--p-mutedfg); margin-top: 7px; }
.p-vcctl { display: flex; justify-content: center; gap: 18px; margin: 12px 0 4px; }
.p-vcbtn { width: 44px; height: 44px; border-radius: 50%; background: var(--p-muted); display: flex; align-items: center; justify-content: center; font-size: 15px; }
.p-vcbtn.end { background: #d92d20; color: #fff; font-weight: 800; }

/* voice-note message — waveform bubble inside chat_thread */
.p-vnote { display: flex; align-items: center; gap: 7px; font-size: 12px; }
.p-vwave { display: flex; align-items: center; gap: 1.5px; }
.p-vwave i { width: 2.5px; border-radius: 2px; background: currentColor; opacity: .75; }
.p-vdur { font-size: 9px; font-weight: 700; font-variant-numeric: tabular-nums; opacity: .8; }
.p-vcap { display: block; font-size: 9.5px; opacity: .7; margin-top: 3px; }
@media (prefers-reduced-motion: reduce) {
  .p-vorb, .p-vorb i, .p-vcdot { animation: none !important; }
}

/* context menu — iOS long-press card floating over the hero base */
.p-menu { position: absolute; z-index: 3; min-width: 46%; transform: translate(-50%, 0); border-radius: 12px; background: color-mix(in srgb, var(--p-card) 88%, transparent); backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px); box-shadow: 0 12px 32px rgba(0,0,0,.26), 0 2px 8px rgba(0,0,0,.14); overflow: hidden; }
.p-menurow { padding: 8px 12px; font-size: 10.5px; font-weight: 600; color: var(--p-cardfg, var(--p-fg)); }
.p-menurow + .p-menurow { border-top: 1px solid color-mix(in srgb, var(--p-fg) 9%, transparent); }

/* camera_capture — viewfinder / scan mock (real build = expo-camera) */
.p-camview { position: relative; flex: 1; min-height: 0; margin: 6px 0 8px; border-radius: 16px; overflow: hidden; background: linear-gradient(160deg,#2a2d34,#14161b); display: flex; align-items: flex-end; justify-content: center; }
.p-camview.scan { background: linear-gradient(160deg,#1a1c22,#0c0d11); }
.p-camgrid { position: absolute; inset: 0; background-image: linear-gradient(rgba(255,255,255,.08) 1px,transparent 1px),linear-gradient(90deg,rgba(255,255,255,.08) 1px,transparent 1px); background-size: 33.33% 33.33%; }
.p-camreticle { position: absolute; top: 50%; left: 50%; transform: translate(-50%,-50%); width: 62%; height: 42%; border: 2px solid rgba(255,255,255,.85); border-radius: 14px; box-shadow: 0 0 0 2000px rgba(0,0,0,.35); }
.p-camhint { position: relative; color: rgba(255,255,255,.9); font-size: 10.5px; font-weight: 600; margin-bottom: 12px; text-align: center; padding: 4px 10px; background: rgba(0,0,0,.4); border-radius: 10px; }
.p-camrow { display: flex; align-items: center; gap: 10px; padding: 7px 0; border-top: 1px solid var(--p-border); }
.p-camrow:first-child { border-top: none; }
.p-camthumb { width: 34px; height: 34px; border-radius: 8px; background: var(--p-muted); flex-shrink: 0; }
.p-camshutter { display: flex; flex-direction: column; align-items: center; gap: 4px; padding: 6px 0 2px; }
.p-camdot { width: 46px; height: 46px; border-radius: 50%; background: #fff; border: 3px solid var(--p-primary); }
.p-camdot.scan { background: var(--p-primary); border-color: #fff; }
.p-camshutter span { font-size: 8.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .4px; color: var(--p-mutedfg); }

/* doc_upload — file/photo slots (real build = expo-document-picker) */
.p-slot { display: flex; align-items: center; gap: 11px; padding: 10px 0; border-top: 1px solid var(--p-border); }
.p-slot:first-of-type { border-top: none; }
.p-sloticon { width: 32px; height: 32px; border-radius: 9px; border: 1.5px dashed var(--p-border); display: flex; align-items: center; justify-content: center; font-size: 15px; color: var(--p-mutedfg); flex-shrink: 0; }
.p-slot.up .p-sloticon { border-style: solid; border-color: var(--p-accent); background: var(--p-accent); color: var(--p-onaccent); }

/* 50px + 12px bottom padding keeps tab labels clear of the home-indicator
   bar (repeated "bottom nav clipped" finding across visual-QA runs). */
.p-tabbar { height: 50px; border-top: 1px solid var(--p-border); display: flex; align-items: center; justify-content: space-around; padding: 0 6px 12px; }
.p-tab { display: flex; flex-direction: column; align-items: center; gap: 2px; }
.p-tabic { width: 18px; height: 18px; color: var(--p-mutedfg); opacity: .55; }
.p-tabic svg { width: 100%; height: 100%; display: block; }
.p-tab.active .p-tabic { color: var(--p-primary-text); opacity: 1; }
.p-tablbl { font-size: 7.5px; font-weight: 700; color: var(--p-mutedfg); display: flex; align-items: center; gap: 3px; }
.tab-badge { min-width: 12px; height: 12px; padding: 0 3px; border-radius: 6px; background: var(--p-primary); color: var(--p-onprimary); font-size: 7px; font-weight: 800; line-height: 12px; text-align: center; }
.p-tab.active .p-tablbl { color: var(--p-primary-text); }

/* ---- sheet ---- */
#sheet {
  position: fixed; inset: 0; background: rgba(17,17,17,.34); backdrop-filter: blur(6px);
  display: flex; align-items: center; justify-content: center; z-index: 300; padding: 16px;
}
/* Flex, not grid: when max-height binds, flex items stretch to the card's
   resolved height, so .sheet-main's overflow-y:auto actually scrolls. A grid
   track sizes to content and just gets clipped by overflow:hidden. */
.sheetcard {
  position: relative; display: flex; align-items: stretch;
  background: #fff; border: 1px solid var(--line); border-radius: 22px;
  /* Wide so the main column fits its content without pushing "Build in
     Mistflow" below the fold — at 860px the receipt scrolled past the CTA. */
  width: min(1120px, 96vw); max-height: 92vh; overflow: hidden;
  box-shadow: 0 40px 90px -30px rgba(17,17,17,.4);
}
.sheet-close {
  position: absolute; z-index: 4; top: 12px; right: 12px; width: 44px; height: 44px;
  border: 1px solid var(--line); border-radius: 50%; background: rgba(255,255,255,.92);
  color: var(--ink); font-size: 22px; line-height: 1; box-shadow: 0 4px 12px rgba(17,17,17,.08);
}
.sheet-close:hover { background: #fff; }
.sheet-close:focus-visible { outline: 3px solid color-mix(in oklch, var(--blue) 32%, transparent); outline-offset: 2px; }
.sheet-main { flex: 1; min-width: 0; padding: 28px 30px 26px; overflow-y: auto; }

/* ---- aside: the graphic column ---- */
.sheet-aside {
  position: relative; flex: 0 0 34%; display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 20px;
  padding: 36px 28px; text-align: center;
  background:
    radial-gradient(120% 90% at 50% 8%, var(--tint) 0%, transparent 62%),
    linear-gradient(180deg, #fff 0%, var(--soft) 100%);
  border-right: 1px solid var(--line); overflow: hidden;
}
.sheet-aside::after {   /* faint iso floor-grid, echoes the hero */
  content: ""; position: absolute; inset: 0; pointer-events: none; opacity: .5;
  background-image:
    linear-gradient(60deg, transparent 49.5%, rgba(17,17,17,.045) 50%, transparent 50.5%),
    linear-gradient(-60deg, transparent 49.5%, rgba(17,17,17,.045) 50%, transparent 50.5%);
  background-size: 34px 60px;
  mask-image: radial-gradient(80% 70% at 50% 40%, #000 30%, transparent 78%);
}
.assemble { position: relative; z-index: 1; width: min(100%, 280px); display: block; }
.assemble .ag-cube {
  opacity: 0; transform: translateY(-14px) scale(.9); transform-origin: center;
  transform-box: fill-box;
  animation: agpop .5s cubic-bezier(.2,.9,.25,1) forwards; animation-delay: var(--d, 0s);
}
@keyframes agpop { to { opacity: 1; transform: translateY(0) scale(1); } }
.aside-cap { position: relative; z-index: 1; }
.aside-title {
  font-family: var(--font-head, inherit); font-weight: 700; font-size: 17px;
  color: var(--ink); letter-spacing: -.02em; margin-bottom: 4px;
}
.aside-sub { color: var(--dim); font-size: 12.5px; line-height: 1.5; }

.sheetcard h2 {
  margin: 0 0 6px; font-size: 22px; letter-spacing: -.03em;
  font-family: var(--font-head, inherit); font-weight: 700; color: var(--ink);
}
.sheetcard .lead { color: var(--dim); font-size: 14px; line-height: 1.55; margin: 0 0 14px; }
.sheetcard input {
  width: 100%; background: #fff; border: 1px solid var(--line); border-radius: 11px;
  color: var(--ink); font-size: 14px; padding: 13px 14px; outline: none; margin-bottom: 10px;
}
.sheetcard input:focus { border-color: color-mix(in oklch, var(--blue) 45%, transparent); }
.sheetcard .go {
  display: block; width: 100%; box-sizing: border-box; background: var(--ink); color: #fff;
  border: none; font-weight: 700; font-size: 15px; padding: 15px; border-radius: 12px;
  text-align: center; text-decoration: none;
  box-shadow: 0 16px 36px -10px var(--glow); transition: transform .2s var(--ease, ease);
}
.sheetcard .go:hover { transform: translateY(-1px); }
.sheetcard .go.secondary {
  background: #fff; color: var(--ink); border: 1px solid var(--line);
  box-shadow: none; font-weight: 600; font-size: 14px; padding: 13px;
}
/* "save it for later" is the escape hatch, so it starts collapsed: the main
   column stays short enough that price + CTA share the first view on a laptop. */
.sheetcard .savetoggle {
  display: flex; align-items: center; gap: 12px; width: 100%;
  background: none; border: none; padding: 0; color: var(--dim); font-size: 11.5px;
  margin: 16px 0 0; text-transform: uppercase; letter-spacing: .06em; cursor: pointer;
}
.sheetcard .savetoggle::before, .sheetcard .savetoggle::after {
  content: ""; flex: 1; height: 1px; background: var(--line);
}
.sheetcard .savetoggle:hover { color: var(--ink); }
.sheetcard .savelater { margin-top: 14px; }
.sheetcard .never { text-align: center; color: var(--dim); font-size: 11.5px; margin-top: 14px; line-height: 1.5; }
.sheetcard .lead em { font-style: normal; color: var(--ink); font-weight: 600; }
.sheetcard .okmsg { background: var(--okbg); color: var(--ok); font-size: 13px; font-weight: 600; border-radius: 10px; padding: 12px 14px; }

/* ---- two-audience bundle ratification (pre-checked, plain words) ---- */
.bundle { margin: 0 0 16px; border: 1px solid var(--line); border-radius: 12px; padding: 14px 16px; background: color-mix(in srgb, var(--line) 22%, #fff); }
.bundle-row { display: flex; align-items: flex-start; gap: 10px; font-size: 13.5px; color: var(--ink); line-height: 1.5; }
.bundle-row + .bundle-row { margin-top: 8px; }
.bundle-row b { font-weight: 700; }
.bundle-ck { flex: none; width: 18px; height: 18px; border-radius: 50%; background: var(--okbg, #e7f6ec); color: var(--ok, #1a7f45); font-size: 11px; font-weight: 800; display: inline-flex; align-items: center; justify-content: center; margin-top: 1px; }
.bundle-note { font-size: 12px; color: var(--dim); margin-top: 10px; line-height: 1.5; }

/* ---- the receipt ----
   Reads as a thermal-printed itemized quote: perforated top+bottom edges,
   mono tabular prices, and hairline dashed rules between lines. The value
   anchor resolves into honest build and live-app prices instead of a $0 claim. */
.receipt {
  --perf: 9px;               /* tear-notch radius */
  position: relative;
  background:
    repeating-linear-gradient(180deg, transparent 0 26px, rgba(17,17,17,.014) 26px 27px),
    var(--soft);
  border: 1px solid var(--line);
  border-radius: 4px;
  padding: 13px 16px 15px;
  margin: 14px 0 18px;
  font-feature-settings: "tnum" 1;
}
/* perforated tear edges — masked notches top and bottom */
.receipt::before, .receipt::after {
  content: ""; position: absolute; left: -1px; right: -1px; height: var(--perf);
  background-image: radial-gradient(circle at var(--perf) 50%, transparent calc(var(--perf) - 1px), var(--paper, #fff) var(--perf));
  background-size: calc(var(--perf) * 2) var(--perf);
  background-repeat: repeat-x;
}
.receipt::before { top: calc(var(--perf) / -2 - 1px); }
.receipt::after  { bottom: calc(var(--perf) / -2 - 1px); transform: scaleY(-1); }

.rc-head {
  display: flex; justify-content: space-between;
  font: 600 10px/1 "IBM Plex Mono", ui-monospace, monospace;
  letter-spacing: .09em; text-transform: uppercase; color: var(--dim);
  padding-bottom: 11px; margin-bottom: 3px;
  border-bottom: 1px dashed var(--line);
}
.rc-row {
  display: flex; align-items: baseline; justify-content: space-between; gap: 14px;
  padding: 8px 0; border-bottom: 1px dashed var(--line);
}
.rc-desc { min-width: 0; display: flex; flex-wrap: wrap; align-items: baseline; column-gap: 8px; row-gap: 2px; }
.rc-sku {
  flex: none; font: 600 9px/1.6 "IBM Plex Mono", ui-monospace, monospace;
  letter-spacing: .05em; color: var(--dim);
  border: 1px solid var(--line); border-radius: 3px; padding: 1px 4px;
}
.rc-label { font-size: 13.5px; font-weight: 600; color: var(--ink); letter-spacing: -.01em; }
/* The comparison rows are "the usual way" (what an agency would charge), NOT
   Mistflow's fees — testers read the dark, heavy line items as our charges.
   Mute them to grey so they read as the crossed-out reference they are, and
   let the "included"/$29 summary rows carry the visual weight. */
.rc-compare .rc-label { font-weight: 500; color: var(--dim); }
.rc-compare .rc-price { font-weight: 500; color: var(--dim); }
.rc-compare .rc-sku { opacity: .7; }
.rc-note {
  flex-basis: 100%; display: flex; align-items: center; gap: 6px;
  font-size: 11px; color: var(--dim); line-height: 1.3;
}
.rc-swatch { width: 10px; height: 10px; border-radius: 3px; border: 1px solid rgba(17,17,17,.14); box-shadow: 0 1px 2px rgba(17,17,17,.12); }
.rc-price {
  flex: none; font: 600 14px/1 "IBM Plex Mono", ui-monospace, monospace;
  color: var(--ink); font-variant-numeric: tabular-nums;
}
.rc-rule { height: 0; border-top: 2px solid var(--ink); margin: 4px 0 0; }
.rc-subtotal { padding-top: 12px; border-bottom: none; }
.rc-subtotal .rc-label { font-weight: 500; color: var(--dim); }
.rc-subtotal .rc-price s { color: var(--dim); text-decoration-thickness: 1.5px; }
.rc-total { padding: 4px 0 0; border-bottom: none; align-items: center; }
.rc-total .rc-desc { row-gap: 1px; }
.rc-total .rc-label { font-size: 15px; }
.rc-total .rc-note { flex-basis: 100%; font-size: 10.5px; color: var(--ok); }
.rc-price.rc-included {
  font-size: 14px; font-weight: 700; letter-spacing: -.01em; color: var(--ok);
}
/* "Make it real" is the one price the user actually pays — make it the hero of
   the receipt so it can't be mistaken for another cost in the stack above. */
.rc-live {
  padding: 11px 12px 9px; margin: 6px -12px 0; border-bottom: none;
  align-items: center; border-radius: 8px;
  background: color-mix(in srgb, var(--blue) 8%, transparent);
}
.rc-live .rc-label { font-size: 16px; font-weight: 700; }
.rc-live .rc-note { font-size: 10.5px; color: var(--blue); }
.rc-price.rc-plan {
  font-size: 30px; font-weight: 800; letter-spacing: -.03em; color: var(--blue);
}
.rc-price.rc-plan span {
  font-size: 11px; font-weight: 600; letter-spacing: 0; color: var(--dim);
}

/* Stack the modal on narrow screens: graphic becomes a compact banner on top. */
@media (max-width: 720px) {
  .sheetcard { flex-direction: column; width: min(440px, 94vw); }
  .sheet-aside {
    flex: none; flex-direction: row; justify-content: flex-start; text-align: left;
    align-items: center; gap: 14px; padding: 16px 22px;
    border-right: none; border-bottom: 1px solid var(--line);
  }
  .assemble { width: 84px; flex: none; }
  .aside-sub { display: none; }
  .sheet-main { flex: 1; min-height: 0; padding: 24px 24px 26px; }
  .create-main { padding: 84px 16px 64px; }
  .create-home-shell { gap: 24px; }
  #landing .create-hero-copy .kicker { margin-bottom: 10px; }
  #landing .create-hero-copy .sub {
    font-size: 15.5px; line-height: 1.42; margin-bottom: 16px;
  }
  .chatbox {
    gap: 8px; padding: 8px 8px 8px 18px; border-radius: 14px;
  }
  .chatbox input { font-size: 15.5px; padding: 13px 0; }
  .chatbox button { padding: 14px 20px; }
  .composer-pill { margin-top: 10px; }
  .cpill-opt { min-height: 44px; padding-top: 0; padding-bottom: 0; }
  .chips {
    flex-wrap: nowrap; overflow-x: auto; overflow-y: hidden;
    gap: 8px; margin-top: 12px; padding-bottom: 4px;
    justify-content: flex-start !important;
    scroll-snap-type: x proximity;
    -ms-overflow-style: none; scrollbar-width: none;
  }
  .chips::-webkit-scrollbar { display: none; }
  .chip { flex: 0 0 auto; min-height: 44px; scroll-snap-align: start; }
  .create-box-note { display: none; }
  .create-cinema-stage { min-height: 0; padding: 20px 16px 18px; border-radius: 24px; }
  .create-cinema-phones {
    min-height: 0; justify-content: flex-start; gap: 16px; overflow-x: auto;
    overflow-y: visible; padding: 0 4px 8px;
    scroll-snap-type: x mandatory;
    -ms-overflow-style: none; scrollbar-width: none;
  }
  .create-cinema-phones::-webkit-scrollbar { display: none; }
  .create-demo-phone { width: 220px; height: 456px; }
  .create-demo-phone { scroll-snap-align: center; }
  .create-demo-phone--left,
  .create-demo-phone--center,
  .create-demo-phone--right { transform: none; animation: none; }
  .create-cinema-notes { gap: 8px; margin-top: 12px; }
  .create-trust-item { padding: 22px; }
  .create-mobile-proof { padding-top: 72px; padding-bottom: 78px; }
  .create-mobile-proof .section-header { margin-bottom: 28px; }
  .create-mobile-gallery {
    display: flex; gap: 14px; overflow-x: auto; margin: 0 -16px;
    padding: 0 16px 12px; scroll-snap-type: x mandatory;
    scrollbar-width: none; -ms-overflow-style: none;
  }
  .create-mobile-gallery::-webkit-scrollbar { display: none; }
  .create-mobile-app { flex: 0 0 min(82vw, 330px); scroll-snap-align: center; }
  .create-mobile-meta { padding-top: 14px; }
  .create-mobile-meta h3 { font-size: 18px; }
  .create-mobile-proof-cta { margin-top: 30px; }
  .create-included { padding-top: 72px; padding-bottom: 78px; }
  .create-included-head { grid-template-columns: 1fr; gap: 18px; margin-bottom: 34px; }
  .create-included h2 { font-size: 38px; }
  .create-stack-showcase { min-height: 330px; }
  .create-original-animation-label { top: 20px; left: 20px; }
  .create-stack-showcase #heroAnim { width: 100%; transform: translateY(10px); }
  .create-included-list { grid-template-columns: 1fr; }
  .create-included-card { min-height: 0; padding: 20px; }
  .create-endcap { padding-top: 64px; padding-bottom: 72px; }
  .create-endcap-actions { width: 100%; }
  .create-endcap-actions .btn-pill { width: 100%; justify-content: space-between; }
}

@media (prefers-reduced-motion: reduce) {
  .assemble .ag-cube { animation: none; opacity: 1; transform: none; }
  .sheetcard .go { transition: none; }
  .m.action.pending .action-mark { animation: none; }
  .rail button, .rail summary { transition: none; }
}

@media (max-width: 1180px) {
  /* Below 3-across width, reflow instead of overflowing toward the editor. */
  #phones .board { grid-template-columns: repeat(auto-fit, 260px); }
  .create-cinema-stage { min-height: 560px; padding: 40px 28px 30px; }
  .create-demo-phone--left { transform: translateY(36px) rotate(-6deg) scale(.88); }
  .create-demo-phone--center { transform: translateY(0) scale(1); }
  .create-demo-phone--right { transform: translateY(40px) rotate(6deg) scale(.9); }
  .create-trust-item h2 { font-size: 22px; }
}
@media (max-width: 900px) {
  .create-main { padding-top: 88px; }
  .create-home-shell { gap: 30px; }
  .create-hero-grid { grid-template-columns: 1fr; }
  .create-hero-copy { padding-top: 0; }
  #landing h1 { font-size: 48px; }
  #landing .section-title { font-size: 34px; }
  #landing .create-hero-copy .sub,
  #landing .create-hero-copy .boxwrap { max-width: 100%; }
  .create-cinema-stage { min-height: 0; padding: 24px 22px 22px; border-radius: 26px; }
  .create-cinema-phones {
    min-height: 0; justify-content: flex-start; gap: 18px; overflow-x: auto;
    overflow-y: visible; padding: 0 12px 10px;
    scroll-snap-type: x mandatory;
    -ms-overflow-style: none; scrollbar-width: none;
  }
  .create-cinema-phones::-webkit-scrollbar { display: none; }
  .create-demo-phone { width: 236px; height: 490px; }
  .create-demo-phone { scroll-snap-align: center; }
  .create-demo-phone--center { order: 1; }
  .create-demo-phone--right { order: 2; }
  .create-demo-phone--left { order: 3; }
  .create-demo-phone--left,
  .create-demo-phone--center,
  .create-demo-phone--right { transform: none; animation: none; }
  .create-cinema-notes { gap: 8px; }
  .create-trust-strip { grid-template-columns: 1fr; }
  .create-mobile-gallery { grid-template-columns: 1fr 1fr; }
  .create-mobile-app:last-child { grid-column: 1 / -1; max-width: calc(50% - 9px); margin: 0 auto; }
  .create-included-head { grid-template-columns: 1fr; gap: 20px; }
  .create-included-head > p:last-child { max-width: 680px; }
  .create-included h2 { font-size: 46px; }
  .create-stack-showcase { min-height: 480px; }
  .create-included-list { grid-template-columns: 1fr 1fr; }
  .create-journey-intro { grid-template-columns: 1fr; gap: 22px; }
  .create-journey-intro h2 { font-size: 50px; }
  .create-journey-intro > p { max-width: 680px; }
  .create-journey-prompt p { font-size: 22px; }
  .create-journey-stage { grid-template-columns: 1fr; min-height: 0; }
  .create-journey-copy { border-right: 0; border-bottom: 1px solid #cbd9e7; }
  .create-journey-link { margin-top: 24px; }
  .create-journey-visual { min-height: 680px; }
  .create-handoff-inner { grid-template-columns: 1fr; gap: 48px; }
  .create-handoff-copy { max-width: 680px; }
  .create-handoff-copy h2 { font-size: 50px; }
  .create-handoff-visual { width: 100%; max-width: 680px; box-sizing: border-box; }
  .create-studio-card { grid-template-columns: 1fr; align-items: start; gap: 28px; }
  .create-studio-link { justify-self: start; }
  .create-endcap-inner { flex-direction: column; align-items: flex-start; }
  .create-endcap h2 { font-size: 38px; }
  .create-endcap-actions { justify-content: flex-start; }
}

@media (max-width: 720px) {
  .create-mobile-gallery { display: flex; }
  .create-mobile-app:last-child { max-width: none; margin: 0; }
  #landing h1 { font-size: 34px; }
  #landing .section-title { font-size: 30px; }
  .create-included h2 { font-size: 38px; }
  .create-included-head > p:last-child { font-size: 15px; }
  .create-stack-showcase { min-height: 330px; }
  .create-included-list { grid-template-columns: 1fr; }
  .create-included-card { min-height: 0; padding: 20px; }
  .create-journey { padding-top: 76px; padding-bottom: 84px; }
  .create-journey-intro { margin-bottom: 34px; }
  .create-journey-intro h2 { font-size: 38px; }
  .create-journey-intro > p { font-size: 15px; }
  .create-journey-copy { padding: 28px 22px 26px; }
  .create-journey-prompt { padding-bottom: 22px; }
  .create-journey-prompt p { font-size: 18px; }
  .create-journey-steps { display: grid; grid-template-columns: 1fr 1fr; margin-top: 18px; }
  .create-journey-step {
    display: block; min-height: 112px; padding: 16px 12px 15px 0;
  }
  .create-journey-step:nth-child(even) { padding-left: 14px; border-left: 1px solid #d8e2ec; }
  .create-journey-step > span:first-child { display: block; margin-bottom: 8px; }
  .create-journey-step b { font-size: 13px; line-height: 1.3; }
  .create-journey-step small { display: none; }
  .create-journey-link { padding-top: 14px; }
  .create-journey-visual { min-height: 592px; }
  .create-journey-caption { top: 20px; left: 20px; }
  .create-journey-phone { width: 262px; height: 536px; border-radius: 38px; }
  .create-journey-screen { padding: 18px 18px; }
  .create-journey-screen h3 { font-size: 24px; }
  .journey-appbar { margin-bottom: 18px; }
  .journey-muted { margin-bottom: 17px; }
  .journey-class { padding: 11px 0; }
  .journey-streak { margin-top: 12px; }
  .journey-live-mark { margin-top: 27px; }
  .journey-change { margin-top: 14px; padding: 10px 12px; }
  .create-handoff { padding-top: 76px; padding-bottom: 84px; }
  .create-handoff-inner { gap: 38px; }
  .create-handoff-copy h2 { font-size: 38px; }
  .create-handoff-copy > p:not(.create-handoff-label) { font-size: 15px; }
  .create-handoff-benefits { display: grid; gap: 11px; margin: 24px 0 26px; }
  .create-handoff-visual { padding: 18px; }
  .create-handoff-project { padding: 14px; }
  .create-handoff-context span { padding: 11px 10px; font-size: 9px; }
  .create-handoff-editors > div { gap: 9px; padding: 12px; }
  .create-editor-mark { width: 34px; height: 34px; }
  .create-studio { padding-top: 64px; padding-bottom: 64px; }
  .create-studio-card { padding: 28px 24px; }
  .create-studio-card h2 { font-size: 30px; }
  .create-studio-link { width: 100%; box-sizing: border-box; }
  .create-endcap h2 { font-size: 32px; }
}

@media (max-width: 420px) {
  .create-handoff-editors { grid-template-columns: 1fr; }
  .create-handoff-editors strong { white-space: normal; }
}

@media (prefers-reduced-motion: reduce) {
  .create-hero-copy > .kicker,
  .create-hero-copy > h1,
  .create-hero-copy > .sub,
  .create-hero-copy > .boxwrap,
  .create-hero-cinema { animation: none; }
  .create-motion-ready .create-reveal { opacity: 1; transform: none; transition: none; }
  .create-mobile-art img,
  .create-mobile-arrow,
  .create-included-card,
  .create-journey-screen,
  .create-journey-link span,
  .create-handoff-link span,
  .create-studio-link span { transition: none; }
  .create-journey-step[aria-selected="true"]::after,
  .journey-build-progress span { animation: none; transform: scaleX(1); }
}

@media (max-width: 760px) {
  .stagegrid { grid-template-columns: 1fr; gap: 32px; }
  .rail { width: 100%; height: min(76dvh, 680px); min-height: 520px; position: static; }
}

@media (pointer: coarse) {
  .sugg .chip, .scope-clear, .sharetools summary, .stylefine summary {
    min-height: 44px; display: inline-flex; align-items: center;
  }
  .dot, .bgsw { width: 44px; height: 44px; border-radius: 12px; }
  .fontbtn, .sizebtn { min-width: 52px; height: 44px; }
  .colorfield input[type="color"] { width: 44px; height: 44px; }
  .colorfield input[type="text"] { height: 44px; font-size: 12px; }
  .sendchange { width: 42px; height: 42px; }
}

@media (min-width: 761px) and (max-width: 980px) {
  .stagegrid { grid-template-columns: minmax(300px, 320px) minmax(0, 1fr); gap: 32px; }
  .railhead { padding-left: 15px; padding-right: 15px; }
  .scopebar { margin-left: 15px; margin-right: 15px; }
  .rail-scroll, .rail-compose { padding-left: 15px; padding-right: 15px; }
}

/* ============================================================
   QR + PHONE VIEWER
   The share link (?p=<token>) opened on a phone. Everything below
   exists to answer one question with the finger, not the eye:
   "does this thing respond when I touch it?" A prototype that
   looks perfect and taps dead reads as a picture, so press
   feedback and slide transitions are load-bearing, not polish.
   ============================================================ */

/* --- QR block on the desktop stage --------------------------- */
.qrbox {
  display: flex; align-items: center; gap: 12px;
  margin-top: 12px; padding: 12px;
  border: 1px solid var(--line); border-radius: 14px;
  background: var(--card, #fff);
}
.qrbox svg { display: block; border-radius: 6px; flex: none; }
.qrbox-txt { font-size: 12px; line-height: 1.45; color: var(--muted, #666); min-width: 0; }
.qrbox-txt b { display: block; font-size: 12.5px; color: var(--fg, #111); margin-bottom: 2px; }

/* --- Phone viewer (read-only, full-bleed) -------------------- */
/* Scale, never reflow: the renderers are tuned to a 260x540 frame with fixed
   px type, so re-laying-out at native width would render everything tiny.
   transform:scale keeps proportions and typography intact. */
body.phoneview {
  margin: 0; background: var(--pv-bg, #0b0b0c);
  overflow: hidden; height: 100%;
}
html:has(body.phoneview) { overflow: hidden; height: 100%; }
/* The site chrome is injected by nav.js / footer.js AFTER this stylesheet, so
   these have to match the real emitted class names (.site-footer, not
   .sitefooter) or the footer keeps 900px of marketing copy under the frame. */
body.phoneview nav, body.phoneview .site-footer, body.phoneview .sitefooter,
body.phoneview footer, body.phoneview .cookie-consent,
body.phoneview #landing, body.phoneview .rail, body.phoneview .appbar,
body.phoneview .narrate, body.phoneview .review,
body.phoneview #sheet, body.phoneview .lb { display: none !important; }
body.phoneview .create-main { padding: 0; max-width: none; }
body.phoneview #stage { display: block; }
body.phoneview .stagegrid { display: block; }
body.phoneview .canvas { padding: 0; }

.pv-wrap {
  position: fixed; inset: 0; display: flex;
  align-items: center; justify-content: center; overflow: hidden;
}
.pv-stage { position: relative; width: 260px; height: 540px; transform-origin: center center; }
/* Screens sit stacked; only the active one is on-screen. */
.pv-screen {
  position: absolute; inset: 0;
  transition: transform .28s cubic-bezier(.22,.61,.36,1);
  will-change: transform;
}
.pv-screen.is-left { transform: translateX(-106%); }
.pv-screen.is-right { transform: translateX(106%); }
.pv-screen.is-active { transform: translateX(0); }
/* Phone view IS the app, not a picture of a phone. The real device supplies
   the frame, corners and status bar — drawing our own (rounded frame, fake
   9:41, drop shadow, neighbor peeking at the edge) reads as a mockup viewer.
   Frameless + edge-to-edge + letterbox blended into the app's own bg. */
.pv-wrap .phone { box-shadow: none; border-radius: 0; border: none; }
.pv-wrap .p-status { display: none; }
/* The frame owns the whole viewport, so drop the desktop caption + column. */
.pv-wrap .phcol { display: block; }
.pv-wrap .p-capt { display: none; }

/* Press feedback: any element that LOOKS tappable must answer the finger,
   even when it navigates nowhere. This is the single biggest contributor to
   "feels like an app" vs "feels like a screenshot". */
.pv-wrap .pv-press {
  transform: scale(.97);
  filter: brightness(.94);
  transition: transform .09s ease, filter .09s ease;
}

/* Dead-tap CTA: the prototype's one honest weakness turned into the pitch. */
/* Sits ABOVE the frame's bottom edge, not at the viewport bottom: at the
   viewport bottom it lands on top of the tab bar, which is both unreadable and
   covers the thing the user is trying to tap. --pv-inset is set from the
   measured frame rect after scaling. */
.pv-cta {
  position: fixed; left: 50%; bottom: var(--pv-cta-bottom, 22px);
  transform: translateX(-50%) translateY(8px);
  max-width: min(88vw, 340px); text-align: center;
  display: flex; align-items: center; gap: 8px;
  padding: 10px 16px; border-radius: 100px;
  background: rgba(17,17,17,.92); color: #fff;
  font: 600 13px/1.2 system-ui, -apple-system, sans-serif;
  text-decoration: none; box-shadow: 0 8px 30px rgba(0,0,0,.35);
  opacity: 0; pointer-events: none;
  transition: opacity .22s ease, transform .22s ease;
  z-index: 40;
}
.pv-cta.show { opacity: 1; transform: translateX(-50%) translateY(0); pointer-events: auto; }

@media (prefers-reduced-motion: reduce) {
  .pv-screen, .pv-wrap .pv-press, .pv-cta { transition: none; }
}

/* --- flip chips (the play layer) ------------------------------------------
   A tappable alternative under each screen. Deliberately small and quiet: it
   should read as "you can change this" without competing with the phone. */
.fliprow {
  display: flex; justify-content: center; align-items: center; gap: 6px;
  margin-top: 6px; flex-wrap: wrap;
}
.fliprow.busy { opacity: .5; pointer-events: none; }
.fliplabel { font: 650 9px/1 var(--font-body, inherit); color: var(--dim); text-transform: uppercase; letter-spacing: .06em; }
.fliptrack { display: inline-flex; gap: 2px; padding: 2px; border-radius: 100px; background: var(--soft); border: 1px solid var(--line); }
.flipopt {
  font: 500 11px/1 var(--font-body, inherit);
  min-height: 26px; padding: 5px 10px; border-radius: 100px;
  border: 0; background: transparent;
  color: var(--muted, #666); cursor: pointer;
  transition: background .15s ease, color .15s ease, border-color .15s ease;
}
.flipopt:hover { color: var(--fg, #111); background: rgba(255,255,255,.7); }
/* The active shape is the user's current choice, not a disabled state. */
.flipopt.on {
  background: var(--fg, #111);
  color: var(--bg, #fff); cursor: default;
}
@media (prefers-reduced-motion: reduce) { .flipopt { transition: none; } }

/* ============================================================
   WEB SURFACE — browser-frame prototypes
   The frame says "browser"; the skeletons say "your app". A mac
   window is to a web app what the 9:41 bar is to an iPhone app:
   instant shorthand, no label needed. Deliberately minimal — no
   tabs, no browser branding, no menu bar or dock, because those
   turn a prototype into a screenshot of someone's desktop.
   ============================================================ */
/* `.web` covers the STREAMING phase, where the board holds shimmer slots and
   no .browser exists yet for :has() to match. Without it a web build spent its
   whole generation in 260px phone-shaped slots and then jumped. */
#phones .board:has(.browser), #phones .board.web { grid-template-columns: repeat(auto-fit, 720px); }
/* The shimmer has to be BROWSER-shaped, not just browser-tall. This overrode
   height and the status-bar text but inherited `width: 260px` and the 40px
   phone radius from `.phone, .skph`, so a web generation showed a column of
   narrow rounded boxes in a 720px grid — unmistakably phones — for the whole
   30s of generation, then snapped to browser frames at the end. The final
   state was right, which is exactly why it read as "web still gives me
   mobile": the part people actually watch was wrong. Same failure the stream
   renderer fixed for the REAL frames; the placeholder was left behind. */
#phones .board.web .skph {
  width: 720px; height: 520px; border-radius: 10px; padding: 34px 22px 18px;
}
#phones .board.web .skph::before { content: "www"; letter-spacing: .06em; }
.wcol { display: flex; flex-direction: column; align-items: center; }
/* 720x520 ~= a 16:11 browser window. Height is generous on purpose: an
   admin_dashboard is stats + a section label + four table rows + a CTA, and a
   shorter frame clips the CTA mid-element, which reads as a rendering bug
   rather than a page that scrolls. */
.browser {
  width: 720px; height: 520px; display: flex; flex-direction: column;
  border-radius: 10px; overflow: hidden;
  background: var(--p-page, #fff); color: var(--p-fg, #111);
  border: 1px solid var(--p-border, #e5e7eb);
  box-shadow: 0 18px 50px rgba(0,0,0,.16);
  font-family: var(--p-body, system-ui);
}
/* Top bar: three muted traffic lights + the app's own invented address. The
   URL pill is the "live URL" promise, rendered before the user asks for it. */
.w-chrome {
  display: flex; align-items: center; gap: 6px;
  padding: 9px 12px; flex: none;
  background: var(--p-card, #f6f7f9);
  border-bottom: 1px solid var(--p-border, #e5e7eb);
}
.w-dot { width: 10px; height: 10px; border-radius: 50%; background: var(--p-muted, #d3d6dc); flex: none; }
.w-dot:nth-child(1) { background: #e5837c; }
.w-dot:nth-child(2) { background: #e3bd75; }
.w-dot:nth-child(3) { background: #86c08b; }
.w-url {
  flex: 1; margin-left: 8px; text-align: center;
  font-size: 11px; color: var(--p-mutedfg, #8b8f98);
  background: var(--p-page, #fff); border-radius: 100px;
  padding: 4px 12px; max-width: 260px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.w-shell { flex: 1; display: flex; min-height: 0; }
/* Sidebar nav — the web-ness comes from HERE (and the skeletons), not the frame */
.w-side {
  width: 168px; flex: none; padding: 14px 10px;
  background: var(--p-card, #f6f7f9);
  border-right: 1px solid var(--p-border, #e5e7eb);
  display: flex; flex-direction: column; gap: 2px;
}
.w-brand {
  font-family: var(--p-display, inherit); font-weight: 700; font-size: 14px;
  padding: 0 8px 12px; color: var(--p-fg, #111);
}
.w-navitem {
  display: flex; align-items: center; gap: 8px;
  padding: 7px 8px; border-radius: 6px;
  font-size: 12px; color: var(--p-mutedfg, #6b7280);
}
.w-navitem.active { background: var(--p-primary, #111); color: var(--p-onprimary, #fff); }
.w-navic { width: 14px; height: 14px; display: flex; opacity: .85; }
.w-navic svg { width: 100%; height: 100%; }
/* Clip like a real viewport: a dashboard with more rows than fit should look
   scrolled-off at the fold, never spill past the window edge into the board. */
.w-main {
  flex: 1; min-width: 0; min-height: 0;
  padding: 18px 20px; overflow: hidden;
  display: flex; flex-direction: column;
}
.w-main > .w-table { display: table; }
/* Web density: the shared phone renderers must stop reading as a stretched
   phone. Feeds and tiles use the width; reading surfaces cap at a column;
   CTAs become inline buttons instead of full-width mobile bars. */
.w-main .p-title { font-size: 22px; }
.w-main .p-feed { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; align-content: start; }
.w-main .p-grid { grid-template-columns: repeat(4, 1fr); gap: 10px; }
.w-main .p-stats, .w-main .p-statband, .w-main .p-hbars, .w-main .p-timeline,
.w-main .p-threads, .w-main .p-rows, .w-main .p-chat, .w-main .p-calweek { max-width: 560px; }
.w-main .p-calslots { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; max-width: none; }
.w-main .p-cta, .w-main .p-fab { align-self: flex-start; padding: 9px 22px; }
.w-main .p-mpart { max-width: 460px; }
.w-toprow { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.w-h1 { font-family: var(--p-display, inherit); font-weight: 700; font-size: 18px; margin-bottom: 12px; }
.w-toprow .w-h1 { margin-bottom: 0; }
.w-seclbl {
  font-size: 10px; letter-spacing: .08em; text-transform: uppercase;
  color: var(--p-mutedfg, #8b8f98); margin: 16px 0 6px;
}
/* KPI tiles — wide-format stat row, the console's first fold */
.w-stats { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; margin-bottom: 4px; }
.w-stat {
  border: 1px solid var(--p-border, #e5e7eb); border-radius: 8px;
  padding: 10px 12px; background: var(--p-card, #fff);
  --p-mutedfg: var(--p-card-mutedfg); --p-primary-text: var(--p-card-primary-text);
}
.w-statval { font-family: var(--p-display, inherit); font-weight: 700; font-size: 20px; font-variant-numeric: tabular-nums; }
.w-statlbl { font-size: 10.5px; color: var(--p-mutedfg, #8b8f98); margin-top: 1px; }
.w-statdelta { font-size: 10px; color: var(--p-primary-text, #111); margin-top: 3px; font-weight: 600; }
/* The dense roster table — the shape a phone frame simply cannot hold */
.w-table { width: 100%; border-collapse: collapse; font-size: 12px; }
.w-table th {
  text-align: left; font-size: 10px; letter-spacing: .06em; text-transform: uppercase;
  color: var(--p-mutedfg, #8b8f98); font-weight: 600;
  padding: 6px 8px; border-bottom: 1px solid var(--p-border, #e5e7eb);
}
.w-table td { padding: 8px; border-bottom: 1px solid var(--p-border, #eef0f3); vertical-align: top; }
/* "+N more" table row — muted, borderless: a hint that more records exist, not
   a real data row. Mirrors the phone list ".p-more" affordance. */
.w-morerow td { border-bottom: none; padding: 6px 8px 2px; font-size: 10.5px; font-weight: 600; color: var(--p-mutedfg, #8b8f98); opacity: .85; }
.w-cellmain {
  display: flex; align-items: center; gap: 8px; font-weight: 600;
}
.w-rowthumb {
  flex: 0 0 28px; width: 28px; height: 28px; border-radius: 6px;
  background: var(--p-border, #e5e7eb) center/cover no-repeat;
}
.w-cellsub { display: block; font-weight: 400; font-size: 10.5px; color: var(--p-mutedfg, #8b8f98); margin-top: 1px; }
.w-cellval { font-variant-numeric: tabular-nums; text-align: right; white-space: nowrap; }
.w-badge {
  display: inline-block; font-size: 10px; font-weight: 600; padding: 2px 8px;
  border-radius: 100px; background: var(--p-muted, #eef0f3); color: var(--p-fg, #111);
  /* Status text is model-written and occasionally long ("needs action"); let it
     wrap inside the pill rather than spill past the table's right edge. */
  max-width: 100%; white-space: normal; line-height: 1.25; text-align: center;
}
/* The status column is the last one and should stay narrow — the main cell is
   what deserves the space. */
.w-table td:last-child, .w-table th:last-child { width: 1%; white-space: nowrap; }
.w-table td:last-child { white-space: normal; }
.w-search {
  font-size: 11.5px; color: var(--p-mutedfg, #8b8f98);
  border: 1px solid var(--p-border, #e5e7eb); border-radius: 6px;
  padding: 7px 10px; margin: 10px 0 12px; background: var(--p-page, #fff);
}
.w-cta {
  display: inline-block; font-size: 11.5px; font-weight: 600;
  background: var(--p-primary, #111); color: var(--p-onprimary, #fff);
  padding: 7px 14px; border-radius: 6px; margin-top: 12px;
}

/* ---- master-detail: the list and the open record, side by side -------------
   The shape a phone cannot draw. Both panes must be visible at once or it is
   just a list; the grid is the whole point of the skeleton. */
.w-split { display: grid; grid-template-columns: minmax(0, 38%) minmax(0, 1fr); gap: 0; margin-top: 10px; }
.w-splitlist { border-right: 1px solid var(--p-border, #e5e7eb); padding-right: 12px; }
.w-splitrow {
  display: flex; align-items: flex-start; justify-content: space-between; gap: 8px;
  padding: 8px 8px 8px 9px; border-radius: 6px; font-size: 11.5px;
  border-left: 2px solid transparent;
}
.w-splitrow.on {
  background: var(--p-muted, #eef0f3);
  border-left-color: var(--p-primary, #111);
}
/* Model-written record titles run long ("CS-1842 — Duplicate charge after plan
   change"), and an un-clamped one wrapped to three lines and pushed the list
   taller than the detail pane beside it. Clamp both lines; the detail pane is
   where the full text lives. */
.w-splitmain { display: block; font-weight: 600; color: var(--p-fg, #111); min-width: 0; }
.w-splitmain, .w-splitsub {
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden;
}
.w-splitsub { font-weight: 400; font-size: 10.5px; color: var(--p-mutedfg, #8b8f98); margin-top: 2px; }
/* Never let a status pill squeeze the title it sits beside. */
.w-splitrow .w-badge { flex: none; max-width: 34%; font-size: 9.5px; padding: 2px 6px; }
.w-splitdetail { padding-left: 18px; min-width: 0; }
.w-splittitle { font-size: 15px; font-weight: 700; color: var(--p-fg, #111); letter-spacing: -.01em; }
.w-splitfield {
  display: flex; justify-content: space-between; gap: 12px;
  padding: 8px 0; border-bottom: 1px solid var(--p-border, #e5e7eb); font-size: 11.5px;
}
.w-splitflbl { color: var(--p-mutedfg, #8b8f98); }
.w-splitfval { color: var(--p-fg, #111); font-weight: 600; text-align: right; }

/* ---- board: stages side by side -------------------------------------------
   Several columns visible at once is what makes it read as a pipeline. */
/* Four stages inside a 720px browser mock leaves ~120px a column, so every
   piece of text here has to survive being narrow: the stage label truncates
   rather than wrapping under its own count, and card titles clamp instead of
   growing the column to three lines of one ticket subject. */
.w-board { display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); gap: 7px; margin-top: 12px; }
.w-bcol { background: var(--p-muted, #f6f7f9); border-radius: 8px; padding: 8px 7px 10px; min-width: 0; }
.w-bcolhead {
  display: flex; align-items: baseline; justify-content: space-between; gap: 5px;
  font-size: 9.5px; font-weight: 700; letter-spacing: .03em; text-transform: uppercase;
  color: var(--p-mutedfg, #8b8f98); margin-bottom: 7px;
}
.w-bcolhead > :first-child { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
.w-bcount { flex: none; font-weight: 600; letter-spacing: 0; text-transform: none; }
.w-bcard {
  background: var(--p-page, #fff); border: 1px solid var(--p-border, #e5e7eb);
  border-radius: 6px; padding: 7px 8px; margin-bottom: 6px;
}
.w-bctitle {
  font-size: 10.5px; font-weight: 600; color: var(--p-fg, #111); line-height: 1.3;
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3; overflow: hidden;
}
.w-bcmeta {
  font-size: 9.5px; color: var(--p-mutedfg, #8b8f98); margin: 3px 0 5px;
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden;
}
.w-bcard .w-badge { font-size: 9px; padding: 1px 6px; }
.w-toprow .w-cta { margin-top: 0; }
.w-sub { font-size: 12px; color: var(--p-mutedfg, #8b8f98); margin: 4px 0 12px; }
.w-setrow {
  display: flex; justify-content: space-between; gap: 12px;
  padding: 10px 0; border-bottom: 1px solid var(--p-border, #e5e7eb); font-size: 12px;
}
.w-setlbl { font-weight: 600; color: var(--p-ink, #111); }
.w-setval {
  color: var(--p-mutedfg, #8b8f98); border: 1px solid var(--p-border, #e5e7eb);
  border-radius: 6px; padding: 4px 8px; min-width: 7rem; text-align: right;
}
.w-mediagrid {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; margin: 12px 0;
}
.w-mediaitem {
  border: 1px solid var(--p-border, #e5e7eb); border-radius: 10px; padding: 8px;
  background: var(--p-page, #fff);
}
.w-mediathumb {
  height: 56px; border-radius: 6px; background: var(--p-border, #e5e7eb) center/cover no-repeat;
  margin-bottom: 6px;
}
.w-medialbl { font-size: 12px; font-weight: 600; }
.w-mediaplace {
  font-size: 11px; color: var(--p-mutedfg, #8b8f98); margin-top: 2px; line-height: 1.3;
}
.w-mediastate { font-size: 11px; color: var(--p-mutedfg, #8b8f98); }
.w-upload {
  display: flex; flex-direction: column; gap: 2px; margin-top: 10px;
  padding: 12px; border: 1px dashed var(--p-primary, #111); border-radius: 10px;
  font-size: 12px; font-weight: 600;
}
.w-upload small { font-weight: 400; color: var(--p-mutedfg, #8b8f98); }
.w-uploadic { font-size: 14px; opacity: 0.7; }
@media (max-width: 820px) {
  .browser { width: min(94vw, 720px); height: auto; min-height: 380px; }
  #phones .board:has(.browser) { grid-template-columns: 1fr; }
}

/* --- comprehension header (who + optional user stories) ------------------
   Actor stays visible. Full jobs open on demand — no truncated chips that
   look like buttons. */
/* One row, not a stack. The phones are what the user came for, and every band
   above them pushes the wow moment further down the fold — measured at 327px
   of meta before the first phone pixel on a 1512x950 laptop. Horizontal keeps
   the premise and the way into the sheet on a single line. */
.comp-header {
  margin: 0 0 10px; padding: 0 8px;
  display: flex; flex-direction: row; align-items: baseline;
  justify-content: center; gap: 10px; flex-wrap: wrap;
  text-align: center;
}
.comp-header.console-comp {
  margin: 8px 0 12px;
}
.comp-header.console-comp .comp-for {
  color: var(--ink, #111);
}
.comp-for {
  margin: 0; max-width: 42rem;
  font: 500 13.5px/1.4 var(--font-body, inherit); color: var(--ink);
}
.comp-stories {
  max-width: 36rem; width: 100%;
}
.comp-stories > summary {
  list-style: none; cursor: pointer; user-select: none;
  display: inline-block; margin: 0 auto;
  font: 500 12.5px/1.3 var(--font-body, inherit); color: var(--dim);
  text-decoration: underline; text-underline-offset: 3px;
}
.comp-stories > summary::-webkit-details-marker { display: none; }
.comp-stories > summary::after {
  content: "";
  display: inline-block; width: 0; height: 0; margin-left: 0.4em;
  border-left: 3.5px solid transparent; border-right: 3.5px solid transparent;
  border-top: 4.5px solid currentColor; vertical-align: 0.1em;
  opacity: .7;
}
.comp-stories[open] > summary::after {
  border-top: 0; border-bottom: 4.5px solid currentColor;
}
.comp-stories > summary:hover { color: var(--ink); }
.comp-jobs {
  list-style: none; margin: 8px 0 0; padding: 10px 14px;
  display: flex; flex-direction: column; align-items: flex-start; gap: 8px;
  text-align: left;
  border: 1px solid var(--line); border-radius: 12px;
  background: color-mix(in oklch, var(--tint, #f6f4ef) 55%, #fff);
}
.comp-jobs li {
  margin: 0; padding: 0 0 0 0.85em; position: relative;
  font: 400 13px/1.45 var(--font-body, inherit); color: var(--ink);
}
.comp-jobs li::before {
  content: "·";
  position: absolute; left: 0; color: var(--dim);
}

/* Quiet secondary console invite when hasConsole is false (prominence, not
   a hard gate). Same click target id as the promoted switcher. */
.console-ask {
  display: flex; justify-content: center; margin: 0 0 16px;
}
.consoleask {
  appearance: none; background: none; border: 0; padding: 0;
  color: var(--dim); font: 500 12.5px/1.3 var(--font-body, inherit);
  cursor: pointer; text-decoration: underline;
  text-underline-offset: 3px;
}
.consoleask:hover { color: var(--ink); }

/* --- business workspace audience switch ----------------------------------
   This sits above the screens: the second surface is product-level context,
   not a footer action users must discover after scrolling. */
.audience-switcher {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(250px, auto);
  align-items: stretch; gap: 8px; margin: 0 0 22px; padding: 8px;
  border: 1px solid var(--line); border-radius: 14px; background: #fff;
}
.audience-current,
.consoleopen {
  min-width: 0; display: flex; align-items: center; gap: 10px; padding: 10px 12px;
  border-radius: 10px; color: var(--ink); text-align: left;
}
.audience-current { background: #fff; }
.consoleopen {
  border: 1px solid var(--line); background: var(--soft); cursor: pointer;
  transition: border-color .18s var(--ease, ease), background .18s var(--ease, ease);
}
.audience-current > span:not(.audience-icon),
.consoleopen > span:not(.audience-icon):not(.audience-arrow) {
  min-width: 0; display: flex; flex-direction: column; gap: 2px;
}
.audience-current b, .consoleopen b { font-size: 12.5px; line-height: 1.2; }
.audience-current small, .consoleopen small { color: var(--dim); font-size: 10.5px; line-height: 1.3; }
.audience-icon { width: 24px; flex: none; font-size: 15px; text-align: center; }
.audience-arrow { margin-left: auto; color: var(--blue); font-size: 17px; }
.consoleopen:hover { border-color: color-mix(in oklch, var(--blue) 45%, transparent); background: var(--tint); }
.consoleopen:disabled { opacity: .7; cursor: wait; }
/* WHO labels above each board */
.audlabel {
  display: flex; align-items: center; justify-content: center; gap: 7px;
  font: 500 12.5px/1 var(--font-body, inherit); color: var(--dim);
  margin: 0 0 14px; text-transform: none;
}
.audlabel b { color: var(--ink); font-weight: 700; }
.audlabel span { font-size: 14px; }
.audlabel.console-owner { margin-top: 30px; }
#consoleBoard { scroll-margin-top: 92px; }
#consoleBoard[hidden] { display: none; }
.consboard { margin-top: 2px; }
@media (max-width: 760px) {
  .audience-switcher { grid-template-columns: 1fr; }
}
@media (prefers-reduced-motion: reduce) {
  .consoleopen { transition: none; }
  .build-progress-mark i { animation: none; opacity: .65; }
}

/* ---------- spec confirmation sheet ---------------------------------------
   Hand back what we already inferred so the user can correct it. Every field
   arrives prefilled: this is a correction surface, not a questionnaire, and
   nothing in it is required.
   See docs/engineering/prototype-spec-confirmation.md. */
/* Tighter than the first pass: jobs stopped being four bordered inputs, so the
   whole sheet shrank by ~90px and now fits a laptop without relying on the
   sticky bar to rescue it. The sticky bar stays for the 6-job case. */
.spec-main { display: flex; flex-direction: column; gap: 0; }
.spec-field { display: flex; flex-direction: column; gap: 5px; padding: 11px 0; border-top: 1px solid var(--line); }
.spec-field:first-of-type { border-top: 0; padding-top: 8px; }
.spec-label { font-size: 11px; font-weight: 700; letter-spacing: .07em; text-transform: uppercase; color: var(--dim); }
.spec-input {
  width: 100%; border: 1px solid var(--line); border-radius: 9px;
  padding: 9px 11px; font: inherit; font-size: 14px; color: var(--ink);
  background: var(--soft);
}
.spec-input:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }
.spec-hint { font-size: 11.5px; color: var(--dim); }

/* Jobs READ as text and become an input only on click. Four bordered boxes
   said "fill this in" and argued with the sheet's own "or go straight
   through" — the sheet is a correction surface, not a form. */
.spec-jobs { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 2px; }
.spec-jobtext {
  width: 100%; text-align: left; border: 1px solid transparent; background: none;
  font: inherit; font-size: 13.5px; line-height: 1.45; color: var(--ink);
  padding: 5px 8px; border-radius: 7px; cursor: text;
}
.spec-jobtext:hover { background: var(--soft); border-color: var(--line); }
.spec-jobtext:focus-visible { outline: 2px solid var(--brand); outline-offset: 1px; }
/* Same left inset as the text it replaces, so a job does not jump sideways the
   moment you click it. */
.spec-jobedit { margin: 1px 0; padding-left: 8px; }

/* Name and actor read as prose too, becoming inputs on click. A bordered,
   autofocused box is the universal "your turn to type" — the wrong opening
   move for a surface whose claim is that we already worked this out. */
.spec-valuetext {
  align-self: flex-start; max-width: 100%; text-align: left;
  border: 1px solid transparent; background: none; font: inherit;
  font-size: 15px; font-weight: 600; letter-spacing: -.01em; color: var(--ink);
  padding: 4px 8px; border-radius: 7px; cursor: text;
}
.spec-valuetext:hover { background: var(--soft); border-color: var(--line); }
.spec-valuetext:focus-visible { outline: 2px solid var(--brand); outline-offset: 1px; }
/* Cap the editing width: a full-bleed 790px input holding the word "Sendline"
   is enterprise-form vocabulary. */
.spec-valueedit { max-width: 420px; padding-left: 8px; }

/* The two load-bearing fields are grouped and warned ONCE, rather than each
   repeating the same pill — two identical warnings read as boilerplate, and
   boilerplate gets skipped. */
.spec-field.tier3 { border-left: 2px solid #f2ddb9; padding-left: 12px; }
.spec-field.tier3 + .spec-field.tier3 { border-top-color: #f7ead3; }

/* Tier 3: editing these regenerates every screen. Say so BEFORE they type,
   not at the consent step — a surprise at a gate is the worst place for one. */
.spec-field.tier3 .spec-label { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
.tier3-flag {
  font-size: 10px; font-weight: 600; letter-spacing: 0; text-transform: none;
  color: #9a5b12; background: #fdf3e3; border: 1px solid #f2ddb9;
  padding: 1px 7px; border-radius: 999px;
}

/* Facts read off a reference image — a record, not a form. */
.spec-facts { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 5px; }
.spec-facts li {
  display: flex; align-items: baseline; justify-content: space-between; gap: 14px;
  font-size: 13.5px; padding: 5px 0; border-bottom: 1px dashed var(--line);
}
.spec-facts li:last-child { border-bottom: 0; }
.spec-facts b { font-weight: 620; }
.spec-facts span { color: var(--dim); font-size: 12.5px; white-space: nowrap; font-variant-numeric: tabular-nums; }
.spec-chips { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }
.spec-chip {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: 12.5px; padding: 4px 6px 4px 11px; border-radius: 999px;
  border: 1px solid var(--line); background: var(--soft); color: var(--ink);
}
.spec-chip-x {
  border: 0; background: none; padding: 0 3px; font: inherit; font-size: 14px;
  line-height: 1; color: var(--dim); cursor: pointer; border-radius: 999px;
}
.spec-chip-x:hover { color: var(--ink); }
.spec-chip.add {
  align-self: flex-start;   /* a chip, not a stretched field */
  padding: 4px 11px; border-style: dashed; color: var(--dim);
  cursor: pointer; font: inherit; font-size: 12.5px;
}
.spec-chip.add:hover { color: var(--ink); border-color: var(--dim); }
.spec-chip-new {
  font: inherit; font-size: 12.5px; width: 120px; padding: 4px 11px;
  border-radius: 999px; border: 1px solid var(--brand); background: #fff; color: var(--ink);
}
/* Pinned, not appended. The sheet is taller than a laptop viewport once four
   jobs and a chip row are prefilled, so an in-flow action row lands below the
   fold and the primary gate reads as a form with no way forward. */
/* In the card, not floating over it. The sticky version hovered above the
   content with a drop shadow and read as a detached toolbar. The sheet is
   shorter now (prose fields, no empty boxes), so the row sits at the end where
   it belongs. */
.spec-actions {
  display: flex; align-items: center; justify-content: flex-end;
  gap: 8px; flex-wrap: wrap;
  margin-top: 18px; padding-top: 16px; border-top: 1px solid var(--line);
}

/* Real buttons. Underlined text links for a genuine choice — especially
   "Rebuild them", which replaces every screen — read as a footnote, and are
   exactly the dated vocabulary this sheet was accused of. */
.spec-btn {
  font: inherit; font-size: 13.5px; font-weight: 620; line-height: 1;
  padding: 11px 18px; border-radius: 10px; cursor: pointer;
  border: 1px solid transparent; transition: background .12s, border-color .12s;
}
.spec-btn:disabled { opacity: .5; cursor: default; }
.spec-btn.primary { background: var(--ink); color: #fff; }
.spec-btn.primary:hover:not(:disabled) { background: #000; }
.spec-btn.ghost { background: none; color: var(--dim); border-color: var(--line); }
.spec-btn.ghost:hover:not(:disabled) { color: var(--ink); border-color: var(--dim); }
.spec-btn.danger { background: none; color: #b3261e; border-color: #f0c9c5; }
.spec-btn.danger:hover:not(:disabled) { background: #fdf5f4; border-color: #b3261e; }
/* The consent step owns its own actions; nesting two sticky rows would stack
   them. Inside the consent card they stay in flow. */
.spec-consent .spec-actions {
  position: static; box-shadow: none; padding: 0; background: none;
}
.linkish {
  border: 0; background: none; padding: 6px 2px; font: inherit; font-size: 13px;
  color: var(--dim); cursor: pointer; text-decoration: underline; text-underline-offset: 3px;
}
.linkish:hover { color: var(--ink); }
.linkish.danger { color: #b3261e; }
/* Tier 3. A changed actor invalidates every screen, so the consent step is
   visually heavier than the rest of the sheet on purpose. */
.spec-consent {
  margin-top: 14px; padding: 14px 16px; border: 1px solid #f0c9c5;
  background: #fdf5f4; border-radius: 11px; display: flex; flex-direction: column; gap: 6px;
}
.spec-consent b { font-size: 14px; }
.spec-consent p { font-size: 13px; color: var(--dim); margin: 0; }
.spec-consent .spec-actions { margin-top: 6px; }
/* Entry A used to be a "Check what we understood" pill under the board. It is
   now the app bar identity itself (.ab-ident) — the name and the persona ARE
   the check, so clicking them opens the review. */

/* ---------- lightbox: one screen, large ------------------------------------
   This replaces the old "Focus" view. Browsing a single screen large is a
   zoom, not a mode — giving it a tab beside Screens/Try it/Map implied it was
   a different KIND of thing, and its side column ended up doubling as the
   confirmation form, so one slot showed two unrelated jobs. Click a phone,
   arrow between screens, Escape out. */
.lb {
  position: fixed; inset: 0; z-index: 120;
  display: flex; align-items: center; justify-content: center; gap: clamp(14px, 3vw, 34px);
  background: rgba(18, 18, 22, .58); backdrop-filter: blur(6px);
  animation: lbIn .18s var(--ease, ease);
}
@keyframes lbIn { from { opacity: 0 } to { opacity: 1 } }
.lb-phone { flex: none; }
.lb-phone .phone { width: 320px; box-shadow: 0 30px 80px rgba(0,0,0,.45); }
.lb-nav {
  flex: none; width: 44px; height: 44px; border-radius: 999px; border: 0;
  background: rgba(255,255,255,.14); color: #fff; font-size: 17px; cursor: pointer;
  transition: background .15s;
}
.lb-nav:hover { background: rgba(255,255,255,.3); }
.lb-nav[disabled] { opacity: .25; cursor: default; }
.lb-close {
  position: absolute; top: 22px; right: 26px; border: 0; background: none;
  color: #d2d3d9; font-size: 13.5px; cursor: pointer; padding: 6px 10px;
}
.lb-close:hover { color: #fff; }
.lb-meta {
  position: absolute; left: 0; right: 0; bottom: clamp(18px, 4vh, 40px);
  text-align: center; color: #cbccd3; font-size: 13px; padding: 0 20px;
  display: flex; flex-direction: column; align-items: center; gap: 10px;
}
.lb-meta .lb-title { color: #fff; font-size: 15px; font-weight: 650; }
.lb-meta .lb-pos { color: #90939c; }
/* The flow lanes are shared with nothing else now, so they read on the dark
   ground: transparent chips, light text. */
.lb .fx-flow { padding: 0; align-items: center; }
.lb .fx-k { display: none; }
.lb .fx-journey { align-items: center; }
.lb .fx-journey-name { color: #cbccd3; font-size: 12px; font-weight: 500; }
.lb .fx-node { background: rgba(255,255,255,.1); border-color: transparent; color: #d5d6dc; font-size: 12px; padding: 6px 11px; }
.lb .fx-node:hover { background: rgba(255,255,255,.2); color: #fff; border-color: transparent; }
.lb .fx-node.here { background: #fff; color: #17181b; border-color: #fff; }
.lb .fx-arrow { color: #6f727b; }

/* The journeys this screen belongs to. A single phone can show what a screen
   looks like and never where it sits in a path. Named paths, not an edge dump. */
.fx-flow { display: flex; flex-direction: column; gap: 14px; padding: 16px 0 4px; }
.fx-journey { display: flex; flex-direction: column; gap: 7px; }
.fx-journey-name { font-size: 13px; font-weight: 640; color: var(--ink); }
.fx-lane { display: flex; align-items: center; gap: 7px; flex-wrap: wrap; }
.fx-arrow { color: var(--dim); font-size: 14px; }
.fx-node {
  border: 1px solid var(--line); background: var(--soft); color: var(--dim);
  border-radius: 10px; padding: 8px 13px; font: inherit; font-size: 13px;
  cursor: pointer; max-width: 18ch; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.fx-node:hover { color: var(--ink); border-color: var(--dim); }
/* The screen you are on, inside its own path. */
.fx-node.here { background: var(--ink); border-color: var(--ink); color: #fff; font-weight: 640; cursor: default; }

/* ---------- the review: the brief as a modal over the visible board ---------
   Fourth container, each one instructive. A plain dialog covered the screens
   it asked about; the Focus side panel made one slot mean two things; the
   full-stage takeover hid the live board and substituted thumbnail proxies as
   "evidence". So: a light dim, the real screens visible around the card, no
   filmstrip. The evidence is the page itself. */
body.reviewing { overflow: hidden; }
.review {
  position: fixed; inset: 0; z-index: 110;
  display: grid;                    /* + margin:auto on the card = vertically
                                       centred when short, scrollable when not */
  overflow-y: auto; overscroll-behavior: contain;
  padding: max(3vh, 18px) 20px;
  /* Dim, do NOT blur: the point of this container is that the screens being
     confirmed stay recognisable behind the question. */
  background: rgba(20, 21, 26, .42);
  animation: rvFade .18s ease;
}
@keyframes rvFade { from { opacity: 0 } to { opacity: 1 } }
.rv-step { font-weight: 700; letter-spacing: .12em; color: var(--dim); }

/* WIDE, not long. A single column ran past the viewport, which put "Build
   this" below the fold of the very question it answers. Two columns keep the
   whole commitment on screen at once. */
.rv-brief {
  position: relative; width: min(940px, 100%); margin: auto; background: #fff;
  border: 1px solid var(--line); border-radius: 18px;
  padding: clamp(24px, 3vw, 36px) clamp(22px, 3.2vw, 44px) 28px;
  box-shadow:
    0 34px 90px -20px rgba(10, 11, 14, .45),
    0 20px 50px -24px color-mix(in oklab, var(--blue) 30%, transparent);
  animation: rvCard .28s cubic-bezier(.2, .9, .3, 1.1);
}
.rv-fields { columns: 2; column-gap: 48px; }
.rv-fields .spec-field { break-inside: avoid; }
@media (max-width: 860px) { .rv-fields { columns: 1; } }
@keyframes rvCard {
  from { opacity: 0; transform: translateY(16px) scale(.97); }
  to { opacity: 1; transform: none; }
}
.rv-close {
  position: absolute; top: 14px; right: 16px;
  border: 0; background: none; color: var(--dim); font-size: 21px; line-height: 1;
  padding: 5px 9px; border-radius: 8px; cursor: pointer;
}
.rv-close:hover { color: var(--ink); background: var(--soft); }
.rv-kicker {
  font: 700 10.5px/1 ui-monospace, SFMono-Regular, Menlo, monospace;
  letter-spacing: .12em; text-transform: uppercase;
  color: var(--p-primary, var(--blue)); margin-bottom: 14px;
}
/* The brief wears the app's identity: it describes THEIR product, so it is set
   in their display face and accented in their colour. */
.rv-brief h2 {
  margin: 0; font-size: clamp(30px, 4.4vw, 42px); line-height: 1.05;
  letter-spacing: var(--p-display-ls, -.035em); font-weight: var(--p-display-weight, 800);
  font-family: var(--p-display, var(--font-head, inherit));
  font-style: var(--p-display-style, normal);
}
.rv-for { font-size: 16.5px; line-height: 1.5; color: var(--ink); margin: 12px 0 4px; }
.rv-sect {
  font: 700 10.5px/1 ui-monospace, SFMono-Regular, Menlo, monospace;
  letter-spacing: .1em; text-transform: uppercase; color: var(--dim); margin: 28px 0 12px;
}
.rv-warn {
  margin-top: 26px; padding-top: 18px; border-top: 1px solid var(--line);
  display: flex; gap: 10px; align-items: flex-start; font-size: 12.5px; color: var(--dim);
}
.rv-warn .rv-dot { flex: none; width: 8px; height: 8px; border-radius: 999px; background: #e0ad2f; margin-top: 5px; }
/* Inside the card now — a modal's commitment row belongs on the card itself. */
.rv-cta {
  margin: 26px 0 0; padding-top: 22px; border-top: 1px solid var(--line-soft, var(--line));
  display: flex; align-items: center; gap: 18px; flex-wrap: wrap;
}
/* Mistflow blue, deliberately NOT the app's accent: the commitment button is
   our ask, and the app's own colours are already on screen behind the card. */
.rv-go {
  border: 0; cursor: pointer; color: #fff;
  background: var(--blue); font-size: 15.5px; font-weight: 700;
  padding: 13px 30px; border-radius: 12px; letter-spacing: -.01em;
  box-shadow: 0 10px 26px -10px color-mix(in oklab, var(--blue) 60%, transparent);
  transition: transform .18s var(--ease, ease), filter .15s;
}
.rv-go:hover { transform: translateY(-1px); filter: brightness(1.06); }
.rv-go[disabled] { opacity: .55; cursor: default; transform: none; }
.rv-note { font-size: 12.5px; color: var(--dim); line-height: 1.45; flex: 1; min-width: 200px; }
.rv-skip { border: 0; background: none; color: var(--dim); font-size: 13px; cursor: pointer; text-decoration: underline; text-underline-offset: 3px; padding: 0; }
.rv-skip:hover { color: var(--ink); }
/* ---- the shared spec fields, read as prose inside the brief ----------------
   Same elements, same IDs, same bindings as the sheet — only the presentation
   changes. Keeping one field renderer (specFieldsHtml) is deliberate: two
   copies would drift and the user would meet a different sheet depending on
   how they arrived. */
.rv-brief .spec-valueedit, .rv-brief .spec-input { max-width: 100%; }
.rv-brief .spec-field { border-top: 0; padding: 0; margin-bottom: 26px; gap: 8px; }
.rv-brief .spec-field:last-of-type { margin-bottom: 0; }
.rv-brief .spec-label {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 10.5px; letter-spacing: .1em;
}
/* The app's own name, at display size, editable in place. */
.rv-brief #specName, .rv-brief .spec-valueedit#specName {
  font-size: clamp(24px, 3vw, 32px); line-height: 1.08;
  font-weight: var(--p-display-weight, 800);
  font-family: var(--p-display, var(--font-head, inherit));
  font-style: var(--p-display-style, normal);
  letter-spacing: var(--p-display-ls, -.035em);
  padding: 2px 8px; margin-left: -8px;
}
.rv-brief #specActor, .rv-brief .spec-valueedit#specActor { font-size: 16.5px; line-height: 1.5; }
.rv-brief .spec-jobtext, .rv-brief .spec-jobedit { font-size: 15px; line-height: 1.5; }
.rv-brief .spec-hint { font-size: 12.5px; }
/* The dotted underline says "this is editable prose" without drawing a box
   around every line, which is what made the old panel read as a form. */
.rv-brief .spec-valuetext, .rv-brief .spec-jobtext {
  border-bottom: 2px dotted color-mix(in oklab, var(--p-primary, var(--blue)) 42%, transparent);
  border-radius: 3px;
}
.rv-brief .spec-valuetext:hover, .rv-brief .spec-jobtext:hover {
  background: color-mix(in oklab, var(--p-primary, var(--blue)) 8%, transparent);
  border-bottom-color: var(--p-primary, var(--blue));
}
.rv-brief .spec-field.tier3 { border-left: 0; padding-left: 0; }
.rv-brief .tier3-flag { background: color-mix(in oklab, var(--p-primary, var(--blue)) 12%, transparent); border-color: transparent; }
.rv-brief .spec-consent { margin-top: 26px; }



/* ---------- the receipt wears the app it is confirming ----------------------
   A sheet closing the deal on a dark, amber, Chalk-styled app rendered in our
   white/gray/blue reads as our dialog rather than their app's. The aside — the
   half that IS their product — now takes the prototype's own accent and display
   face. The copy and the CTA stay in Mistflow's voice on purpose: that half is
   our transaction, and putting a customer palette on our pricing would be
   worse than generic. */
.sheet-themed .sheet-aside {
  background:
    radial-gradient(120% 90% at 50% 8%,
      color-mix(in oklab, var(--p-primary) 22%, transparent) 0%, transparent 62%),
    linear-gradient(180deg, #fff 0%, color-mix(in oklab, var(--p-primary) 7%, #fff) 100%);
}
.sheet-themed .sheet-aside svg,
.sheet-themed .sheet-aside canvas {
  filter: drop-shadow(0 10px 24px color-mix(in oklab, var(--p-primary) 30%, transparent));
}
.sheet-themed .aside-title {
  font-family: var(--p-display, inherit);
  font-weight: var(--p-display-weight, 800);
  font-style: var(--p-display-style, normal);
  letter-spacing: var(--p-display-ls, -.02em);
}
/* One accent line under the name, in their colour — enough to say "this is
   yours" without repainting a page that has to stay readable. */
.sheet-themed .aside-title::after {
  content: ""; display: block; width: 34px; height: 3px; border-radius: 2px;
  margin: 10px auto 0; background: var(--p-primary);
}

/* ---------- layout_spec interpreter (create.js lsNode) ----------
   Tree screens read from a reference image. Everything themes through the
   same --p-* vars as the fixed skeletons: spacing multiplies --p-density,
   radii derive from --p-radius, tones from the resolved theme. Keep in sync
   with create.js lsNode and (later) the RN kit interpreter. */
.p-ls { display: flex; flex-direction: column; gap: 8px; flex: 1; min-height: 0; overflow: hidden; }
.p-ls-stack, .p-ls-list { display: flex; flex-direction: column; min-width: 0; }
.p-ls-row { display: flex; align-items: center; min-width: 0; }
.p-ls-row.ls-a-start { justify-content: flex-start; }
.p-ls-row.ls-a-center { justify-content: center; }
.p-ls-row.ls-a-end { justify-content: flex-end; }
.p-ls-row.ls-a-between { justify-content: space-between; }
.p-ls-row > * { min-width: 0; }
.p-ls-grid { display: grid; }
.p-ls-grid.ls-c2 { grid-template-columns: 1fr 1fr; }
.p-ls-grid.ls-c3 { grid-template-columns: 1fr 1fr 1fr; }
.p-ls-scroll { display: flex; overflow: hidden; }
.p-ls-scroll > * { flex: none; }
.p-ls-card { background: var(--p-card); border: var(--p-cardborder, 1px) solid var(--p-bordercol, var(--p-border)); border-radius: calc(var(--p-radius) * .7); display: flex; flex-direction: column; padding: 10px; }
.p-ls-card.ls-tone-accent { background: color-mix(in srgb, var(--p-primary) 14%, var(--p-card)); }
.p-ls-card.ls-tone-muted { background: var(--p-muted); border-color: transparent; }
.p-ls-div { height: 1px; background: var(--p-border); flex: none; }
.p-ls-text { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.p-ls-text.ls-display { font-family: var(--p-display); font-style: var(--p-display-style, normal); font-weight: var(--p-display-weight, 800); letter-spacing: var(--p-display-ls, -.4px); font-size: calc(24px * var(--p-tscale, 1)); line-height: 1.08; }
.p-ls-text.ls-title { font-family: var(--p-display); font-style: var(--p-display-style, normal); font-weight: var(--p-display-weight, 800); letter-spacing: var(--p-display-ls, -.3px); font-size: calc(16px * var(--p-tscale, 1)); line-height: 1.2; }
.p-ls-text.ls-subtitle { font-weight: 600; font-size: calc(12.5px * var(--p-tscale, 1)); color: var(--p-mutedfg); }
.p-ls-text.ls-body { font-size: calc(12px * var(--p-tscale, 1)); line-height: 1.45; }
.p-ls-text.ls-meta { font-size: calc(10.5px * var(--p-tscale, 1)); color: var(--p-mutedfg); }
.p-ls-text.ls-eyebrow { font-size: 9.5px; font-weight: 700; letter-spacing: .12em; text-transform: uppercase; color: var(--p-mutedfg); }
.p-ls-text.ls-value { font-weight: 800; font-size: calc(13px * var(--p-tscale, 1)); font-variant-numeric: tabular-nums; }
.p-ls-text.ls-al-center { text-align: center; }
.p-ls-text.ls-al-end { text-align: right; }
.p-ls-text.ls-tone-accent, .p-ls-icon.ls-tone-accent, .p-ls-stat.ls-tone-accent .p-ls-statval { color: var(--p-primary-text, var(--p-primary)); }
.p-ls-text.ls-tone-muted { color: var(--p-mutedfg); }
.p-ls-text.ls-tone-positive, .p-ls-statdelta { color: #1a9b62; }
.p-ls-text.ls-tone-negative { color: #d5484f; }
.p-ls-stat { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.p-ls-stat .p-ls-statval { font-family: var(--p-display); font-weight: var(--p-display-weight, 800); letter-spacing: -.02em; font-variant-numeric: tabular-nums; line-height: 1.05; font-size: calc(17px * var(--p-num-scale, 1) * var(--p-tscale, 1)); }
.p-ls-stat.ls-sm .p-ls-statval { font-size: calc(13px * var(--p-tscale, 1)); }
.p-ls-stat.ls-lg .p-ls-statval { font-size: calc(24px * var(--p-num-scale, 1) * var(--p-tscale, 1)); }
.p-ls-stat.ls-hero .p-ls-statval { font-size: calc(34px * var(--p-num-scale, 1) * var(--p-tscale, 1)); }
.p-ls-stat .p-ls-statval i { font-style: normal; font-size: .48em; font-weight: 700; color: var(--p-mutedfg); margin-left: 3px; }
.p-ls-stat .p-ls-statlab { font-size: 10px; color: var(--p-mutedfg); font-weight: 600; }
.p-ls-stat .p-ls-statdelta { font-size: 10px; font-weight: 700; }
.p-ls-img { background: var(--p-muted); border-radius: calc(var(--p-radius) * .55); flex: none; width: 100%; }
.p-ls-img.ls-wide { aspect-ratio: 16 / 9; }
.p-ls-img.ls-square { aspect-ratio: 1; }
.p-ls-img.ls-tall { aspect-ratio: 3 / 4; }
.p-ls-row .p-ls-img, .p-ls-scroll .p-ls-img { width: auto; height: 54px; }
.p-ls-icon { display: inline-flex; flex: none; color: var(--p-mutedfg); }
.p-ls-icon svg { width: 16px; height: 16px; }
.p-ls-icon.ls-sm svg { width: 12px; height: 12px; }
.p-ls-icon.ls-lg svg { width: 22px; height: 22px; }
.p-ls-av { flex: none; display: inline-flex; }
.p-ls-av img { border-radius: 50%; }
.p-ls-badge { flex: none; }
.p-ls-prog { display: flex; flex-direction: column; gap: 3px; min-width: 0; flex: 1; }
.p-ls-prog .p-ls-proglab { font-size: 10px; font-weight: 600; color: var(--p-mutedfg); }
.p-ls-progbar { height: 5px; border-radius: 3px; background: var(--p-muted); overflow: hidden; }
.p-ls-progbar i { display: block; height: 100%; border-radius: 3px; background: var(--p-primary); }
.p-ls-chart, .p-ls-line { display: flex; flex-direction: column; gap: 3px; flex: none; }
.p-ls-barrow { display: flex; align-items: flex-end; gap: 4px; height: 58px; }
.p-ls-bar { flex: 1; border-radius: 3px 3px 1px 1px; background: color-mix(in srgb, var(--p-primary) 34%, var(--p-muted)); }
.p-ls-bar.hot { background: var(--p-primary); }
.p-ls-line svg { width: 100%; height: 58px; display: block; }
.p-ls-line .stroke { fill: none; stroke: var(--p-primary); stroke-width: 2.4; stroke-linecap: round; stroke-linejoin: round; vector-effect: non-scaling-stroke; }
.p-ls-line .fill { fill: color-mix(in srgb, var(--p-primary) 16%, transparent); stroke: none; }
.p-ls-xlab { display: flex; justify-content: space-between; font-size: 8.5px; font-weight: 600; color: var(--p-mutedfg); }
.p-ls-spark { flex: none; width: 52px; }
.p-ls-spark svg { width: 100%; height: 14px; display: block; }
.p-ls-spark polyline { fill: none; stroke: var(--p-primary); stroke-width: 2; vector-effect: non-scaling-stroke; }
.p-ls-btn { text-align: center; font-weight: 700; font-size: 12.5px; padding: calc(9px * var(--p-density, 1)) 12px; border-radius: calc(var(--p-radius) * .7); background: var(--p-primary); color: var(--p-onprimary); transition: transform .12s ease; }
.p-ls-btn:active { transform: scale(.97); }
.p-ls-btn.ls-secondary { background: var(--p-muted); color: var(--p-fg); }
.p-ls-btn.ls-ghost { background: transparent; border: 1px solid var(--p-border); color: var(--p-fg); }
.p-ls-chips { flex-wrap: nowrap; overflow: hidden; }
.p-ls-inp { display: flex; flex-direction: column; gap: 3px; }
.p-ls-inp .p-ls-inplab { font-size: 10px; font-weight: 700; color: var(--p-mutedfg); }
.p-ls-inpbox { border: 1px solid var(--p-border); border-radius: calc(var(--p-radius) * .55); padding: 8px 10px; font-size: 11.5px; color: var(--p-mutedfg); background: var(--p-card); }
.p-ls-search { display: flex; align-items: center; gap: 6px; border: 1px solid var(--p-border); border-radius: 999px; padding: 7px 12px; font-size: 11.5px; color: var(--p-mutedfg); background: var(--p-muted); }
.p-ls-search svg { width: 13px; height: 13px; flex: none; }
.p-ls-togrow { display: flex; align-items: center; justify-content: space-between; gap: 8px; font-size: 12px; font-weight: 600; }
.p-ls-tog { flex: none; width: 34px; height: 20px; border-radius: 12px; background: var(--p-muted); position: relative; transition: background .15s ease; }
.p-ls-tog i { position: absolute; top: 2px; left: 2px; width: 16px; height: 16px; border-radius: 50%; background: var(--p-card); box-shadow: 0 1px 2px rgba(0,0,0,.2); transition: left .15s ease; }
.p-ls-tog.on { background: var(--p-primary); }
.p-ls-tog.on i { left: 16px; }
.p-ls-stage { flex: none; height: 128px; margin: 0; border-radius: calc(var(--p-radius) * .55); }
/* layout_spec: table + checkbox_row (create.js lsNode). Cells are data, so
   the grid is one node; the row label takes a fixed share and the cells split
   the rest evenly, which is what keeps columns aligned across rows. */
.p-ls-table { display: flex; flex-direction: column; border: 1px solid var(--p-border); border-radius: calc(var(--p-radius) * .55); overflow: hidden; }
.p-ls-trow { display: flex; align-items: center; gap: 4px; padding: calc(6px * var(--p-density, 1)) 8px; border-top: 1px solid var(--p-border); min-width: 0; }
.p-ls-trow:first-child { border-top: 0; }
.p-ls-thead { background: var(--p-muted); }
.p-ls-thead .p-ls-tcell { font-size: 8.5px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; color: var(--p-mutedfg); }
.p-ls-tlab { flex: 1 1 40%; min-width: 0; font-size: 11px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.p-ls-tcell { flex: 1 1 0; min-width: 0; text-align: center; font-size: 10.5px; font-variant-numeric: tabular-nums; color: var(--p-fg); overflow: hidden; white-space: nowrap; }
.p-ls-cbrow { display: flex; align-items: center; gap: 9px; min-width: 0; }
.p-ls-cb { flex: none; width: 17px; height: 17px; border-radius: 50%; border: 1.5px solid var(--p-border); }
.p-ls-cb.on { background: var(--p-primary); border-color: var(--p-primary); }
.p-ls-cblab { flex: 1; min-width: 0; font-size: 12px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.p-ls-cblab.done { color: var(--p-mutedfg); text-decoration: line-through; }
.p-ls-cbmeta { flex: none; font-size: 10px; color: var(--p-mutedfg); }


/* ── layout_spec primitives, WEB surface ─────────────────────────────────
   MIRROR OF platform/backend/templates/web-kit/kit.css. Change the two in the
   same commit or the /create preview and the shipped app drift — the same rule
   the `.w-*` block above carries, and the reason those class names are shared
   rather than merely similar.

   Distinct from the `.p-ls-*` block (the PHONE tree renderer). Both interpret
   the same normalized tree; a browser window and a phone are not the same
   answer, which is the whole premise of the `admin_*` split.
*/
.ls-root { width: 100%; }
.ls-stack { display: flex; flex-direction: column; }
.ls-row { display: flex; flex-direction: row; align-items: center; flex-wrap: wrap; }
.ls-grid { display: grid; }
.ls-list { display: flex; flex-direction: column; }
.ls-scrollrow { display: flex; flex-direction: row; overflow-x: auto; scrollbar-width: thin; }
.ls-scrollrow > * { flex: 0 0 auto; }
.ls-card {
  background: var(--p-card); border: var(--p-cardborder, 1px) solid var(--p-bordercol, var(--p-border));
  border-radius: var(--p-radius, 16px); padding: 16px;
}

.ls-display { font-family: var(--p-display, inherit); font-weight: 700; font-size: 28px; line-height: 1.15; }
.ls-title   { font-family: var(--p-display, inherit); font-weight: 700; font-size: 18px; line-height: 1.25; }
.ls-body    { font-size: 14px; line-height: 1.5; }
.ls-detail  { font-size: 12.5px; color: var(--p-mutedfg); line-height: 1.45; }
.ls-eyebrow { font-size: 10.5px; letter-spacing: .09em; text-transform: uppercase; color: var(--p-mutedfg); font-weight: 600; }
.ls-value   { font-family: var(--p-display, inherit); font-weight: 700; font-size: 22px; font-variant-numeric: tabular-nums; }

.ls-stat { display: flex; flex-direction: column; gap: 2px; }
.ls-statval { font-family: var(--p-display, inherit); font-weight: 700; font-size: 24px; font-variant-numeric: tabular-nums; }
.ls-statlbl { font-size: 11px; color: var(--p-mutedfg); }
.ls-statdelta { font-size: 11px; font-weight: 600; }

.ls-badge {
  display: inline-block; padding: 3px 9px; border-radius: 999px;
  background: var(--p-muted); color: var(--p-fg); font-size: 11px; font-weight: 600;
}
.ls-btn {
  border: 0; border-radius: calc(var(--p-radius, 16px) * 0.55); cursor: pointer;
  padding: 9px 16px; font: inherit; font-size: 13px; font-weight: 600;
  background: var(--p-primary); color: var(--p-onprimary);
}
.ls-btn-primary { background: var(--p-primary); color: var(--p-onprimary); }
.ls-btn-secondary { background: var(--p-muted); color: var(--p-fg); }
.ls-btn-ghost { background: transparent; color: var(--p-primary-text, var(--p-primary)); }

.ls-input {
  border: 1px solid var(--p-bordercol, var(--p-border)); border-radius: calc(var(--p-radius, 16px) * 0.5);
  padding: 9px 12px; font-size: 13px; color: var(--p-mutedfg); background: var(--p-card); width: 100%;
}
.ls-input-search { max-width: 320px; }

.ls-segment { display: inline-flex; background: var(--p-muted); border-radius: 999px; padding: 3px; }
.ls-seg { padding: 5px 14px; border-radius: 999px; font-size: 12.5px; font-weight: 600; color: var(--p-mutedfg); }
.ls-seg-on { background: var(--p-card); color: var(--p-fg); }

.ls-chips { display: flex; flex-wrap: wrap; gap: 6px; }
.ls-chip {
  padding: 4px 11px; border-radius: 999px; font-size: 12px;
  border: 1px solid var(--p-bordercol, var(--p-border)); color: var(--p-mutedfg);
}

.ls-avatar {
  display: inline-flex; align-items: center; justify-content: center;
  width: 34px; height: 34px; border-radius: 999px; background: var(--p-muted);
  font-size: 12px; font-weight: 700; text-transform: uppercase; color: var(--p-mutedfg);
}
.ls-icon { display: inline-block; width: 18px; height: 18px; border-radius: 5px; background: var(--p-muted); }

.ls-img { width: 100%; aspect-ratio: 16 / 9; border-radius: calc(var(--p-radius, 16px) * 0.7); background: var(--p-muted); }
.ls-img-square { aspect-ratio: 1 / 1; }
.ls-img-tall { aspect-ratio: 3 / 4; }

.ls-divider { border: 0; border-top: 1px solid var(--p-bordercol, var(--p-border)); margin: 0; width: 100%; }

.ls-progress { width: 100%; height: 7px; border-radius: 999px; background: var(--p-muted); overflow: hidden; }
.ls-progressfill { height: 100%; background: var(--p-primary); }

.ls-bars { display: flex; align-items: flex-end; gap: 6px; height: 96px; }
.ls-bar { flex: 1; border-radius: 4px 4px 0 0; }
.ls-chart { width: 100%; height: 96px; display: block; }
.ls-spark { width: 100%; height: 30px; display: block; }
.ls-axis { display: flex; justify-content: space-between; margin-top: 4px; }
.ls-axis span { font-size: 9.5px; font-weight: 600; color: var(--p-mutedfg); }

.ls-table { width: 100%; border-collapse: collapse; font-size: 13px; }
.ls-table th {
  text-align: left; font-size: 10.5px; letter-spacing: .06em; text-transform: uppercase;
  color: var(--p-mutedfg); padding: 0 10px 7px 0; font-weight: 600;
}
.ls-table td { padding: 8px 10px 8px 0; border-top: 1px solid var(--p-bordercol, var(--p-border)); }

.ls-ctlrow { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 9px 0; width: 100%; }
.ls-ctllbl { font-size: 13.5px; }
.ls-toggle { width: 38px; height: 22px; border-radius: 999px; background: var(--p-muted); flex: 0 0 auto; }
.ls-toggle-on { background: var(--p-primary); }
.ls-check { width: 19px; height: 19px; border-radius: 5px; border: 1.5px solid var(--p-bordercol, var(--p-border)); flex: 0 0 auto; }
.ls-check-on { background: var(--p-primary); border-color: var(--p-primary); }

/* Motion is opt-out, not opt-in, for anyone who asked the OS to reduce it. */
@media (prefers-reduced-motion: reduce) {
  .ls-root *, .ls-root *::before, .ls-root *::after {
    animation-duration: .01ms !important; transition-duration: .01ms !important;
  }
}

/* ============================================================
   PDF export — the leave-behind
   ============================================================
   The export is the browser printing the SAME DOM the board renders, through
   the SAME stylesheet, so a screen in the PDF is the screen on the page. No
   rasteriser sits in between to quietly drop a gradient or a photo.

   Everything a BUILDER needs and a reader does not — the caption buttons, the
   layout flip rows, the "opens from" hints — is stripped. This file goes to
   somebody's customer, not back to the person building. */
#printsheet { display: none; }

@media print {
  @page { size: A4 portrait; margin: 14mm; }

  /* Only while an export is in flight. A plain Ctrl+P of the editor still
     prints the editor. */
  body.printing > *:not(#printsheet) { display: none !important; }
  body.printing #printsheet { display: block; }

  /* Photo fills and theme colours are the product here, so they must survive
     the print engine's default ink-saving. */
  #printsheet, #printsheet * {
    -webkit-print-color-adjust: exact;
    print-color-adjust: exact;
  }

  /* Builder-only affordances never reach the reader's copy. */
  #printsheet .p-capt,
  #printsheet .fliprow,
  #printsheet .opens-cap { display: none !important; }

  /* Screen shadows read as grey smears on paper. */
  #printsheet .phone,
  #printsheet .browser { box-shadow: none; }

  #printsheet .pxcover {
    break-after: page;
    display: flex; flex-direction: column; justify-content: center;
    min-height: 240mm; text-align: left;
  }
  /* align-self, not just max-*: .pxcover is a flex column, so the default
     `align-items: stretch` pulls the logo to the full column width and the
     max-height then squashes it — a square mark came out 180x64. Pin the
     cross-axis size to the content and let object-fit hold the ratio. */
  #printsheet .pxlogo {
    align-self: flex-start;
    width: auto; height: auto;
    max-width: 180px; max-height: 64px;
    object-fit: contain;
    margin-bottom: 28px;
  }
  #printsheet .pxcover h1 {
    font-size: 40px; line-height: 1.1; margin: 0 0 10px; letter-spacing: -.02em;
  }
  #printsheet .pxmeta { font-size: 13px; opacity: .6; margin: 0 0 28px; }
  #printsheet .pxnote {
    font-size: 14px; line-height: 1.55; max-width: 46em; opacity: .8; margin: 0;
  }

  #printsheet .pxpage { break-after: page; }
  #printsheet .pxpage:last-of-type { break-after: auto; }
  #printsheet .pxhead {
    display: flex; align-items: baseline; gap: 10px; margin: 0 0 14px;
  }
  #printsheet .pxnum {
    font-size: 12px; font-weight: 600; opacity: .45;
    min-width: 1.4em;
  }
  #printsheet .pxhead h2 {
    font-size: 19px; margin: 0; letter-spacing: -.01em;
  }

  /* The frames carry fixed pixel sizes (260x540 phone, 720x520 browser), so
     scale them to the page rather than reflowing them — reflowing would change
     the layout being reviewed, which is the one thing an export must not do.
     transform leaves the layout box behind, hence the explicit height. */
  #printsheet .pxframe {
    display: flex; justify-content: center;
    height: var(--pxh, 880px);
  }
  #printsheet .pxframe .phcol,
  #printsheet .pxframe .wcol {
    transform: scale(var(--pxs, 1.6));
    transform-origin: top center;
  }

  #printsheet .pxcredit {
    break-before: page;
    font-size: 11px; opacity: .55; line-height: 1.6;
  }
  #printsheet .pxcredit a { color: inherit; }
}
