/* The dictation demo widget. Shared by /demo/ and any page that embeds it, so the
   two can never drift apart. Everything here is scoped to the widget's own classes.

   Layout rules worth keeping: the card is a fixed height and the meter slot a fixed
   size, so text arriving or a status changing cannot move anything the visitor is
   reading. See the comments inline. */

.demo-hero {
  padding: 52px 24px 22px;
  text-align: center;
  background: linear-gradient(180deg, #fdf7f3 0%, var(--color-bg) 100%);
}

.demo-hero .eyebrow {
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 2px;
  text-transform: uppercase;
  background: var(--gradient-hero);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  margin-bottom: 14px;
}

.demo-hero h1 {
  font-size: clamp(1.9rem, 4.4vw, 2.7rem);
  line-height: 1.15;
  color: var(--color-text-dark);
  margin-bottom: 12px;
}

.demo-hero .lede {
  font-size: 1.05rem;
  color: var(--color-text-light);
  max-width: 620px;
  margin: 0 auto;
}

/* ---- the editor ---- */

/* width:100% matters. The page body is a flex container, so without it this
   section is a flex item that shrink-wraps its contents: the card starts
   narrow and then widens as text arrives, which is exactly the jump we do
   not want. With it, the card is the same width empty or full. */
.demo-stage {
  width: 100%;
  max-width: 1000px;
  margin: 0 auto;
  padding: 0 24px 56px;
}

.editor { width: 100%; }

.editor {
  background: var(--color-bg);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-xl);
  box-shadow: var(--shadow-lg);
  overflow: hidden;
  transition: box-shadow 0.25s ease, border-color 0.25s ease;
}

.editor.live {
  border-color: rgba(231, 80, 230, 0.45);
  box-shadow: 0 0 0 4px rgba(231, 80, 230, 0.09), var(--shadow-lg);
}

/* fake mail chrome, so it reads as somewhere you would actually write */
.editor-chrome {
  border-bottom: 1px solid var(--color-border-light);
  background: #fcfbfd;
  padding: 4px 28px 0;
}

.chrome-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 9px 0;
  font-size: 0.9rem;
  border-bottom: 1px solid var(--color-border-light);
}

.chrome-row:last-child { border-bottom: none; }

.chrome-row .label {
  color: var(--color-text-muted);
  width: 62px;
  flex-shrink: 0;
}

.chrome-row .value { color: var(--color-text); }

.chrome-row .value.subject { font-weight: 600; }

/* Fixed height, not min-height. The card must never change size as text
   arrives, or the whole page nudges under the cursor mid-dictation. */
.editor-body {
  position: relative;
  height: 200px;
  overflow-y: auto;
  padding: 24px 32px 20px;
  font-size: 1.1rem;
  line-height: 1.7;
  color: var(--color-text);
  word-break: break-word;
}

#demo-text { white-space: pre-wrap; }

/* the blinking caret that sells it as a real editor */
.caret {
  display: inline-block;
  width: 2px;
  height: 1.15em;
  background: var(--color-orange);
  vertical-align: text-bottom;
  margin-left: 1px;
  animation: demoBlink 1.1s steps(1) infinite;
}

@keyframes demoBlink { 0%, 49% { opacity: 1; } 50%, 100% { opacity: 0; } }

.editor-body.working .caret { animation: none; opacity: 0.35; }

/* text that just arrived gets a brief highlight, so you see it land */
.fresh { animation: demoLand 1.1s ease-out; border-radius: 3px; }

@keyframes demoLand {
  0%   { background: rgba(255, 112, 0, 0.22); }
  100% { background: transparent; }
}

/* ---- status bar ---- */

/* Three tracks with equal side fractions, so the meter sits dead centre no
   matter how the status text or the word count changes width, and nothing
   in the bar can shift anything else. */
.editor-bar {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 14px;
  padding: 12px 28px;
  border-top: 1px solid var(--color-border-light);
  background: #fcfbfd;
}

.status {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  font-size: 0.88rem;
  font-weight: 600;
  color: var(--color-text-muted);
  justify-self: start;
  min-width: 168px;   /* room for the longest state, so the label never reflows */
}

.status .dot {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--color-border);
  flex-shrink: 0;
}

.status.live .dot { background: #e5498a; animation: demoPulse 1.1s ease-in-out infinite; }
.status.live { color: #d63384; }
.status.busy .dot { background: var(--color-orange); }
.status.busy { color: var(--color-orange); }

@keyframes demoPulse {
  0%, 100% { transform: scale(1); box-shadow: 0 0 0 0 rgba(229, 73, 138, 0.45); }
  50%      { transform: scale(1.15); box-shadow: 0 0 0 6px rgba(229, 73, 138, 0); }
}

/* The centre slot holds the meter AND the short status messages, stacked on
   top of each other in a box of fixed size. Both are absolutely positioned, so
   swapping one for the other cannot move a single pixel of the rest of the page.
   Anything brief enough to fit belongs here rather than in the error box below,
   which pushes the page around when it appears. */
.centre-slot {
  position: relative;
  width: 230px;
  height: 24px;
  justify-self: center;
}

/* Mirrored level meter: loudest band in the middle, tapering out both ways. */
.levels {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 3px;
  opacity: 0;
  transition: opacity 0.2s ease;
}

.levels.active { opacity: 1; }

.slot-msg {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.84rem;
  font-weight: 600;
  color: var(--color-text-muted);
  white-space: nowrap;
  opacity: 0;
  transition: opacity 0.25s ease;
  pointer-events: none;
}

.slot-msg.show { opacity: 1; }

.levels span {
  width: 3px;
  height: 3px;
  border-radius: 2px;
  background: var(--gradient-hero);
  transition: height 0.07s linear;
}

.bar-actions {
  display: flex;
  align-items: center;
  gap: 12px;
  justify-self: end;
}

.bar-btn {
  border: 1px solid var(--color-border);
  background: var(--color-bg);
  color: var(--color-text-light);
  font-family: var(--font-family);
  font-size: 0.82rem;
  font-weight: 600;
  padding: 7px 14px;
  border-radius: 999px;
  cursor: pointer;
  transition: all 0.18s ease;
}

.bar-btn:hover:not(:disabled) { border-color: var(--color-orange); color: var(--color-orange); }

/* The open menu inherits the control's colour, which turned the whole language
   list orange on hover. Options get their own explicit colours. */
.lang-select option {
  color: var(--color-text);
  background: var(--color-bg);
  font-weight: 400;
}
.bar-btn:disabled { opacity: 0.4; cursor: default; }


.lang-select {
  width: 190px;              /* fits 'Auto-detect language'; fixed so the bar never shifts */
  appearance: none;
  padding-right: 26px;
  text-overflow: ellipsis;
  background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath fill='%23888899' d='M1 1l5 5 5-5'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 11px center;
  background-size: 9px;
}

/* The challenge lives here, above the button and inside the first screenful.
   Reserved height 0 until it is needed, so it costs nothing when it never is. */
.challenge-slot {
  display: flex;
  justify-content: center;
  margin: 0 auto;
}

.challenge-slot.show { margin: 0 auto 18px; }

/* ---- hold to talk ---- */

.ptt {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  margin: 14px auto 34px;  /* the button sits ABOVE the card, so it needs air on both sides */
  padding: 14px 30px;
  min-width: 300px;     /* the label changes between states; the button must not */
  border: none;
  border-radius: 999px;
  background: var(--gradient-button);
  color: #fff;
  font-family: var(--font-family);
  font-size: 1rem;
  font-weight: 600;
  cursor: pointer;
  box-shadow: 0 8px 24px rgba(255, 112, 0, 0.28);
  touch-action: none;
  user-select: none;
  -webkit-user-select: none;
  transition: transform 0.15s ease, box-shadow 0.15s ease, background 0.25s ease;
}

.ptt:hover { transform: translateY(-1px); box-shadow: 0 12px 30px rgba(255, 112, 0, 0.36); }
.ptt:active, .ptt.held { transform: scale(0.98); background: var(--gradient-button-pink); }
.ptt:disabled { opacity: 0.5; cursor: default; transform: none; }

.ptt i { font-size: 1.05rem; }

/* Reserve the error row, so showing a message never pushes the page down. */
.demo-error {
  visibility: hidden;
  max-width: 560px;
  margin: 16px auto 0;
  background: #fff5f5;
  border: 1px solid #ffd9d9;
  color: #a02020;
  border-radius: var(--radius-lg);
  padding: 12px 18px;
  font-size: 0.9rem;
  text-align: center;
  min-height: 44px;
}

.demo-error.show { visibility: visible; }

/* The strip always occupies its final height, from page load, even while it is
   invisible. Growing it on reveal would push the download call to action and
   everything under it down the page, which is the jump we keep designing out.
   Only the contents fade in. */
.demo-tips {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: 10px;
  margin-top: 18px;
  min-height: 40px;
}

/* Each item starts low and faded, then springs into place. Staggering them a
   tenth of a second apart reads as the suggestions arriving one by one rather
   than a block appearing, which is the whole point of holding them back. */
/* Pin down the box metrics rather than inheriting them. On our own site a global
   rule leaks margin-bottom:16px and a line-height onto these spans, and flexbox
   centres MARGIN boxes, so that stray margin was silently doing the vertical
   alignment for us. A partner page without our global stylesheet got the label
   sitting 8px high. Stating both here makes the strip render the same anywhere. */
.demo-tips .tips-lead,
.demo-tips .tip {
  margin: 0;
  line-height: 1.4;
}

/* The label is a bare text span next to pills that carry vertical padding, so
   centring their boxes still leaves the label's text reading high against the
   pill text. Nudge the label onto the pill text's optical centre. Measured, not
   guessed: with the metrics above pinned, this is 8px on any page. */
.demo-tips .tips-lead {
  position: relative;
  top: 8px;
}

.demo-tips .tips-lead,
.demo-tips .tip {
  opacity: 0;
  transform: translateY(10px) scale(0.94);
}

.demo-tips.show .tips-lead,
.demo-tips.show .tip {
  animation: tipIn 0.6s cubic-bezier(0.34, 1.4, 0.5, 1) forwards;
}

/* Counted by how many .tip siblings precede each one, NOT by nth-of-type: the
   label is a span too, so nth-of-type numbered it as the first one and the last
   pill fell through with no delay and animated first. */
.demo-tips.show .tip                { animation-delay: 0.10s; }
.demo-tips.show .tip ~ .tip         { animation-delay: 0.22s; }
.demo-tips.show .tip ~ .tip ~ .tip  { animation-delay: 0.34s; }

/* Bounces into existence: overshoots up and slightly oversized, drops back a
   little past the mark, then settles. */
@keyframes tipIn {
  0%   { opacity: 0; transform: translateY(16px) scale(0.78); }
  45%  { opacity: 1; transform: translateY(-8px) scale(1.10); }
  66%  { transform: translateY(3px) scale(0.96); }
  82%  { transform: translateY(-3px) scale(1.03); }
  93%  { transform: translateY(1px) scale(0.99); }
  100% { opacity: 1; transform: translateY(0) scale(1); }
}

/* Reduced motion still gets an animation, just not a moving one. Turning it off
   entirely was a mistake: Windows ships with "show animations" disabled on a lot
   of machines, and those visitors saw the pills simply pop into existence. A
   staggered fade carries the same "arriving one by one" feeling with no motion
   at all, which is what the preference actually asks for. */
@media (prefers-reduced-motion: reduce) {
  .demo-tips.show .tips-lead,
  .demo-tips.show .tip {
    animation: tipFade 0.45s ease forwards;
  }

  @keyframes tipFade {
    from { opacity: 0; transform: none; }
    to   { opacity: 1; transform: none; }
  }
}

.demo-tips .tips-lead {
  font-size: 0.78rem;
  font-weight: 600;
  letter-spacing: 0.6px;
  text-transform: uppercase;
  color: var(--color-text-muted);
  line-height: 1;
}

/* Fixed height and clipped on purpose. The emoji glyph carries a much taller
   line box than the text beside it, and left alone it inflated the whole flex
   row to 50px while the pills stayed 34px, which is what left them sitting
   high against the label. Pinning the height removes the cause. */
.tip {
  display: inline-flex;
  align-items: center;
  height: 32px;
  box-sizing: border-box;
  overflow: hidden;
  position: relative;
  top: 8px;             /* optical, against the uppercase label beside them */
  gap: 7px;
  font-size: 0.84rem;
  color: var(--color-text-light);
  background: var(--color-bg);
  border: 1px solid var(--color-border);
  border-radius: 999px;
  padding: 0 13px;
  box-shadow: var(--shadow-card);
}

.tip b { font-weight: 600; color: var(--color-text); }

.tip .arrow { color: var(--color-text-muted); }

/* What the words turn into. A symbol rather than a description, so the pill
   shows the result instead of explaining it. */
.tip .result {
  display: inline-flex;
  align-items: center;
  font-weight: 700;
  font-size: 0.95rem;
  line-height: 1;
  color: var(--color-orange);
}

.tip .result.purple { color: rgb(133, 46, 209); }

.demo-cta { text-align: center; padding: 64px 24px 80px; }

.demo-cta h2 {
  font-size: clamp(1.6rem, 3.5vw, 2.2rem);
  color: var(--color-text-dark);
  margin-bottom: 12px;
}

.demo-cta p { color: var(--color-text-light); margin-bottom: 28px; }

/* The line break in the headline exists only on narrow screens; on desktop the
   sentence fits comfortably on one line and a forced break would look wrong. */
.only-mobile { display: none; }

/* Mobile only. The whole point is to get the headline, the button, the card and
   the suggestions into one screenful without scrolling, so every vertical gap
   here is tighter than its desktop counterpart. */
@media (max-width: 640px) {
  .only-mobile { display: inline; }

  .demo-hero { padding: 28px 20px 14px; }
  .demo-hero .eyebrow { margin-bottom: 9px; font-size: 12px; }
  .demo-hero h1 { font-size: clamp(1.55rem, 7.2vw, 2rem); line-height: 1.2; margin-bottom: 8px; }
  .demo-hero .lede { font-size: 0.92rem; }

  .demo-stage { padding: 0 16px 32px; }

  .ptt { min-width: 0; width: 100%; margin: 0 auto 16px; padding: 13px 20px; }

  .editor-chrome { padding: 2px 18px 0; }
  .chrome-row { padding: 7px 0; font-size: 0.86rem; }
  .chrome-row .label { width: 52px; }
  .editor-body { height: 150px; padding: 16px 18px 14px; font-size: 1rem; }

  .editor-bar { grid-template-columns: 1fr auto; gap: 8px; padding: 9px 14px; }
  /* The status can wrap to two lines on a narrow bar; keeping it on one keeps
     the row the same height whatever it says. */
  .status { min-width: 0; font-size: 0.76rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .centre-slot { display: none; }
  /* Small enough to fit beside the status on a 375px screen, wide enough that
     "Auto-detect language" is not cut off. */
  .lang-select { width: 158px; font-size: 0.74rem; padding-right: 22px; background-position: right 8px center; }

  /* The suggestions wrap to two lines on a phone, so the strip needs room for
     both and tighter gaps to stay on screen. */
  .demo-tips { gap: 7px; margin-top: 12px; min-height: 72px; align-content: center; }
  .demo-tips .tips-lead { font-size: 0.72rem; width: 100%; text-align: center; }
  .tip { height: 29px; padding: 0 11px; font-size: 0.79rem; gap: 6px; top: 0; }

  .demo-error { margin-top: 12px; font-size: 0.85rem; padding: 10px 14px; }
}

/* Short phones (an iPhone SE is 667px tall) need a little more taken out again,
   or the suggestions fall just past the bottom of the screen. Scoped to short
   screens so taller phones keep the roomier version above. */
@media (max-width: 640px) and (max-height: 700px) {
  .demo-hero { padding: 16px 20px 8px; }
  .demo-hero .lede { font-size: 0.86rem; }
  .demo-hero .eyebrow { margin-bottom: 7px; }
  .editor-body { height: 118px; padding: 14px 18px 12px; }
  .ptt { margin-bottom: 12px; padding: 12px 20px; }
  .demo-tips { margin-top: 10px; }
}
