/* ═══════════════════════════════════════════════════════════
   DEMO FORMATS  —  the #demo section switcher.

   The page states the three-format claim three times before this
   section (hero subtitle, .cf-fan, the workflow outputs) and every
   one of them is an illustration. This is where it gets shown: the
   same run, in all three forms, one click apart.

   Two things carry the argument and they pull in opposite
   directions on purpose.

   The source line above the stage says ONE RUN. It repeats the
   .cf-source pills the visitor already scrolled past, so the tie
   back to "one link in" is made by recognition, not by copy.

   The chrome INSIDE each panel says THREE SEPARATE THINGS. A video
   frame, a shared-link browser frame and a document window are
   three different objects you would send to three different people.
   Giving all three a single shared chrome would have read as three
   views of one asset, which undersells it.

   What holds them together physically is the stage: one box, fixed
   height, panels crossfaded in place. Nothing reflows on a tab
   change, so the switch reads as the same object turning rather
   than as a carousel of different ones.

   Namespaced dfx- and scoped under .dfx, matching the per-section
   convention already in use (cf-, wf-, bfy-, idp-, dsp-).
   ═══════════════════════════════════════════════════════════ */

.dfx {
  --dfx-ink:    rgb(28, 28, 28);
  --dfx-ink-2:  rgb(84, 84, 84);
  --dfx-ink-3:  rgba(28, 28, 28, .46);
  --dfx-hair:   rgba(28, 28, 28, .09);
  --dfx-hair-2: rgba(28, 28, 28, .055);
  --dfx-accent: #5B5EF0;
  --dfx-paper:  #fff;
  --dfx-mono:   'JetBrains Mono', ui-monospace, monospace;
  --dfx-sans:   'Instrument Sans', sans-serif;

  width: 100%;
  max-width: 1020px;
  padding: 0 20px;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 20px;
}

/* ── the source line ───────────────────────────────────────
   Deliberately a quote of .cf-source. Same white lozenge, same
   mono-then-sans pairing, same plus sitting in even air between
   two text runs. It is not absolutely positioned here because it
   has no diagram to sit on top of. */
.dfx-source {
  display: inline-flex;
  align-items: center;
  max-width: 100%;
  background: #fff;
  border: 1px solid var(--dfx-hair-2);
  border-radius: 100px;
  box-shadow:
    0 2.29px 2.29px rgba(28, 28, 28, .02),
    0 12px 22px -8px rgba(40, 36, 80, .16);
}

.dfx-pill {
  display: inline-flex;
  align-items: center;
  white-space: nowrap;
  padding: 10px 13px 10px 17px;
  font-family: var(--dfx-mono);
  font-size: 12.5px;
  letter-spacing: .01em;
  color: var(--dfx-ink);
}

/* the prompt reads as something a person typed, not a field value */
.dfx-pill--prompt {
  padding: 10px 17px 10px 13px;
  font-family: var(--dfx-sans);
  font-size: 13px;
  color: var(--dfx-ink-2);
  overflow: hidden;
  text-overflow: ellipsis;
}

.dfx-plus {
  flex: none;
  font-family: var(--dfx-mono);
  font-size: 14px;
  line-height: 1;
  color: rgba(28, 28, 28, .34);
}

/* ── the stage ─────────────────────────────────────────────
   One box that never changes size. Panels are stacked in it and
   crossfaded, so switching tabs cannot shift the page under the
   pointer.

   16:10, not the video's 16:9. The walkthrough needs the height: at
   16:9 the app screen is only ~470px and the Describe step loses its
   chips, which is the same squeeze that made /interactive-demos give
   its own screen 4:3 between 761 and 1120px. The video centres in
   the extra height instead of dictating it. */
.dfx-stage {
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 10;
}

.dfx-panel {
  position: absolute;
  inset: 0;
  opacity: 0;
  visibility: hidden;
  transform: scale(.992);
  transition: opacity .22s ease, transform .22s ease, visibility 0s linear .22s;
}

.dfx-panel.is-on {
  opacity: 1;
  visibility: visible;
  transform: none;
  transition: opacity .26s ease, transform .26s ease, visibility 0s;
}

/* ═══ PANEL 1 — VIDEO ══════════════════════════════════════ */

/* Centred in the stage at its own 16:9 rather than stretched to fill
   it. Letterboxing the video inside its own frame would read as a
   bug; clear air above and below reads as a fit. */
.dfx-panel[data-panel='video'] { display: flex; align-items: center; }

.dfx-video {
  width: 100%;
  border-radius: 20px;
  overflow: hidden;
  background: rgb(246, 246, 246);
  border: 1px solid #fff;
  box-shadow:
    0 .6px .6px rgba(28, 28, 28, .01),
    0 2.29px 2.29px rgba(28, 28, 28, .03),
    0 10px 10px rgba(28, 28, 28, .12),
    0 -6px 6px -5px #fff;
}

.dfx-video media-player {
  width: 100%;
  height: auto;
  aspect-ratio: 16 / 9;
  border-radius: 0;
  display: block;
}

/* ═══ PANEL 2 — INTERACTIVE DEMO ═══════════════════════════
   The player from /interactive-demos, running inside the stage.

   The adapter below is the only hand-written part: it hands the
   player a height instead of an aspect ratio (the stage already
   decided that), and drops the parts of its chrome that belong to
   a full page rather than a panel. Everything after the adapter is
   the ported stylesheet.
   ═══════════════════════════════════════════════════════════ */

.dfx-int {
  /* The player's own tokens. They live in a :root block on the source
     page, which the extraction skipped because :root is not one of the
     scoped families — so every ported rule using them silently fell
     back to nothing. That is what made the caption bar transparent
     (white text on a white page) and the current step dot invisible.
     Redeclared here rather than on :root so they cannot leak. */
  --idp-ink:        rgb(18, 18, 18);
  --idp-ink-2:      rgb(92, 92, 92);
  --idp-ink-3:      rgb(110, 110, 110);
  --idp-blue:       #4043FF;
  --idp-blue-soft:  rgba(64, 67, 255, .08);
  --idp-line:       rgba(0, 0, 0, .08);
  --idp-line-soft:  rgba(0, 0, 0, .05);
  --idp-surface:    #ffffff;
  --idp-base:       rgb(246, 246, 246);
  --idp-dark:       #0e0e10;
  --idp-green:      #16a34a;
  --idp-card-shadow: 0 1px 2px rgba(0, 0, 0, .03), 0 6px 20px rgba(0, 0, 0, .05);
  --idp-lift-shadow: 0 2px 4px rgba(0, 0, 0, .04), 0 18px 44px rgba(0, 0, 0, .10);

  /* --ds-ink-2 and --ds-ink-3 are referenced by a dozen rules in the
     Video and Document panes and are defined nowhere — not here and
     not on /interactive-demos either, where an undefined var() makes
     `color` fall back to inherit, so that secondary text renders at
     full ink instead of grey. Same bug is live on that page. Defined
     to the greys they are plainly meant to be. */
  --ds-ink-2: #6B7280;
  --ds-ink-3: #9CA3AF;

  position: relative;
  width: 100%;
  height: 100%;
}

/* the player fills the stage and lays itself out as bar / screen / foot */
.dfx-int .idp-player {
  display: flex;
  flex-direction: column;
  height: 100%;
}

.dfx-int .idp-player-bar,
.dfx-int .idp-player-foot { flex: none; }

/* the screen takes what is left. min-height:0 is what makes the app's
   own scrollers work instead of the page growing past its clip. */
.dfx-int .idp-screen {
  flex: 1;
  min-height: 0;
  aspect-ratio: auto;
}

/* the bloom and the ground shadow the player sits in on its own page */
.dfx-int::before {
  content: '';
  position: absolute;
  inset: -7% -5% -10%;
  z-index: -2;
  pointer-events: none;
  background:
    radial-gradient(ellipse 60% 55% at 28% 18%, rgba(64, 67, 255, .15), transparent 68%),
    radial-gradient(ellipse 55% 50% at 78% 82%, rgba(123, 77, 255, .12), transparent 68%);
  filter: blur(34px);
}

/* The entrance animation belongs to that page's hero, where the player
   drops in on load. Here the panel is revealed by a tab, so it would
   replay on every switch. */
.dfx-int .idp-player-stage,
.dfx-int .idp-player { animation: none; }

/* The share button is ours, not the player's: that page puts a plain
   CTA here and we want the same one the other two panels point at. */
.dfx-int .idp-pb-cta {
  flex: none;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 25px;
  padding: 0 11px;
  border-radius: 7px;
  background: #16161C;
  color: #fff;
  font-family: 'Instrument Sans', sans-serif;
  font-size: 11.5px;
  font-weight: 600;
  text-decoration: none;
  white-space: nowrap;
  transition: opacity .18s ease;
}

.dfx-int .idp-pb-cta:hover { opacity: .85; }
.dfx-int .idp-pb-cta svg { width: 11px; height: 11px; }

/* ── the compressed first screen ───────────────────────────
   Steps 1 and 2 of the source player are two separate frames: the
   URL on one, the prompt on the next. They are one frame here, with
   the prompt card revealed by the first click, so a visitor watches
   the address type itself, clicks, and then watches the brief type
   itself into the box below it. Two beats, one screen, and the step
   counter still runs to five. */
/* display, not opacity: the brief card and the Continue button are
   ~270px of layout, and an invisible-but-present copy of them pushed
   the address field itself off the top of the first beat. */
.dfx-int [data-beat='2'] { display: none; }

/* The centred heading and the nudge banner are the address step's own.
   They stay out of the way once the brief card arrives, which is also
   what the source player shows on its second frame. */
.dfx-int .idp-frame.beat-2 [data-only='1'] { display: none; }

.dfx-int .idp-frame.beat-2 [data-beat='2'] {
  display: flex;
  flex-direction: column;
  gap: 16px;
  flex: none;
  animation: dfxBeatIn .42s cubic-bezier(.2, .9, .3, 1) both;
}

/* The brief card is .ds-card.is-scroll, which carries min-height:0 and
   overflow-y:auto so that on the source page, where it is the only
   thing on its frame, it can scroll inside a fixed screen. Here it is
   one child of a column among several, and those two properties let it
   shrink to 42px around 180px of content with no scrollbar to reveal
   what was lost: the brief simply vanished between its label and the
   Continue button. It keeps its natural height, and .vg-page does the
   scrolling instead, which is what revealTarget already assumes. */
.dfx-int [data-beat='2'] .ds-card {
  flex: none;
  min-height: auto;
  overflow: visible;
}

@keyframes dfxBeatIn {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: none; }
}

/* the first beat's target stops asking to be clicked once it has been */
.dfx-int .idp-frame.beat-2 [data-beat='1'] .idp-tw::before { animation: none; box-shadow: none; }
.dfx-int .idp-frame.beat-2 [data-beat='1'] .idp-tt { display: none; }
.dfx-int .idp-frame.beat-2 [data-beat='1'] .idp-draw { display: none; }



/* ═══ THE PLAYER, PORTED VERBATIM ══════════════════════════
   Everything below is the interactive player from
   /interactive-demos, lifted rule for rule rather than
   re-approximated, and scoped under .dfx-int so the idp-, ds-,
   dp-, bl- and vg- families cannot reach the rest of the home
   page. None of them appears in styles.css, coverage-fan.css or
   interactive-visual.css, so the scope is belt and braces.

   Verbatim on purpose. An approximation of this app is worse
   than useless: the point of the panel is that a visitor
   recognises the product they have already seen, and two
   attempts at drawing it by hand both failed that test.

   Two deliberate changes, and only two: .idp-screen loses its
   aspect-ratio because .dfx-stage owns the height here, and
   every selector gains a .dfx-int prefix. The source's own
   comments are kept, lifted above their rule rather than left
   in the prelude, where prefixing would have glued them to the
   selector and voided the rule.

   Source of truth is interactive-demos.html. If that player
   changes, re-run the extraction rather than patching this.
   ═══════════════════════════════════════════════════════════ */

@keyframes idpUnderline {
  to { transform:scaleX(1); }
}

/* =====================================================
       HERO PLAYER — the clickable demo-of-the-demo
    ===================================================== */
.dfx-int .idp-player-stage {
  width:100%; position:relative;
  animation:idpStage 1s .5s cubic-bezier(.2,.85,.3,1) both;
}

@keyframes idpStage {
  from { opacity:0; transform:translateY(40px) scale(.965); }
  to   { opacity:1; transform:none; }
}

.dfx-int .idp-player-stage::before {
  content:''; position:absolute; inset:-9% -6% -14%; z-index:-2; pointer-events:none;
  background:
  radial-gradient(ellipse 60% 55% at 28% 18%, rgba(64,67,255,.17), transparent 68%),
  radial-gradient(ellipse 55% 50% at 78% 82%, rgba(123,77,255,.14), transparent 68%);
  filter:blur(34px);
}

.dfx-int .idp-player-stage::after {
  content:''; position:absolute; left:8%; right:8%; bottom:-24px; height:64px; z-index:-1;
  background:radial-gradient(ellipse at center, rgba(16,16,28,.20) 0%, rgba(0,0,0,0) 72%);
  filter:blur(11px);
}

.dfx-int .idp-player {
  background:#fff; border-radius:20px; overflow:hidden; position:relative;
  box-shadow:
  0 0 0 1px rgba(16,16,28,.07),
  0 1px 1px rgba(16,16,28,.04),
  0 4px 8px rgba(16,16,28,.04),
  0 16px 32px rgba(16,16,28,.07),
  0 40px 72px -18px rgba(16,16,28,.16);
}

.dfx-int .idp-player::after {
  content:''; position:absolute; inset:0; border-radius:20px; pointer-events:none; z-index:20;
  box-shadow:inset 0 1px 0 rgba(255,255,255,.9);
}

.dfx-int .idp-player-bar {
  display:flex; align-items:center; gap:12px;
  padding:11px 16px; border-bottom:1px solid var(--idp-line-soft);
  background:linear-gradient(180deg,#fcfcfd,#f7f7f9);
}

.dfx-int .idp-pb-dots {
  display:flex; gap:6px; flex-shrink:0;
}

.dfx-int .idp-pb-dots i {
  width:9px; height:9px; border-radius:50%; display:block;
}

.dfx-int .idp-pb-dots i:nth-child(1) {
  background:#ff5f57;
}

.dfx-int .idp-pb-dots i:nth-child(2) {
  background:#febc2e;
}

.dfx-int .idp-pb-dots i:nth-child(3) {
  background:#28c840;
}

.dfx-int .idp-pb-url {
  flex:1; height:24px; border-radius:7px; background:#fff;
  border:1px solid var(--idp-line); display:flex; align-items:center; gap:6px;
  padding:0 10px; font-family:"Inter",sans-serif; font-size:11px; color:var(--idp-ink-3);
  max-width:320px;
}

.dfx-int .idp-pb-url svg {
  width:10px; height:10px; color:var(--idp-green);
}

/* Screen canvas */
.dfx-int .idp-screen {
  position:relative;  background:#f4f5f8;
  overflow:hidden; user-select:none;
}

/* ═══ PLAYER CHROME ══════════════════════════════════════ */
.dfx-int .idp-player-bar {
  display:flex; align-items:center; gap:12px;
  padding:11px 16px; border-bottom:1px solid var(--idp-line-soft);
  background:linear-gradient(180deg,#fcfcfd,#f7f7f9);
}

.dfx-int .idp-pb-dots {
  display:flex; gap:6px; flex-shrink:0;
}

.dfx-int .idp-pb-dots i {
  width:9px; height:9px; border-radius:50%; display:block;
}

.dfx-int .idp-pb-dots i:nth-child(1) {
  background:#ff5f57;
}

.dfx-int .idp-pb-dots i:nth-child(2) {
  background:#febc2e;
}

.dfx-int .idp-pb-dots i:nth-child(3) {
  background:#28c840;
}

.dfx-int .idp-pb-url {
  flex:1; height:25px; border-radius:7px; background:#fff;
  border:1px solid var(--idp-line); display:flex; align-items:center; gap:6px;
  padding:0 10px; font-family:"Inter",sans-serif; font-size:11px; color:var(--idp-ink-3);
  max-width:330px;
}

.dfx-int .idp-pb-url svg {
  width:10px; height:10px; color:var(--idp-green); flex-shrink:0;
}

.dfx-int .idp-player-foot {
  display:flex; align-items:center; gap:14px; flex-wrap:wrap;
  padding:11px 16px; border-top:1px solid var(--idp-line-soft); background:#fff;
}

.dfx-int .idp-dots {
  display:flex; align-items:center; gap:6px;
}

.dfx-int .idp-dots button {
  width:26px; height:5px; border-radius:99px; background:#e4e5ea; padding:0;
  transition:background .3s ease, width .3s ease;
}

.dfx-int .idp-dots button.done {
  background:rgba(64,67,255,.4);
}

.dfx-int .idp-dots button.on {
  background:var(--idp-blue); width:38px;
}

/* The bars are 5px tall on purpose, which is a 26x5 tap target: fine with a
       mouse, a guess with a thumb, and under the 24x24 of WCAG 2.5.8. Widen the
       target rather than the bar, so the hit area is 24px tall and the design
       does not change. */
.dfx-int .idp-dots button {
  position:relative;
}

.dfx-int .idp-dots button::after {
  content:''; position:absolute; left:-2px; right:-2px;
  top:50%; transform:translateY(-50%); height:24px;
}

.dfx-int .idp-foot-label {
  font-family:"Instrument Sans",sans-serif; font-size:12px; font-weight:600;
  color:var(--idp-ink-3); white-space:nowrap;
}

.dfx-int .idp-foot-right {
  margin-left:auto; display:flex; align-items:center; gap:9px;
}

.dfx-int .idp-foot-chip {
  display:inline-flex; align-items:center; gap:7px; padding:5px 11px; border-radius:99px;
  border:1px solid var(--idp-line); background:#fff;
  font-family:"Instrument Sans",sans-serif; font-size:11.5px; font-weight:600; color:var(--idp-ink-2);
  transition:color .2s ease, border-color .2s ease, background .2s ease;
}

.dfx-int .idp-foot-chip svg {
  width:12px; height:12px;
}

.dfx-int .idp-foot-chip:hover {
  color:var(--idp-ink); border-color:rgba(0,0,0,.18);
}

.dfx-int .idp-foot-chip.sound-on {
  color:var(--idp-blue); border-color:rgba(64,67,255,.35); background:var(--idp-blue-soft);
}

.dfx-int .idp-eq {
  display:flex; align-items:flex-end; gap:1.5px; height:11px;
}

.dfx-int .idp-eq i {
  width:2px; border-radius:99px; background:currentColor; display:block; height:30%;
}

.dfx-int .idp-foot-chip.sound-on .idp-eq i:nth-child(1) {
  animation:idpEq .9s  ease-in-out infinite;
}

.dfx-int .idp-foot-chip.sound-on .idp-eq i:nth-child(2) {
  animation:idpEq .7s  ease-in-out infinite .1s;
}

.dfx-int .idp-foot-chip.sound-on .idp-eq i:nth-child(3) {
  animation:idpEq 1.1s ease-in-out infinite .05s;
}

.dfx-int .idp-foot-chip.sound-on .idp-eq i:nth-child(4) {
  animation:idpEq .8s  ease-in-out infinite .15s;
}

@keyframes idpEq {
  0%,100%{ height:25%; } 50%{ height:100%; }
}

/* ═══ THE REAL DEMOSMITH UI ══════════════════════════════
       Structure, labels, colours and the generation stages all come
       from the app at ~/Desktop/ZelieUI, so what a visitor clicks
       through is what they will actually sign into.
    ═══════════════════════════════════════════════════════════ */
.dfx-int .vg {
  --ds-indigo:#4F46E5; --ds-indigo-5:#6366F1; --ds-indigo-1:#E0E7FF;
  --ds-purple-5:#A855F7; --ds-ink:#111827; --ds-body:#374151;
  --ds-muted:#6B7280; --ds-faint:#9CA3AF; --ds-line:#E5E7EB;
  --ds-wash:#F9FAFB; --ds-surface:#FFFFFF; --ds-raise:#F3F4F6;
}

/* Dark mode, toggled from the app's own moon button */
.dfx-int .idp-screen.is-dark .vg {
  --ds-ink:#F9FAFB; --ds-body:#D1D5DB; --ds-muted:#9CA3AF; --ds-faint:#6B7280;
  --ds-line:#374151; --ds-wash:#111827; --ds-surface:#1F2937; --ds-raise:#374151;
  --ds-indigo-1:#312E81;
}

.dfx-int .idp-screen.is-dark .ds-lucky {
  background:#312E81; border-color:#4338CA;
}

.dfx-int .idp-screen.is-dark .vg-nav.on {
  background:#312E81; color:#C7D2FE;
}

.dfx-int .idp-screen.is-dark .vg-nav.on svg {
  color:#C7D2FE;
}

.dfx-int .idp-screen.is-dark .ds-chip.on {
  background:#312E81; border-color:#4338CA; color:#C7D2FE;
}

.dfx-int .idp-screen.is-dark .ds-pill.pub {
  background:#064E3B; color:#6EE7B7;
}

.dfx-int .idp-screen.is-dark .ds-gen-halo {
  background:#312E81; color:#C7D2FE;
}

/* --ds-indigo-1 darkens to indigo-900 but --ds-indigo stays indigo-600, so
       these chips came out dark-on-dark at 1.8:1. The app lightens the glyph
       to indigo-300 in dark mode; so do we. */
.dfx-int .idp-screen.is-dark .ds-idhead-ic,
.dfx-int .idp-screen.is-dark .ds-idlist i {
  color:#A5B4FC;
}

.dfx-int .idp-screen.is-dark .ds-gen.is-done .ds-gen-halo {
  background:#064E3B; color:#6EE7B7;
}

.dfx-int .idp-screen.is-dark .ds-tl {
  background:rgba(255,255,255,.03);
}

.dfx-int .idp-screen.is-dark .ds-tl-i {
  background:#374151; color:#9CA3AF;
}

.dfx-int .idp-screen.is-dark .ds-tl.is-now {
  background:#1E1B4B; border-color:#4338CA; box-shadow:0 4px 16px rgba(0,0,0,.45);
}

.dfx-int .idp-screen.is-dark .ds-tl.is-now .ds-tl-i {
  background:#312E81; color:#C7D2FE;
}

.dfx-int .idp-screen.is-dark .ds-tl.is-now .ds-tl-n {
  color:#C7D2FE;
}

.dfx-int .idp-screen.is-dark .ds-tl.is-done {
  background:#022C22; border-color:#065F46;
}

.dfx-int .idp-screen.is-dark .ds-tl.is-done .ds-tl-i {
  background:#064E3B; color:#6EE7B7;
}

.dfx-int .idp-screen.is-dark .ds-bar-track,
.dfx-int .idp-screen.is-dark .ds-usage-bar {
  background:#374151;
}

/* Scrollbars inside the mock app. Ported from .scrollbar-thin in the
       app's index.css: 6px, gray-400 thumb on a gray-200 track, and
       indigo-600 on gray-800 once dark mode is on. Without it the browser
       default put a fat pale bar down the side of a dark panel. */
.dfx-int .vg-scroll {
  scrollbar-width: thin;
  scrollbar-color: rgb(156 163 175) rgb(229 231 235);
}

.dfx-int .vg-scroll::-webkit-scrollbar {
  width:6px; height:6px;
}

.dfx-int .vg-scroll::-webkit-scrollbar-track {
  background:rgb(229 231 235); border-radius:3px;
}

.dfx-int .vg-scroll::-webkit-scrollbar-thumb {
  background:rgb(156 163 175); border-radius:3px; transition:background-color .2s ease;
}

.dfx-int .vg-scroll::-webkit-scrollbar-thumb:hover {
  background:rgb(107 114 128);
}

.dfx-int .idp-screen.is-dark .vg-scroll {
  scrollbar-color: rgb(67 56 202) rgb(31 41 55);
}

.dfx-int .idp-screen.is-dark .vg-scroll::-webkit-scrollbar-track {
  background:rgb(31 41 55);
}

.dfx-int .idp-screen.is-dark .vg-scroll::-webkit-scrollbar-thumb {
  background:rgb(67 56 202);
}

.dfx-int .idp-screen.is-dark .vg-scroll::-webkit-scrollbar-thumb:hover {
  background:rgb(55 48 163);
}

/* Sidebar collapse, toggled from the app's own panel button */
.dfx-int .idp-screen.is-collapsed .vg-side {
  display:none;
}

/* Sidebar */
.dfx-int .vg-side {
  width:224px; background:var(--ds-surface); border-right:1px solid var(--ds-line); padding:14px 12px;
}

.dfx-int .ds-logo {
  display:flex; flex-shrink:0; align-items:center; gap:10px; padding:2px 4px 12px;
}

.dfx-int .ds-logo-mark {
  width:30px; height:30px; border-radius:9px; background:var(--ds-indigo);
  display:flex; align-items:center; justify-content:center; overflow:hidden; flex-shrink:0;
}

.dfx-int .ds-logo-mark img {
  width:100%; height:100%; object-fit:contain; transform:scale(1.5);
}

.dfx-int .ds-logo-word {
  font-family:"Instrument Sans",sans-serif; font-size:16px; font-weight:700;
  color:var(--ds-ink); letter-spacing:-0.02em;
}

/* sidebar-simple.tsx: text-lg / font-bold on an indigo-600 → purple-600
       gradient. It is deliberately much larger than the nav rows under it —
       matching their size made it read as just another list item. */
.dfx-int .ds-create {
  /* flex-shrink:0 or the sidebar column takes its overflow entirely out
  of this button — it was the only child with an explicit height, so
  a 9px deficit squashed a 44px button down to 25px. */
  display:flex; flex-shrink:0; align-items:center; justify-content:center; gap:8px; height:44px;
  border-radius:8px; margin-bottom:14px; color:#fff;
  background:linear-gradient(90deg,#4F46E5,#9333EA);
  font-family:"Instrument Sans",sans-serif; font-size:17px; font-weight:700; letter-spacing:-0.01em;
  box-shadow:0 1px 2px rgba(79,70,229,.35);
}

.dfx-int .ds-create svg {
  width:18px; height:18px;
}

.dfx-int .ds-navlabel {
  font-family:"Inter",sans-serif; font-size:10px; font-weight:600; letter-spacing:.08em;
  text-transform:uppercase; color:var(--ds-faint); padding:0 8px; margin:6px 0 4px; flex-shrink:0;
}

.dfx-int .vg-nav {
  display:flex; flex-shrink:0; align-items:center; gap:11px; padding:7px 9px; border-radius:9px;
  font-family:"Inter",sans-serif; font-size:13.5px; color:var(--ds-body); margin-bottom:1px;
}

.dfx-int .vg-nav svg {
  width:16px; height:16px; flex-shrink:0; color:var(--ds-muted);
}

.dfx-int .vg-nav.on {
  background:#EEF2FF; color:var(--ds-indigo); font-weight:600;
}

.dfx-int .vg-nav.on svg {
  color:var(--ds-indigo);
}

.dfx-int .ds-usage {
  margin-top:auto; flex-shrink:0; border:1px solid var(--ds-line); border-radius:12px; padding:11px;
}

.dfx-int .ds-usage-t {
  font-family:"Instrument Sans",sans-serif; font-size:12.5px; font-weight:600; color:var(--ds-ink);
}

.dfx-int .ds-usage-s {
  font-family:"Inter",sans-serif; font-size:11px; color:var(--ds-muted); line-height:1.45; margin-top:5px;
}

.dfx-int .ds-usage-bar {
  height:6px; border-radius:99px; background:#E5E7EB; margin:10px 0 6px; overflow:hidden;
}

.dfx-int .ds-usage-bar i {
  display:block; height:100%; width:0; border-radius:99px; background:linear-gradient(90deg,#5B4BE8,#8B5CF6);
}

.dfx-int .ds-usage-q {
  font-family:"Inter",sans-serif; font-size:10.5px; color:var(--ds-faint);
}

.dfx-int .ds-upgrade {
  display:flex; align-items:center; justify-content:center; height:32px; margin-top:11px;
  border:1px solid var(--ds-line); border-radius:9px;
  font-family:"Instrument Sans",sans-serif; font-size:12.5px; font-weight:600; color:var(--ds-indigo);
}

/* Top bar */
.dfx-int .vg-top {
  padding:11px 20px; border-bottom:1px solid var(--ds-line); gap:14px;
}

.dfx-int .ds-collapse,
.dfx-int .ds-iconbtn {
  width:28px; height:28px; border-radius:8px; display:flex; align-items:center;
  justify-content:center; color:var(--ds-muted); background:none; border:none; padding:0;
  transition:background .15s ease, color .15s ease;
}

.dfx-int .ds-collapse:hover,
.dfx-int .ds-iconbtn:hover {
  background:var(--ds-raise); color:var(--ds-ink);
}

.dfx-int .ds-iconbtn svg {
  width:17px; height:17px;
}

.dfx-int .ds-collapse svg {
  width:17px; height:17px;
}

.dfx-int .ds-topright {
  margin-left:auto; display:flex; align-items:center; gap:16px;
}

.dfx-int .ds-topright svg {
  width:17px; height:17px; color:var(--ds-muted);
}

.dfx-int .ds-feedback {
  font-family:"Inter",sans-serif; font-size:13.5px; color:var(--ds-body);
}

.dfx-int .ds-avatar {
  width:30px; height:30px; border-radius:50%; overflow:hidden; flex-shrink:0;
  background:linear-gradient(170deg,#FDBA74 0%,#FDBA74 42%,#7DA2F0 42%);
}

/* Page shell */
/* Must be a flex column. It was a plain block, which made every `gap`
       declared on it dead and left the sections on each page stacked flush
       against one another with no spacing at all. */
.dfx-int .vg-page {
  /* flex:1 + min-height:0 is what makes overflow-y:auto mean anything.
  At flex:0 1 auto with min-height:auto this box sized to its content,
  so on a short screen it grew past .vg and got chopped by .vg's
  overflow:hidden — and because scrollHeight then equalled
  clientHeight, no scrollbar ever appeared and the Continue button
  underneath was simply unreachable. It also left dead space at the
  bottom whenever the content was short. */
  flex:1; min-height:0;
  display:flex; flex-direction:column; padding:22px 26px; gap:16px;
  background:var(--ds-wash); overflow-y:auto; overflow-x:hidden;
}

.dfx-int .ds-pagehead {
  display:flex; align-items:center; gap:13px; background:var(--ds-surface); border:1px solid var(--ds-line);
  border-radius:12px; padding:15px 18px;
}

.dfx-int .ds-pagehead-ic {
  width:34px; height:34px; border-radius:10px; flex-shrink:0; background:var(--ds-indigo);
  display:flex; align-items:center; justify-content:center;
}

.dfx-int .ds-pagehead-ic svg {
  width:17px; height:17px; color:#fff;
}

.dfx-int .vg-h1 {
  font-family:"Instrument Sans",sans-serif; font-size:17px; font-weight:700; color:var(--ds-ink); letter-spacing:-0.02em;
}

.dfx-int .vg-sub {
  font-family:"Inter",sans-serif; font-size:12px; color:var(--ds-muted); margin-top:2px;
}

.dfx-int .ds-stepcount {
  margin-left:auto; font-family:"Inter",sans-serif; font-size:12.5px; color:var(--ds-muted);
}

/* Describe / Review / Customize */
.dfx-int .ds-wizard {
  display:flex; align-items:center; justify-content:center; gap:0; padding:4px 0 2px;
}

.dfx-int .ds-wz {
  display:flex; flex-direction:column; align-items:center; gap:7px;
}

.dfx-int .ds-wz b {
  width:36px; height:36px; border-radius:50%; display:flex; align-items:center; justify-content:center;
  background:var(--ds-raise); color:var(--ds-faint);
}

.dfx-int .ds-wz b svg {
  width:16px; height:16px;
}

.dfx-int .ds-wz.on b {
  background:var(--ds-indigo); color:#fff; box-shadow:0 0 0 4px #E0E7FF;
}

.dfx-int .ds-wz span {
  font-family:"Inter",sans-serif; font-size:11.5px; color:var(--ds-faint);
}

.dfx-int .ds-wz.on span {
  color:var(--ds-indigo); font-weight:600;
}

.dfx-int .ds-wz-line {
  width:74px; height:1.5px; background:var(--ds-line); margin:0 4px 20px;
}

.dfx-int .ds-h2 {
  font-family:"Instrument Sans",sans-serif; font-size:27px; font-weight:700; color:var(--ds-ink);
  letter-spacing:-0.03em; text-align:center;
}

.dfx-int .ds-lede {
  font-family:"Inter",sans-serif; font-size:13.5px; line-height:1.55; color:var(--ds-muted);
  text-align:center; max-width:520px; margin:7px auto 0;
}

.dfx-int .ds-lucky {
  display:flex; align-items:center; gap:13px; padding:15px 17px; border-radius:12px;
  background:#EEF2FF; border:1px solid #C7D2FE;
}

.dfx-int .ds-lucky-ic {
  width:34px; height:34px; border-radius:9px; background:var(--ds-indigo); flex-shrink:0;
  display:flex; align-items:center; justify-content:center;
}

.dfx-int .ds-lucky-ic svg {
  width:17px; height:17px; color:#fff;
}

.dfx-int .ds-lucky-t {
  font-family:"Instrument Sans",sans-serif; font-size:13.5px; font-weight:600; color:var(--ds-ink);
}

.dfx-int .ds-lucky-s {
  font-family:"Inter",sans-serif; font-size:12px; color:var(--ds-muted); line-height:1.45; margin-top:2px;
}

.dfx-int .ds-lucky-btn {
  margin-left:auto; flex-shrink:0; padding:9px 16px; border-radius:9px; background:var(--ds-indigo); color:#fff;
  font-family:"Instrument Sans",sans-serif; font-size:13px; font-weight:600;
}

.dfx-int .ds-card {
  background:var(--ds-surface); border:1px solid var(--ds-line); border-radius:12px; padding:20px;
}

/* Opt-in, never blanket: a scrolling card is a clipping context, and any
       card holding an .idp-tw would have its tooltip sliced off at the card
       edge. Only step 2's brief card is tall enough to need this, and its
       action row sits outside the card. Flex items default to
       min-height:auto and refuse to shrink below their content, which is what
       pushed step 2's Continue button below the fold once the page gaps
       started applying. */
.dfx-int .ds-card.is-scroll {
  min-height:0; overflow-y:auto;
}

.dfx-int .ds-label {
  font-family:"Instrument Sans",sans-serif; font-size:12.5px; font-weight:600; color:var(--ds-body);
}

.dfx-int .ds-input {
  display:flex; align-items:center; gap:9px; height:44px; border-radius:10px; background:var(--ds-surface);
  border:1px solid var(--ds-line); padding:0 13px;
  font-family:"Inter",sans-serif; font-size:13.5px; color:var(--ds-ink);
}

.dfx-int .ds-input svg {
  width:15px; height:15px; color:var(--ds-faint); flex-shrink:0;
}

.dfx-int .ds-input.ghost {
  color:var(--ds-faint);
}

/* Types itself in when the step opens, then the caret starts blinking */
.dfx-int .ds-type {
  display:inline; clip-path:inset(0 100% 0 0); animation:dsType 1.5s .35s steps(34,end) forwards;
}

.dfx-int .idp-frame:not(.is-on) .ds-type {
  animation:none; clip-path:inset(0 100% 0 0);
}

@keyframes dsType {
  to { clip-path:inset(0 0 0 0); }
}

.dfx-int .ds-caret {
  width:1.5px; height:16px; background:var(--ds-indigo); display:inline-block;
  vertical-align:text-bottom; opacity:0; animation:idpCaret 1.1s steps(1) 1.85s infinite;
}

.dfx-int .idp-frame:not(.is-on) .ds-caret {
  animation:none; opacity:0;
}

.dfx-int .ds-chips {
  display:flex; flex-wrap:wrap; gap:7px;
}

.dfx-int .ds-chip {
  padding:6px 12px; border-radius:99px; border:1px solid var(--ds-line); background:var(--ds-surface);
  font-family:"Inter",sans-serif; font-size:12px; color:var(--ds-body);
}

.dfx-int .ds-chip.on {
  background:#EEF2FF; border-color:#C7D2FE; color:var(--ds-indigo); font-weight:600;
}

.dfx-int .ds-rowlabel {
  display:flex; align-items:center; gap:10px;
}

.dfx-int .ds-enhance {
  margin-left:auto; display:inline-flex; align-items:center; gap:6px; padding:6px 12px;
  border-radius:8px; border:1px solid var(--ds-line); background:var(--ds-surface);
  font-family:"Instrument Sans",sans-serif; font-size:12px; font-weight:600; color:var(--ds-faint);
}

.dfx-int .ds-enhance svg {
  width:12px; height:12px;
}

.dfx-int .ds-textarea {
  border:1px solid var(--ds-line); border-radius:10px; background:var(--ds-surface); padding:13px;
  font-family:"Inter",sans-serif; font-size:13.5px; line-height:1.6; color:var(--ds-ink); min-height:76px;
}

.dfx-int .ds-textarea.ghost {
  color:var(--ds-faint);
}

.dfx-int .ds-help {
  font-family:"Inter",sans-serif; font-size:11.5px; line-height:1.5; color:var(--ds-muted);
}

.dfx-int .ds-help a,
.dfx-int .ds-help span.lnk {
  color:var(--ds-indigo);
}

.dfx-int .ds-fold {
  display:flex; align-items:center; gap:12px; padding:13px 0; border-top:1px solid var(--ds-line);
}

.dfx-int .ds-fold-ic {
  width:32px; height:32px; border-radius:9px; background:var(--ds-raise); flex-shrink:0;
  display:flex; align-items:center; justify-content:center;
}

.dfx-int .ds-fold-ic svg {
  width:15px; height:15px; color:var(--ds-muted);
}

.dfx-int .ds-fold-t {
  font-family:"Instrument Sans",sans-serif; font-size:13px; font-weight:600; color:var(--ds-ink);
}

.dfx-int .ds-fold-s {
  font-family:"Inter",sans-serif; font-size:11.5px; color:var(--ds-muted); margin-top:1px;
}

.dfx-int .ds-fold-c {
  margin-left:auto; width:15px; height:15px; color:var(--ds-faint);
}

/* ═══ STEP 3 — THE GENERATION PANEL ══════════════════════
       Layout, stage names, descriptions, per-stage glyphs and the 0-100
       ranges are all lifted from DemoProgress.tsx / glyphs.tsx in the app.
       The whole pipeline runs end to end in about seven seconds and then
       loops, so a visitor watches every stage start and finish instead of
       staring at a bar frozen at 51%.
    ═══════════════════════════════════════════════════════════ */
.dfx-int .ds-gen {
  display:flex; flex-direction:column; align-items:center; justify-content:center; gap:10px; flex:1; min-height:0; width:100%;
}

.dfx-int .ds-gen-halo {
  width:52px; height:52px; border-radius:50%; background:var(--ds-indigo-1); position:relative;
  display:flex; align-items:center; justify-content:center; color:var(--ds-indigo); flex-shrink:0;
  transition:background .3s ease, color .3s ease;
}

.dfx-int .ds-gen.is-done .ds-gen-halo {
  background:#D1FAE5; color:#059669;
}

.dfx-int .ds-gen-halo .ds-g {
  width:26px; height:26px;
}

.dfx-int .ds-gen-halo::after {
  content:''; position:absolute; inset:-1px; border-radius:50%; border:1.5px solid currentColor;
  animation:dsHalo 2.6s ease-out infinite; pointer-events:none;
}

@keyframes dsHalo {
  0%   { opacity:.55; transform:scale(.92); }
  70%  { opacity:.08; transform:scale(1.22); }
  100% { opacity:0;   transform:scale(1.3); }
}

.dfx-int .ds-gen-t {
  font-family:"Instrument Sans",sans-serif; font-size:16px; font-weight:700;
  color:var(--ds-ink); line-height:1.3; text-align:center;
}

.dfx-int .ds-gen-s {
  font-family:"Inter",sans-serif; font-size:12px; color:var(--ds-muted);
  text-align:center; max-width:430px; line-height:1.4; margin-top:-5px;
}

.dfx-int .ds-bar {
  width:100%; max-width:470px;
}

.dfx-int .ds-bar-track {
  height:9px; border-radius:99px; background:#E5E7EB; overflow:hidden; box-shadow:inset 0 1px 2px rgba(0,0,0,.07);
}

/* Tailwind's from-indigo-500 via-purple-500 to-pink-500, on the fill itself
       exactly as the app has it. */
.dfx-int .ds-bar-fill {
  height:100%; border-radius:99px; width:0%;
  background:linear-gradient(90deg,#6366F1,#A855F7,#EC4899);
}

.dfx-int .ds-bar-row {
  display:flex; justify-content:space-between; gap:12px; margin-top:6px;
  font-family:"Inter",sans-serif; font-size:11.5px; color:var(--ds-muted);
}

.dfx-int .ds-bar-pct {
  font-weight:600; color:var(--ds-body);
}

/* The list is a window onto all eight stages. It slides to keep the
       running stage in view, which is half of how the movement reads.
       The height is set rather than flexed: .vg-page is a scrolling block,
       so flex:1 here just let the list grow to all eight rows and pushed the
       card past the bottom of the screen. Three rows and a peek of a fourth. */
.dfx-int .ds-timeline {
  width:100%; max-width:470px; height:200px; flex:none; overflow:hidden; position:relative;
  -webkit-mask-image:linear-gradient(180deg,#000 0,#000 84%,transparent 100%);
  mask-image:linear-gradient(180deg,#000 0,#000 84%,transparent 100%);
}

.dfx-int .ds-timeline-i {
  display:flex; flex-direction:column; gap:6px;
  transition:transform .45s cubic-bezier(.4,0,.2,1); will-change:transform;
}

.dfx-int .ds-tl {
  display:flex; align-items:center; gap:10px; padding:8px 11px; flex-shrink:0; height:50px;
  border-radius:11px; border:1.5px solid transparent; background:var(--ds-raise);
  font-family:"Inter",sans-serif; opacity:.5;
  transition:background .25s ease, border-color .25s ease, box-shadow .25s ease, opacity .25s ease;
}

.dfx-int .ds-tl-i {
  width:28px; height:28px; border-radius:50%; flex-shrink:0; background:var(--ds-line);
  display:flex; align-items:center; justify-content:center; color:var(--ds-muted);
  transition:background .25s ease, color .25s ease;
}

.dfx-int .ds-tl-i .ds-g {
  width:17px; height:17px;
}

.dfx-int .ds-tl-x {
  min-width:0;
}

.dfx-int .ds-tl-n {
  font-size:12.5px; font-weight:500; color:var(--ds-ink); display:block; transition:color .25s ease;
}

.dfx-int .ds-tl-d {
  font-size:10.5px; color:var(--ds-muted); display:block; margin-top:1px; line-height:1.35;
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
}

.dfx-int .ds-tl.is-now {
  opacity:1; background:#EEF2FF; border-color:#A5B4FC; box-shadow:0 5px 16px rgba(79,70,229,.17);
}

.dfx-int .ds-tl.is-now .ds-tl-i {
  background:#E0E7FF; color:var(--ds-indigo);
}

.dfx-int .ds-tl.is-now .ds-tl-n {
  color:var(--ds-indigo); font-weight:650;
}

.dfx-int .ds-tl.is-done {
  opacity:1; background:#ECFDF5; border-color:#A7F3D0;
}

.dfx-int .ds-tl.is-done .ds-tl-i {
  background:#D1FAE5; color:#059669;
}

/* Each row carries its own glyph plus a tick; completing swaps them. */
.dfx-int .ds-g-ok {
  display:none;
}

.dfx-int .ds-tl-i .ds-g-ok {
  width:17px; height:17px;
}

.dfx-int .ds-gen-halo .ds-g-ok {
  width:26px; height:26px;
}

.dfx-int .ds-tl.is-done .ds-g {
  display:none;
}

.dfx-int .ds-tl.is-done .ds-g-ok {
  display:block;
}

/* ── Stage glyph motion, ported from StageMotionStyles ──
       The gate that keeps idle rows still lives at the bottom of this block,
       not the top: every rule below uses the `animation` shorthand, which
       resets animation-play-state, and at equal specificity the later rule
       wins. Declared first, the pause was silently undone and all eight rows
       fidgeted at once. */
/* record */
@keyframes dpRecDot {
  0%,100% { opacity:1; } 70% { opacity:.45; }
}

@keyframes dpRecPing {
  0% { transform:scale(.7); opacity:.7; } 75%,100% { transform:scale(2.1); opacity:0; }
}

.dfx-int .dp-rec-dot {
  animation:dpRecDot 1s ease-in-out infinite;
}

.dfx-int .dp-rec-ping {
  transform-box:view-box; transform-origin:18.4px 6.6px; animation:dpRecPing 1s ease-out infinite;
}

/* preprocess — halves close on the strip, hold, then spring open */
@keyframes dpScissorTop {
  0%,52% { transform:rotate(0deg); } 63%,71% { transform:rotate(-28deg); } 84%,100% { transform:rotate(0deg); }
}

@keyframes dpScissorBottom {
  0%,52% { transform:rotate(0deg); } 63%,71% { transform:rotate(28deg);  } 84%,100% { transform:rotate(0deg); }
}

@keyframes dpClipFeed {
  0% { transform:translateX(0); } 55%,78% { transform:translateX(-5px); } 100% { transform:translateX(-10px); }
}

.dfx-int .dp-scissor-top,
.dfx-int .dp-scissor-bottom {
  transform-box:view-box; transform-origin:12px 11.8px;
}

.dfx-int .dp-scissor-top {
  animation:dpScissorTop 3.2s ease-in-out infinite;
}

.dfx-int .dp-scissor-bottom {
  animation:dpScissorBottom 3.2s ease-in-out infinite;
}

.dfx-int .dp-clip-feed {
  transform-box:view-box; animation:dpClipFeed 3.2s linear infinite;
}

/* analyze — frames light in turn under a hopping marker */
@keyframes dpFrame {
  0%,22% { opacity:1; } 32%,96% { opacity:.3; } 100% { opacity:1; }
}

@keyframes dpFrameMarker {
  0%,22% { transform:translateX(0); } 33%,55% { transform:translateX(7.35px); } 66%,88% { transform:translateX(14.7px); } 100% { transform:translateX(0); }
}

.dfx-int .dp-frame {
  animation:dpFrame 2.7s ease-in-out infinite;
}

.dfx-int .dp-frame-2 {
  animation-delay:.9s;
}

.dfx-int .dp-frame-3 {
  animation-delay:1.8s;
}

.dfx-int .dp-frame-marker {
  transform-box:view-box; transform-origin:4.7px 5px; animation:dpFrameMarker 2.7s ease-in-out infinite;
}

/* audio — mismatched durations so the five bars never resync */
@keyframes dpWave {
  0%,100% { transform:scaleY(1); } 50% { transform:scaleY(.34); }
}

.dfx-int .dp-wave-bar {
  transform-box:fill-box; transform-origin:center; animation-name:dpWave; animation-iteration-count:infinite; animation-timing-function:ease-in-out;
}

/* sync — the lower clip slides up into line, then holds */
@keyframes dpSyncMarker {
  0% { transform:translateX(7.5px); } 45%,72% { transform:translateX(0); } 100% { transform:translateX(7.5px); }
}

.dfx-int .dp-sync-marker {
  transform-box:view-box; transform-origin:8.5px 16px; animation:dpSyncMarker 2.8s cubic-bezier(.4,0,.2,1) infinite;
}

/* render — the arm snaps shut, bounces once, swings back open */
@keyframes dpClap {
  0%,48% { transform:rotate(-24deg); } 60% { transform:rotate(0deg); } 66% { transform:rotate(-5deg); } 72% { transform:rotate(0deg); } 88%,100% { transform:rotate(-24deg); }
}

.dfx-int .dp-clap {
  transform-box:view-box; transform-origin:3.6px 10.5px; animation:dpClap 2.6s cubic-bezier(.45,0,.3,1) infinite;
}

/* finalize */
@keyframes dpUploadArrow {
  0% { transform:translateY(3px); opacity:0; } 25%,55% { opacity:1; } 100% { transform:translateY(-3.5px); opacity:0; }
}

.dfx-int .dp-upload-arrow {
  transform-box:view-box; transform-origin:12px 17px; animation:dpUploadArrow 1.9s ease-out infinite;
}

/* complete — the tick draws itself on. Dash lengths are the ring's
       circumference (~63) and the check's own path length (~8.5), rounded up. */
@keyframes dpDraw {
  to { stroke-dashoffset:0; }
}

/* Scoped to the glyphs that are actually on screen. A blanket .dp-draw rule
       left the pending "Demo Ready" row holding an undrawn, invisible tick. */
.dfx-int .ds-g-ok.dp-draw circle,
.dfx-int .ds-tl.is-now .ds-g.dp-draw circle,
.dfx-int .ds-gen-halo .ds-g.dp-draw circle {
  stroke-dasharray:64; stroke-dashoffset:64; animation:dpDraw .5s cubic-bezier(.2,.8,.2,1) forwards;
}

.dfx-int .ds-g-ok.dp-draw path,
.dfx-int .ds-tl.is-now .ds-g.dp-draw path,
.dfx-int .ds-gen-halo .ds-g.dp-draw path {
  stroke-dasharray:12; stroke-dashoffset:12; animation:dpDraw .32s cubic-bezier(.2,.8,.2,1) .26s forwards;
}

/* Only the running stage moves; every other row holds its rest pose.
       This is what stops an eight-icon list reading as a fidget spinner. */
.dfx-int .ds-g * {
  animation-play-state:paused;
}

.dfx-int .ds-gen-halo .ds-g *,
.dfx-int .ds-tl.is-now .ds-g * {
  animation-play-state:running;
}

/* Step 4: the demo detail page */
.dfx-int .ds-crumbline {
  display:flex; align-items:center; gap:12px;
}

.dfx-int .ds-status {
  display:inline-flex; align-items:center; gap:6px; font-family:"Inter",sans-serif; font-size:12.5px; color:#059669; font-weight:500;
}

.dfx-int .ds-status::before {
  content:''; width:7px; height:7px; border-radius:50%; background:#10B981;
}

.dfx-int .ds-demotitle {
  font-family:"Instrument Sans",sans-serif; font-size:17px; font-weight:700; color:var(--ds-ink); letter-spacing:-0.02em;
}

/* Output switcher, straight from DemoDetailsPage.tsx: a bordered card
       holding a centred, width-capped grid of three EQUAL segments on a
       recessed track. The old version was an inline-flex pill hugging its
       own content, which is why it sat off-centre and cramped. */
.dfx-int .ds-tabbar {
  border:1px solid var(--ds-line); border-radius:10px; background:var(--ds-surface);
  padding:12px; box-shadow:0 1px 2px rgba(16,24,40,.05);
}

.dfx-int .ds-tabs {
  display:grid; grid-template-columns:repeat(3,1fr); gap:4px;
  max-width:520px; margin:0 auto; padding:4px; border-radius:8px; background:var(--ds-raise);
}

.dfx-int .ds-tab {
  position:relative; display:flex; align-items:center; justify-content:center; gap:8px;
  min-width:0; padding:9px 12px; border-radius:6px;
  font-family:"Inter",sans-serif; font-size:12.5px; font-weight:500; color:var(--ds-muted); white-space:nowrap;
}

.dfx-int .ds-tab svg {
  width:15px; height:15px; flex-shrink:0;
}

.dfx-int .ds-tab-l {
  min-width:0; overflow:hidden; text-overflow:ellipsis;
}

.dfx-int .ds-tab.on {
  background:var(--ds-indigo); color:#fff; box-shadow:0 1px 2px rgba(16,24,40,.08);
}

/* The app pins this to the segment's top-right corner, not its centre. */
.dfx-int .ds-tab-new {
  position:absolute; top:-8px; right:-6px; line-height:1;
  font-family:"Inter",sans-serif; font-size:8.5px; font-weight:700; letter-spacing:.05em;
  text-transform:uppercase; color:var(--ds-indigo); background:#fff;
  padding:3px 6px; border-radius:99px;
  box-shadow:0 1px 2px rgba(16,24,40,.08); border:1px solid rgba(0,0,0,.05);
}

.dfx-int .ds-panel {
  display:grid; grid-template-columns:1fr 178px; gap:13px; flex:1; min-height:0;
}

/* ── The Video and Document tabs ─────────────────────────────
       The tab bar was decoration: three tabs, one of them permanently on.
       A visitor who wants to know what the other two hold had no way to
       look. They switch now, the same way the sidebar and dark mode do.
       Nothing inside the two new panes is clickable. They are not part of
       the walkthrough, they are there so the tab bar stops lying, so the
       panes take pointer-events:none and the tab bar sits outside them. */
.dfx-int .ds-tabpane {
  display:none; flex:1; min-height:0; flex-direction:column; gap:13px;
}

.dfx-int .ds-tabpane.on {
  display:flex;
}

.dfx-int .ds-tabpane.is-settled .vg-anim,
.dfx-int .ds-tabpane.is-settled .vg-anim-l,
.dfx-int .ds-tabpane.is-settled .vg-anim-pop {
  animation:none !important; opacity:1 !important; transform:none !important;
}

.dfx-int .ds-tabpane[data-pane="video"],
.dfx-int .ds-tabpane[data-pane="document"] {
  pointer-events:none;
}

.dfx-int .ds-tab {
  cursor:pointer;
}

/* While the visitor is off exploring, the way back to the step has to
       stay obvious, because the advance button lives in the demo's own pane. */
.dfx-int .ds-tab.is-waiting {
  box-shadow:0 0 0 2px rgba(79,70,229,.35);
}

/* Video tab */
.dfx-int .ds-vid {
  flex:1; min-height:0; display:flex; flex-direction:column; gap:11px;
}

/* The ambient wash around the frame is the app's signature on this screen:
       colour pulled off the video and bled out behind it. A flat dark panel
       with 18px showing read as a border, not a glow, so it is layered
       radials now and the frame is inset far enough to let them show. */
.dfx-int .ds-vid-stage {
  flex:1; min-height:0; position:relative; border-radius:12px; overflow:hidden;
  background:
  radial-gradient(62% 82% at 10% 26%, rgba(156,32,62,.80), transparent 62%),
  radial-gradient(58% 78% at 90% 64%, rgba(158,46,168,.72), transparent 60%),
  radial-gradient(74% 62% at 48% 104%, rgba(64,44,150,.62), transparent 70%),
  #14162b;
  display:flex; align-items:center; justify-content:center; padding:26px 30px;
  /* The player is the point of this tab, so it gets a floor rather than
  whatever is left after the rows under it. Past that the page scrolls,
  which is where the feedback card sits in the real screen anyway. */
  min-height:236px;
}

.dfx-int .ds-vid-inner {
  width:100%; height:100%; border-radius:7px; overflow:hidden; background:var(--ds-surface);
  box-shadow:0 10px 30px rgba(0,0,0,.28); display:flex; min-height:0;
}

/* The frame under the play button is Blume, the product this whole
       walkthrough demos, not a second invented app. */
.dfx-int .ds-vid-rail {
  width:34px; flex-shrink:0; background:#1E1B2E; padding:10px 0;
  display:flex; flex-direction:column; align-items:center; gap:8px;
}

.dfx-int .ds-vid-rail i {
  width:16px; height:16px; border-radius:5px; background:rgba(255,255,255,.16); display:block;
}

.dfx-int .ds-vid-rail i:first-child {
  background:linear-gradient(135deg,#F472B6,#A855F7);
}

.dfx-int .ds-vid-main {
  flex:1; min-width:0; padding:11px; display:flex; flex-direction:column; gap:9px;
}

.dfx-int .ds-vid-head {
  display:flex; align-items:center; gap:7px;
}

.dfx-int .ds-vid-head b {
  font-family:"Instrument Sans",sans-serif; font-size:11px; font-weight:700; color:var(--ds-ink);
}

.dfx-int .ds-vid-head i {
  display:block; height:6px; width:54px; border-radius:99px; background:var(--ds-line);
}

.dfx-int .ds-vid-canvas {
  flex:1; min-height:0; border-radius:6px; position:relative; overflow:hidden;
  background:repeating-conic-gradient(#E6E6EC 0% 25%, #FAFAFC 0% 50%) 50% / 13px 13px;
}

/* Dark rather than the usual translucent white: the frame underneath is a
       light transparency checkerboard, so a white scrim and a white icon both
       vanished into it. */
.dfx-int .ds-vid-play {
  position:absolute; left:50%; top:50%; transform:translate(-50%,-50%);
  width:62px; height:62px; border-radius:50%; background:rgba(17,17,20,.58);
  backdrop-filter:blur(4px); border:1.5px solid rgba(255,255,255,.55);
  box-shadow:0 8px 26px rgba(0,0,0,.34);
  display:flex; align-items:center; justify-content:center;
}

.dfx-int .ds-vid-play svg {
  width:22px; height:22px; color:#fff; margin-left:3px;
}

/* The feedback prompt and the Sharing/Variations/Settings strip that sit
       under the player. Neither is reachable, they are here so the tab looks
       like the screen it is standing in for rather than a video on its own. */
/* A share row rather than the feedback prompt that was here: on a page
       arguing that the output is something you send, showing where the link
       comes from is worth more than asking how the demo went. */
.dfx-int .ds-share {
  display:flex; align-items:center; gap:8px; flex-shrink:0;
}

.dfx-int .ds-share-link {
  flex:1; min-width:0; display:flex; align-items:center; gap:7px; height:32px;
  padding:0 11px; border-radius:8px; background:var(--ds-wash);
  border:1px solid var(--ds-line);
  font-family:"Inter",sans-serif; font-size:11px; color:var(--ds-ink-2);
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
}

.dfx-int .ds-share-link svg {
  width:12px; height:12px; color:var(--ds-ink-3); flex-shrink:0;
}

.dfx-int .ds-share-btn {
  display:inline-flex; align-items:center; gap:6px; height:32px; padding:0 12px;
  border-radius:8px; border:1px solid var(--ds-line); background:var(--ds-surface);
  font-family:"Instrument Sans",sans-serif; font-size:11.5px; font-weight:600;
  color:var(--ds-ink); flex-shrink:0;
}

.dfx-int .ds-share-btn svg {
  width:12px; height:12px;
}

.dfx-int .ds-share-btn.primary {
  background:var(--ds-indigo); border-color:var(--ds-indigo); color:#fff;
}

.dfx-int .ds-vtabs {
  display:flex; gap:17px; border-bottom:1px solid var(--ds-line); flex-shrink:0;
}

.dfx-int .ds-vtab {
  display:inline-flex; align-items:center; gap:5px; padding:7px 1px 8px;
  font-family:"Instrument Sans",sans-serif; font-size:11px; font-weight:600; color:var(--ds-ink-3);
}

.dfx-int .ds-vtab svg {
  width:12px; height:12px;
}

.dfx-int .ds-vtab.on {
  color:var(--ds-indigo); box-shadow:inset 0 -2px 0 var(--ds-indigo);
}

.dfx-int .ds-vrow {
  display:flex; align-items:center; justify-content:space-between; padding-top:10px; flex-shrink:0;
}

.dfx-int .ds-vrow b {
  font-family:"Instrument Sans",sans-serif; font-size:12px; font-weight:700; color:var(--ds-ink);
}

.dfx-int .ds-vrow span {
  font-family:"Instrument Sans",sans-serif; font-size:11px; font-weight:600; color:var(--ds-indigo);
}

.dfx-int .ds-vid-cap {
  position:absolute; left:50%; bottom:16px; transform:translateX(-50%); max-width:78%;
  background:rgba(17,17,20,.92); color:#fff; border-radius:8px; padding:7px 13px;
  font-family:"Inter",sans-serif; font-size:11px; line-height:1.35; text-align:center; white-space:nowrap;
  overflow:hidden; text-overflow:ellipsis;
}

.dfx-int .ds-vid-acts {
  display:flex; align-items:center; gap:8px; flex-shrink:0;
}

.dfx-int .ds-vid-btn {
  display:inline-flex; align-items:center; gap:6px; height:32px; padding:0 13px; border-radius:8px;
  border:1px solid var(--ds-line); background:var(--ds-surface);
  font-family:"Instrument Sans",sans-serif; font-size:11.5px; font-weight:600; color:var(--ds-ink);
}

.dfx-int .ds-vid-btn svg {
  width:13px; height:13px;
}

/* Text is --ds-surface, not #fff. --ds-ink inverts in dark mode, so a
       hardcoded white label turned this into a white button with white text. */
.dfx-int .ds-vid-btn.primary {
  background:var(--ds-ink); border-color:var(--ds-ink); color:var(--ds-surface);
}

.dfx-int .ds-vid-btn.edit {
  margin-left:auto; background:var(--ds-indigo); border-color:var(--ds-indigo); color:#fff;
}

/* Document tab */
.dfx-int .ds-doc {
  flex:1; min-height:0; display:flex; flex-direction:column; gap:11px;
  border:1px solid var(--ds-line); border-radius:11px; background:var(--ds-surface); padding:13px;
}

.dfx-int .ds-doc-head {
  display:flex; align-items:center; gap:9px; flex-shrink:0;
}

.dfx-int .ds-doc-head b {
  font-family:"Instrument Sans",sans-serif; font-size:13.5px; font-weight:700; color:var(--ds-ink);
}

.dfx-int .ds-doc-v {
  font-family:"Inter",sans-serif; font-size:9px; font-weight:600; color:var(--ds-ink-2);
  border:1px solid var(--ds-line); border-radius:5px; padding:1px 6px;
}

.dfx-int .ds-doc-ready {
  margin-left:auto; font-family:"Inter",sans-serif; font-size:10px; color:var(--ds-ink-3);
}

.dfx-int .ds-doc-body {
  flex:1; min-height:0; display:grid; grid-template-columns:168px 1fr; gap:13px;
}

.dfx-int .ds-doc-fmts {
  display:flex; flex-direction:column; gap:7px; min-height:0;
}

.dfx-int .ds-doc-fmts > p {
  font-family:"Inter",sans-serif; font-size:9.5px; line-height:1.45; color:var(--ds-ink-3); margin-bottom:1px;
}

.dfx-int .ds-fmt {
  border:1px solid var(--ds-line); border-radius:8px; padding:8px 9px; display:flex; gap:8px; align-items:flex-start;
}

.dfx-int .ds-fmt.on {
  border-color:rgba(79,70,229,.45); background:rgba(79,70,229,.05);
}

.dfx-int .ds-fmt svg {
  width:13px; height:13px; color:var(--ds-ink-2); flex-shrink:0; margin-top:1px;
}

.dfx-int .ds-fmt b {
  display:block; font-family:"Instrument Sans",sans-serif; font-size:11px; font-weight:700; color:var(--ds-ink);
}

.dfx-int .ds-fmt i {
  display:block; font-style:normal; font-family:"Inter",sans-serif; font-size:8.5px; line-height:1.4; color:var(--ds-ink-3);
}

.dfx-int .ds-fmt-rec {
  font-family:"Inter",sans-serif; font-size:7px; font-weight:700; letter-spacing:.06em;
  text-transform:uppercase; color:var(--ds-indigo); margin-left:5px;
}

.dfx-int .ds-doc-right {
  border:1px solid var(--ds-line); border-radius:9px; background:var(--ds-wash);
  display:flex; flex-direction:column; align-items:center; justify-content:center; gap:9px; padding:14px; min-height:0;
}

.dfx-int .ds-prev {
  width:78%; max-width:230px; border-radius:8px; background:var(--ds-surface);
  border:1px solid var(--ds-line); padding:11px; display:flex; flex-direction:column; gap:7px;
  box-shadow:0 5px 16px rgba(16,24,40,.07); position:relative; overflow:hidden;
}

.dfx-int .ds-prev::before {
  content:''; position:absolute; left:0; right:0; top:0; height:2px;
  background:linear-gradient(90deg,#4F46E5,#22C55E);
}

.dfx-int .ds-prev i {
  display:block; height:6px; border-radius:99px; background:var(--ds-line);
}

.dfx-int .ds-prev i.w1 {
  width:62%;
}

.dfx-int .ds-prev i.w2 {
  width:88%;
}

.dfx-int .ds-prev i.w3 {
  width:74%;
}

.dfx-int .ds-prev-chips {
  display:flex; gap:5px; margin-top:2px;
}

.dfx-int .ds-prev-chips span {
  font-family:"Inter",sans-serif; font-size:7.5px; font-weight:600; color:var(--ds-ink-2);
  border:1px solid var(--ds-line); border-radius:4px; padding:2px 5px;
}

.dfx-int .ds-doc-gen {
  font-family:"Instrument Sans",sans-serif; font-size:12.5px; font-weight:700; color:var(--ds-ink);
}

.dfx-int .ds-doc-right > p {
  font-family:"Inter",sans-serif; font-size:9.5px; line-height:1.45;
  color:var(--ds-ink-3); text-align:center; max-width:230px;
}

.dfx-int .ds-doc-btn {
  display:inline-flex; align-items:center; gap:6px; height:31px; padding:0 15px; border-radius:8px;
  background:var(--ds-indigo); color:#fff;
  font-family:"Instrument Sans",sans-serif; font-size:11.5px; font-weight:600;
}

.dfx-int .ds-doc-btn svg {
  width:12px; height:12px;
}

/* ── Step 4: the Interactive Demo tab with nothing made yet ──
       InteractiveDemoPanel.tsx's `not_created` state. The app puts a live
       preview of the player beside the pitch and one button, so the visitor
       sees the thing before they ask for it — and again, made, on step 5. */
.dfx-int .ds-idnew {
  flex:1; min-height:0; display:grid; gap:20px; align-items:center;
  grid-template-columns:minmax(0,320px) minmax(0,1fr);
  border:1px solid var(--ds-line); border-radius:12px; padding:18px;
  background:linear-gradient(180deg,var(--ds-raise),var(--ds-surface));
}

.dfx-int .ds-idprev {
  min-width:0; height:100%; display:flex;
}

.dfx-int .ds-idpitch {
  min-width:0;
}

.dfx-int .ds-idhead {
  display:flex; align-items:flex-start; gap:11px; margin-bottom:14px;
}

.dfx-int .ds-idhead-ic {
  width:34px; height:34px; border-radius:9px; flex-shrink:0;
  background:var(--ds-indigo-1); color:var(--ds-indigo);
  display:flex; align-items:center; justify-content:center;
}

.dfx-int .ds-idhead-ic svg {
  width:17px; height:17px;
}

.dfx-int .ds-idhead-t {
  display:flex; align-items:center; gap:8px; flex-wrap:wrap;
  font-family:"Instrument Sans",sans-serif; font-size:13.5px; font-weight:700; color:var(--ds-ink);
}

.dfx-int .ds-idhead-s {
  font-family:"Inter",sans-serif; font-size:11.5px; color:var(--ds-muted); margin-top:3px; line-height:1.45;
}

.dfx-int .ds-idnew-h {
  font-family:"Instrument Sans",sans-serif; font-size:16px; font-weight:700; color:var(--ds-ink); letter-spacing:-0.02em;
}

.dfx-int .ds-idnew-p {
  font-family:"Inter",sans-serif; font-size:12px; line-height:1.55; color:var(--ds-muted); margin-top:6px;
}

.dfx-int .ds-idlist {
  display:flex; flex-direction:column; gap:8px; margin-top:13px;
}

.dfx-int .ds-idlist .l {
  display:flex; align-items:center; gap:9px; font-family:"Inter",sans-serif; font-size:12px; color:var(--ds-body);
}

.dfx-int .ds-idlist i {
  width:21px; height:21px; border-radius:6px; flex-shrink:0;
  background:var(--ds-indigo-1); color:var(--ds-indigo);
  display:flex; align-items:center; justify-content:center;
}

.dfx-int .ds-idlist i svg {
  width:12px; height:12px;
}

.dfx-int .ds-idcta {
  display:flex; align-items:center; gap:12px; flex-wrap:wrap; margin-top:17px;
}

.dfx-int .idp-hit.ds-idbtn {
  height:38px; padding:0 16px; border-radius:9px; gap:8px; border:none;
  background:var(--ds-indigo); color:#fff;
  font-family:"Instrument Sans",sans-serif; font-size:12.5px; font-weight:600;
}

.dfx-int .idp-hit.ds-idbtn svg {
  width:14px; height:14px;
}

.dfx-int .idp-hit.ds-idbtn:hover {
  background:#4338CA;
}

.dfx-int .ds-idnote {
  font-family:"Inter",sans-serif; font-size:11px; color:var(--ds-faint);
}

@media (max-width:1120px) {
  .dfx-int .ds-idnew {
    grid-template-columns:1fr;
  }
  .dfx-int .ds-idprev {
    display:none;
  }}

.dfx-int .ds-pill-row {
  display:flex; align-items:center; gap:8px;
}

.dfx-int .ds-pill {
  padding:3px 9px; border-radius:99px; font-family:"Instrument Sans",sans-serif;
  font-size:10.5px; font-weight:600;
  background:var(--ds-raise); color:var(--ds-muted);   /* the app's neutral default */
}

.dfx-int .ds-pill.pub {
  background:#D1FAE5; color:#047857;
}

.dfx-int .ds-embed {
  border:1px solid var(--ds-line); border-radius:11px; overflow:hidden; background:var(--ds-surface); flex:1; min-height:0; display:flex; flex-direction:column;
}

.dfx-int .ds-embed-bar {
  display:flex; align-items:center; gap:9px; padding:8px 11px; border-bottom:1px solid var(--ds-line);
}

.dfx-int .ds-embed-mark {
  width:19px; height:19px; border-radius:6px; background:var(--ds-indigo); overflow:hidden; flex-shrink:0;
}

.dfx-int .ds-embed-mark img {
  width:100%; height:100%; object-fit:contain; transform:scale(1.5);
}

/* The player inside an interactive demo carries the CUSTOMER's brand, not
       ours — this one is Blume's, the fictional product being demoed. Seeing
       the Demosmith mark here implied we stamp our logo on your demo. */
.dfx-int .ds-embed-mark.bl-mark {
  background:linear-gradient(135deg,#F472B6,#A855F7);
  display:flex; align-items:center; justify-content:center; color:#fff;
}

.dfx-int .ds-embed-mark.bl-mark svg {
  width:68%; height:68%;
}

/* The title sits in a flex child with no min-width, so a long one wrapped to
       a second line and grew the bar from 30px to 64px. Inside a fixed-height
       embed that pushed the slide underneath it into the bar. Browser chrome
       truncates; so does this. */
.dfx-int .ds-embed-bar > span {
  min-width:0;
}

.dfx-int .ds-embed-t {
  font-family:"Instrument Sans",sans-serif; font-size:11px; font-weight:600; color:var(--ds-ink); display:block;
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
}

.dfx-int .ds-embed-u {
  font-family:"Inter",sans-serif; font-size:9.5px; color:var(--ds-faint); display:block;
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
}

.dfx-int .ds-embed-prog {
  margin-left:auto; display:flex; align-items:center; gap:7px;
}

.dfx-int .ds-embed-prog span {
  font-family:"Inter",sans-serif; font-size:10px; color:var(--ds-muted);
}

.dfx-int .ds-embed-prog i {
  width:70px; height:3px; border-radius:99px; background:#E5E7EB; display:block; position:relative;
}

.dfx-int .ds-embed-prog i::after {
  content:''; position:absolute; inset:0 auto 0 0; width:22%; border-radius:99px; background:var(--ds-indigo);
}

.dfx-int .ds-embed-body {
  flex:1; min-height:0; position:relative; padding:14px;
  background:linear-gradient(135deg,#FBE8EC 0%,#EAE4FB 48%,#DDE6FA 100%);
  display:flex; align-items:center; justify-content:center;
}

.dfx-int .ds-embed-slide {
  background:var(--ds-surface); border-radius:10px; width:100%; height:100%; display:flex; align-items:center; gap:14px; padding:16px 18px; box-shadow:0 8px 26px rgba(0,0,0,.08);
}

.dfx-int .ds-slide-l {
  flex:1; min-width:0; display:flex; flex-direction:column; gap:8px;
}

.dfx-int .ds-slide-brand {
  display:flex; align-items:center; gap:8px;
}

.dfx-int .ds-slide-brand .ds-embed-mark {
  width:22px; height:22px;
}

.dfx-int .ds-slide-brand span {
  font-family:"Instrument Sans",sans-serif; font-size:12px; font-weight:700; color:var(--ds-ink);
}

.dfx-int .ds-slide-h {
  font-family:"Instrument Sans",sans-serif; font-size:17px; font-weight:700; color:var(--ds-ink); line-height:1.16; letter-spacing:-0.02em;
}

.dfx-int .ds-slide-cta {
  align-self:flex-start; margin-top:2px; padding:7px 15px; border-radius:8px; background:#2563EB; color:#fff; font-family:"Instrument Sans",sans-serif; font-size:11.5px; font-weight:600;
}

.dfx-int .ds-slide-r {
  position:relative; width:44%; flex-shrink:0; border-radius:7px; overflow:hidden; box-shadow:0 5px 16px rgba(0,0,0,.14); background:#F3F4F6; aspect-ratio:16/11;
}

/* Blume's own screen inside the demo player. These five classes were used
       and defined nowhere, so every element computed to 0px and .ds-slide-r
       rendered as a flat grey rectangle on steps 4, 5 and the outro. The
       checkerboard is the point: it reads as a photo with its background
       taken out, which is the flow the demo walks through. */
.dfx-int .bl {
  position:absolute; inset:0; display:flex; background:var(--ds-surface);
}

.dfx-int .bl-rail {
  width:26px; flex-shrink:0; background:#1E1B2E; padding:7px 0;
  display:flex; flex-direction:column; align-items:center; gap:6px;
}

.dfx-int .bl-tool {
  width:12px; height:12px; border-radius:4px; background:rgba(255,255,255,.16); display:block; flex-shrink:0;
}

.dfx-int .bl-tool.on {
  background:linear-gradient(135deg,#F472B6,#A855F7);
}

.dfx-int .bl-canvas {
  flex:1; min-width:0; padding:7px; display:flex;
}

.dfx-int .bl-photo {
  flex:1; border-radius:4px; position:relative; overflow:hidden;
  background:repeating-conic-gradient(#E6E6EC 0% 25%, #FAFAFC 0% 50%) 50% / 9px 9px;
}

/* The subject on the canvas. This was a rounded blob with a circle on top,
       which read as a person and not a good one. A background remover is shown
       off on a product, so it is a plant in a pot now: a silhouette that still
       reads at the ~90px this renders at inside the slide. Drawn as a background
       image rather than markup because the same span appears in two frames, so
       the art belongs in one place. */
.dfx-int .bl-cutout {
  position:absolute; left:50%; bottom:5%; transform:translateX(-50%);
  width:46%; height:88%; display:block;
  background:url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20120%20160'%3E%20%3Cdefs%3E%20%3ClinearGradient%20id='a'%20gradientUnits='userSpaceOnUse'%20x1='24'%20y1='12'%20x2='96'%20y2='112'%3E%20%3Cstop%20offset='0'%20stop-color='%23C9A0FF'/%3E%3Cstop%20offset='1'%20stop-color='%235B4BE8'/%3E%20%3C/linearGradient%3E%20%3ClinearGradient%20id='b'%20gradientUnits='userSpaceOnUse'%20x1='30'%20y1='98'%20x2='90'%20y2='158'%3E%20%3Cstop%20offset='0'%20stop-color='%237E6DF2'/%3E%3Cstop%20offset='1'%20stop-color='%233B32BE'/%3E%20%3C/linearGradient%3E%20%3C/defs%3E%20%3Cpath%20d='M60%20112V44'%20stroke='url%28%23a%29'%20stroke-width='5'%20stroke-linecap='round'%20fill='none'/%3E%20%3Cellipse%20cx='40'%20cy='76'%20rx='21'%20ry='9.5'%20fill='url%28%23a%29'%20transform='rotate%2830%2040%2076%29'/%3E%20%3Cellipse%20cx='80'%20cy='68'%20rx='21'%20ry='9.5'%20fill='url%28%23a%29'%20transform='rotate%28-30%2080%2068%29'/%3E%20%3Cellipse%20cx='60'%20cy='34'%20rx='10'%20ry='22'%20fill='url%28%23a%29'/%3E%20%3Crect%20x='26'%20y='100'%20width='68'%20height='13'%20rx='4'%20fill='url%28%23b%29'/%3E%20%3Cpath%20d='M32%20115h56l-7%2038a5%205%200%200%201-5%204H44a5%205%200%200%201-5-4Z'%20fill='url%28%23b%29'/%3E%20%3C/svg%3E") center bottom / contain no-repeat;
}

.dfx-int .ds-actions {
  display:flex; flex-direction:column; gap:7px;
}

.dfx-int .ds-act {
  display:flex; align-items:center; justify-content:center; gap:8px; height:36px; border-radius:9px;
  border:1px solid var(--ds-line); background:var(--ds-surface);
  font-family:"Instrument Sans",sans-serif; font-size:12.5px; font-weight:600; color:var(--ds-ink);
}

.dfx-int .ds-act svg {
  width:13px; height:13px;
}

/* Explicit colours rather than --ds-ink: that token flips to near-white
       in dark mode, which left this button white text on a white pill. */
.dfx-int .ds-act.dark {
  background:#111827; border-color:#111827; color:#fff;
}

.dfx-int .idp-screen.is-dark .ds-act.dark {
  background:#F9FAFB; border-color:#F9FAFB; color:#111827;
}

.dfx-int .ds-act.danger {
  color:#DC2626;
}

.dfx-int .idp-screen.is-dark .ds-act.danger {
  color:#F87171;
}

/* The one clickable action in this scene. Wears .ds-act's look so it sits
       flush in the column while keeping .idp-hit's hover and focus states.
       These were inline styles with a hardcoded white background, which is
       the other half of why this column vanished in dark mode. */
.dfx-int .idp-hit.ds-act-hit {
  width:100%; height:36px; border-radius:9px; gap:8px; justify-content:center;
  background:var(--ds-surface); color:var(--ds-ink); border:1px solid var(--ds-line);
  font-family:"Instrument Sans",sans-serif; font-size:12.5px; font-weight:600;
}

.dfx-int .idp-hit.ds-act-hit svg {
  width:13px; height:13px;
}

.dfx-int .idp-hit.ds-act-hit:hover {
  background:var(--ds-indigo); border-color:var(--ds-indigo); color:#fff;
}

.dfx-int .idp-hit.ds-act-hit.is-primary {
  background:#111827; border-color:#111827; color:#fff;
}

.dfx-int .idp-screen.is-dark .idp-hit.ds-act-hit.is-primary {
  background:#F9FAFB; border-color:#F9FAFB; color:#111827;
}

.dfx-int .idp-hit.ds-act-hit.is-primary:hover {
  background:var(--ds-indigo); border-color:var(--ds-indigo); color:#fff;
}

/* Step 1's URL field. Same story: it was inline styles with a hardcoded
       white background, so dark mode gave near-white text on white. */
.dfx-int .idp-hit.ds-urlfield {
  width:100%; height:44px; padding:0 13px; border-radius:10px; gap:9px;
  justify-content:flex-start;
  background:var(--ds-surface); color:var(--ds-ink); border:1px solid var(--ds-line);
  font-family:"Inter",sans-serif; font-weight:400; font-size:13.5px;
}

.dfx-int .idp-hit.ds-urlfield svg {
  width:15px; height:15px; color:var(--ds-faint);
}

.dfx-int .idp-hit.ds-urlfield:hover {
  background:var(--ds-surface); color:var(--ds-ink); border-color:var(--ds-indigo);
}

.dfx-int .ds-stats {
  display:grid; grid-template-columns:repeat(3,1fr); gap:9px;
}

.dfx-int .ds-stat {
  border:1px solid var(--ds-line); border-radius:10px; padding:10px 12px; background:var(--ds-surface);
}

.dfx-int .ds-stat-l {
  display:flex; align-items:center; gap:6px; font-family:"Inter",sans-serif; font-size:10.5px; color:var(--ds-muted);
}

.dfx-int .ds-stat-l svg {
  width:11px; height:11px;
}

.dfx-int .ds-stat-v {
  font-family:"Instrument Sans",sans-serif; font-size:18px; font-weight:700; color:var(--ds-ink); letter-spacing:-0.02em; margin-top:5px; line-height:1;
}

.dfx-int .ds-stat-v small {
  font-size:10.5px; font-weight:400; color:var(--ds-faint); margin-left:5px; letter-spacing:0;
}

/* The app shell the screens sit in. Surfaces are token-driven so the
       app's own dark-mode toggle actually changes them. */
.dfx-int .vg {
  position:absolute; inset:0; display:flex; overflow:hidden;
  background:var(--ds-surface); color:var(--ds-ink);
  font-family:"Inter",sans-serif;
}

.dfx-int .vg,
.dfx-int .vg * {
  font-variant-numeric:tabular-nums;
}

.dfx-int .vg-side {
  flex-shrink:0; display:flex; flex-direction:column; overflow:hidden;
}

.dfx-int .vg-main {
  flex:1; min-width:0; display:flex; flex-direction:column; background:var(--ds-wash);
}

.dfx-int .vg-top {
  display:flex; align-items:center; flex-shrink:0; background:var(--ds-surface);
}

/* ═══ MOTION ═════════════════════════════════════════════
       Restored after a CSS cleanup pass removed this block by mistake,
       which let every frame render at once. Only the active frame is
       ever visible; the rest are hidden AND removed from the a11y tree.
    ═══════════════════════════════════════════════════════════ */
.dfx-int .idp-frame {
  position:absolute; inset:0; opacity:0; visibility:hidden;
  transform:translateX(26px) scale(.985);
  transition:opacity .38s ease, transform .5s cubic-bezier(.22,.9,.28,1), visibility .38s;
}

.dfx-int .idp-frame.is-on {
  opacity:1; visibility:visible; transform:none;
}

.dfx-int .idp-frame.leaving {
  opacity:0; transform:translateX(-22px) scale(.985);
}

/* Staggered entrance for anything inside the active screen */
.dfx-int .vg-anim {
  animation:vgIn .5s cubic-bezier(.2,.9,.3,1) both; animation-delay:var(--d,0s);
}

.dfx-int .idp-frame:not(.is-on) .vg-anim {
  animation:none; opacity:0;
}

@keyframes vgIn {
  from { opacity:0; transform:translateY(9px); } to { opacity:1; transform:none; }
}

.dfx-int .vg-anim-l {
  animation:vgInL .5s cubic-bezier(.2,.9,.3,1) both; animation-delay:var(--d,0s);
}

.dfx-int .idp-frame:not(.is-on) .vg-anim-l {
  animation:none; opacity:0;
}

@keyframes vgInL {
  from { opacity:0; transform:translateX(-12px); } to { opacity:1; transform:none; }
}

.dfx-int .vg-anim-pop {
  animation:vgInPop .55s cubic-bezier(.2,1.25,.4,1) both; animation-delay:var(--d,0s);
}

.dfx-int .idp-frame:not(.is-on) .vg-anim-pop {
  animation:none; opacity:0;
}

@keyframes vgInPop {
  from { opacity:0; transform:scale(.88); } to { opacity:1; transform:none; }
}

/* A transform creates a stacking context, so an animated container would
       trap its own tooltip underneath later siblings. Anything holding a
       target is lifted above the rest of the screen. */
.dfx-int .vg-lift {
  position:relative; z-index:20;
}

/* The click ripple. There is no fake cursor; the visitor has their own. */
.dfx-int .idp-ripple {
  position:absolute; z-index:8; width:42px; height:42px; margin:-21px 0 0 -21px;
  border-radius:50%; pointer-events:none; opacity:0;
  background:radial-gradient(circle, rgba(64,67,255,.42) 0%, rgba(64,67,255,0) 70%);
}

.dfx-int .idp-ripple.go {
  animation:idpRip .62s ease-out forwards;
}

@keyframes idpRip {
  0%   { opacity:.9; transform:scale(.25); }
  100% { opacity:0;  transform:scale(1.9); }
}

/* ═══ THE TARGET ══════════════════════════════════════════
       The ring lives on the button itself, so it can never drift
       out of alignment the way a JS-positioned overlay does.
    ═══════════════════════════════════════════════════════════ */
.dfx-int .idp-tw {
  position:relative; display:inline-flex;
}

.dfx-int .idp-hit {
  position:relative; z-index:2; display:inline-flex; align-items:center; gap:7px;
  padding:9px 16px; border-radius:9px; background:var(--idp-ink); color:#fff;
  font-family:"Instrument Sans",sans-serif; font-size:13px; font-weight:600;
  cursor:pointer; white-space:nowrap; transition:transform .15s ease, background .15s ease;
}

.dfx-int .idp-hit svg {
  width:13px; height:13px;
}

.dfx-int .idp-hit:hover {
  transform:translateY(-1px); background:var(--idp-blue);
}

.dfx-int .idp-hit:active {
  transform:translateY(0) scale(.97);
}

.dfx-int .idp-hit:focus-visible {
  outline:3px solid var(--idp-blue); outline-offset:4px;
}

.dfx-int .idp-hit.ghost {
  background:#fff; color:var(--idp-ink-2); border:1px solid var(--idp-line);
}

.dfx-int .idp-hit.ghost:hover {
  background:#fff; color:var(--idp-blue); border-color:var(--idp-blue);
}

/* The highlight draws itself around the target when the step opens.
       pathLength normalises the perimeter so one animation fits any size. */
.dfx-int .idp-draw {
  position:absolute; inset:-6px; z-index:1; pointer-events:none; overflow:visible;
}

.dfx-int .idp-draw rect {
  fill:none; stroke:var(--idp-blue); stroke-width:2; stroke-linecap:round;
  stroke-dasharray:100; stroke-dashoffset:100;
  animation:idpDraw .78s .18s cubic-bezier(.4,0,.2,1) forwards;
}

.dfx-int .idp-draw rect.glow {
  stroke-width:6; stroke-opacity:.18; filter:blur(3px);
  animation-delay:.24s;
}

@keyframes idpDraw {
  to { stroke-dashoffset:0; }
}

/* Once drawn, it breathes so it keeps drawing the eye */
.dfx-int .idp-tw::before,
.dfx-int .vg-tr.is-target::before {
  content:''; position:absolute; inset:-6px; border-radius:15px; z-index:0;
  pointer-events:none; opacity:0;
  animation:idpHalo 2.4s 1s ease-in-out infinite;
}

.dfx-int .vg-tr.is-target::before {
  inset:-3px 3px; border-radius:9px;
}

@keyframes idpHalo {
  0%,100% { opacity:1; box-shadow:0 0 0 3px rgba(64,67,255,.15), 0 0 16px rgba(64,67,255,.26); }
  50%     { opacity:1; box-shadow:0 0 0 10px rgba(64,67,255,.03), 0 0 26px rgba(64,67,255,.08); }
}

@keyframes idpRing {
  0%,100% { box-shadow:0 0 0 3px rgba(64,67,255,.18), 0 0 14px rgba(64,67,255,.28); }
  50%     { box-shadow:0 0 0 10px rgba(64,67,255,.04), 0 0 22px rgba(64,67,255,.10); }
}

.dfx-int .idp-tw:hover::before {
  animation:none; box-shadow:0 0 0 7px rgba(64,67,255,.2);
}

/* Tooltip, anchored to the target so it never needs JS geometry */
.dfx-int .idp-tt {
  position:absolute; z-index:4; width:244px; text-align:left;
  background:linear-gradient(168deg,#23242c,#131419); color:#fff;
  border-radius:12px; padding:12px 14px;
  box-shadow:0 2px 6px rgba(16,16,28,.2), 0 18px 40px rgba(16,16,28,.32),
  inset 0 1px 0 rgba(255,255,255,.07);
  pointer-events:none;
  animation:idpTtIn .45s .1s cubic-bezier(.2,.9,.3,1) both;
  top:calc(100% + 15px); left:0;
}

.dfx-int .idp-tt.right {
  left:auto; right:0;
}

.dfx-int .idp-tt.up {
  top:auto; bottom:calc(100% + 15px);
}

.dfx-int .idp-tt::after {
  content:''; position:absolute; width:11px; height:11px; background:#23242c;
  transform:rotate(45deg); border-radius:2px; top:-4px; left:24px;
}

.dfx-int .idp-tt.right::after {
  left:auto; right:24px;
}

.dfx-int .idp-tt.up::after {
  top:auto; bottom:-4px;
}

@keyframes idpTtIn {
  from { opacity:0; transform:translateY(7px) scale(.96); } to { opacity:1; transform:none; }
}

.dfx-int .idp-tt-n {
  font-family:"Instrument Sans",sans-serif; font-size:9.5px; font-weight:700;
  letter-spacing:.11em; text-transform:uppercase; color:#9a9cff;
  display:block; margin-bottom:6px;
}

.dfx-int .idp-tt-t {
  font-family:"Inter",sans-serif; font-size:12.5px; line-height:1.5; color:#fff;
  display:block; white-space:normal;
}

/* Intro + outro */
/* The real app sits behind the title card, softened, so the first
       thing a visitor sees is that there is actual software waiting. */
.dfx-int .idp-backdrop {
  position:absolute; inset:0; overflow:hidden; pointer-events:none;
  filter:blur(1.6px) saturate(.72); transform:scale(1.02);
}

.dfx-int .idp-splash {
  position:absolute; inset:0; display:flex; flex-direction:column;
  align-items:center; justify-content:center; gap:15px; text-align:center;
  padding:28px;
  /* Dark where the words are, clearer at the edges, so the product
  still reads without costing any contrast on the copy. */
  background:
  radial-gradient(ellipse 58% 64% at 50% 48%, rgba(9,9,15,.95) 0%, rgba(9,9,15,.80) 58%, rgba(9,9,15,.60) 100%),
  linear-gradient(158deg, rgba(12,12,20,.52), rgba(22,22,34,.62));
}

.dfx-int .idp-splash::before {
  content:''; position:absolute; inset:0;
  background:
  radial-gradient(ellipse 70% 60% at 50% 0%, rgba(64,67,255,.34) 0%, transparent 64%),
  radial-gradient(ellipse 50% 50% at 80% 100%, rgba(123,77,255,.20) 0%, transparent 62%);
}

.dfx-int .idp-splash > * {
  position:relative;
}

.dfx-int .idp-splash-kicker {
  font-family:"Instrument Sans",sans-serif; font-size:10.5px; font-weight:700;
  letter-spacing:.14em; text-transform:uppercase; color:rgba(255,255,255,.42);
}

.dfx-int .idp-splash-title {
  font-family:"Instrument Sans",sans-serif; font-weight:500; color:#fff;
  font-size:clamp(19px,2.5vw,28px); letter-spacing:-0.03em; line-height:1.2; max-width:450px;
}

.dfx-int .idp-splash-sub {
  font-family:"Inter",sans-serif; font-size:13.5px; line-height:1.55;
  color:rgba(255,255,255,.62); max-width:380px;
}

.dfx-int .idp-splash-btn {
  display:inline-flex; align-items:center; gap:8px; padding:11px 22px; border-radius:11px;
  background:#fff; color:var(--idp-ink);
  font-family:"Instrument Sans",sans-serif; font-size:13.5px; font-weight:600;
  transition:transform .2s ease, box-shadow .2s ease; box-shadow:0 6px 20px rgba(0,0,0,.3);
}

.dfx-int .idp-splash-btn:hover {
  transform:translateY(-2px); box-shadow:0 10px 26px rgba(0,0,0,.4);
}

.dfx-int .idp-splash-btn svg {
  width:14px; height:14px;
}

.dfx-int .idp-splash-btn.accent {
  background:var(--idp-blue); color:#fff;
}

.dfx-int .idp-splash-foot {
  font-family:"Inter",sans-serif; font-size:11.5px; color:rgba(255,255,255,.4);
}

/* The opening cover is a title and one button, nothing else. With no
       paragraph to keep legible it can carry far less scrim than the outro,
       so the app behind it still reads as a real screen. */
.dfx-int .idp-splash.is-cover {
  gap:22px;
  background:
  radial-gradient(ellipse 54% 58% at 50% 50%, rgba(9,9,15,.86) 0%, rgba(9,9,15,.60) 60%, rgba(9,9,15,.40) 100%),
  linear-gradient(158deg, rgba(12,12,20,.32), rgba(22,22,34,.44));
}

.dfx-int .idp-splash.is-cover::before {
  opacity:.7;
}

.dfx-int .idp-splash.is-cover .idp-splash-title {
  font-size:clamp(20px,2.7vw,30px); font-weight:600; max-width:none;
}

.dfx-int .idp-pb-cta {
  /* Carries the margin that used to sit on the status pill beside it. */
  margin-left:auto;
  display:inline-flex; align-items:center; padding:5px 12px; border-radius:99px;
  background:var(--idp-ink); color:#fff;
  font-family:"Instrument Sans",sans-serif; font-size:11.5px; font-weight:600;
  white-space:nowrap; transition:background .2s ease, transform .2s ease;
}

.dfx-int .idp-pb-cta:hover {
  background:var(--idp-blue); transform:translateY(-1px);
}

.dfx-int .idp-stage-note {
  display:flex; align-items:center; justify-content:center; gap:8px; flex-wrap:wrap;
  margin-top:20px; text-align:center;
  font-family:"Inter",sans-serif; font-size:14px; line-height:1.5; color:var(--idp-ink-3);
}

.dfx-int .idp-stage-note svg {
  width:15px; height:15px; color:var(--idp-blue); flex-shrink:0;
}

.dfx-int .idp-stage-note span {
  font-family:"SF Mono",ui-monospace,Menlo,monospace; font-size:12.5px;
  padding:2px 7px; border-radius:6px; background:#fff;
  border:1px solid var(--idp-line); color:var(--idp-ink-2);
}

/* Full screen: the player takes the whole viewport and the app mock
       grows with it, so the demo is genuinely usable at full size. */
.dfx-int .idp-player:fullscreen {
  border-radius:0; border:none; display:flex; flex-direction:column;
  width:100vw; height:100vh; background:#fff;
}

.dfx-int .idp-player:fullscreen .idp-screen {
  flex:1; aspect-ratio:auto; min-height:0;
}

.dfx-int .idp-player:fullscreen .idp-caption {
  display:none;
}

.dfx-int .idp-player:fullscreen .idp-tt {
  width:280px;
}

.dfx-int .idp-player:fullscreen .vg-side {
  width:240px;
}

.dfx-int .idp-player:fullscreen .vg-page {
  padding:24px 32px; gap:18px;
}

/* On a phone the app mock has no room for a floating tooltip, so the
       step text moves to a caption bar under the screen instead. */
.dfx-int .idp-caption {
  display:none;
}

.dfx-int .idp-sr {
  position:absolute; width:1px; height:1px; overflow:hidden;
  clip:rect(0 0 0 0); clip-path:inset(50%); white-space:nowrap;
}

@keyframes idpBreathe {
  0%,100%{ transform:scale(1); } 50%{ transform:scale(1.1); }
}

@keyframes idpScrub {
  0%{ width:0; } 92%,100%{ width:100%; }
}

@keyframes idpAutoRow {
  0%,7%    { opacity:.42; transform:translateY(2px); }
  15%,78%  { opacity:1;   transform:translateY(0); }
  90%,100% { opacity:.42; transform:translateY(2px); }
}

@keyframes idpAutoIc {
  0%,7%    { background:var(--idp-line-soft); color:var(--idp-ink-3); }
  15%,78%  { background:var(--idp-blue);      color:#fff; }
  90%,100% { background:var(--idp-line-soft); color:var(--idp-ink-3); }
}

@keyframes idpBriefGo {
  0%,70%,100% { transform:translateY(0);   box-shadow:0 0 0 0 rgba(64,67,255,.35); }
  80%         { transform:translateY(-2px); box-shadow:0 0 0 7px rgba(64,67,255,0); }
}

@keyframes idpBarGrow {
  0%,100%{ transform:scaleY(.25); } 30%,75%{ transform:scaleY(1); }
}

@keyframes idpAnatCursor {
  0%       { transform:translate(-118px,88px); opacity:0; }
  14%      { transform:translate(-118px,88px); opacity:1; }
  46%,74%  { transform:translate(-7px,-2px);   opacity:1; }
  90%,100% { transform:translate(-7px,-2px);   opacity:0; }
}

@keyframes idpAnatRipple {
  0%,46%  { opacity:0; transform:scale(.3); }
  54%     { opacity:.8; transform:scale(.6); }
  70%,100%{ opacity:0; transform:scale(1.8); }
}

@keyframes idpScan {
  0%{ top:-120px; } 60%,100%{ top:100%; }
}

@keyframes idpNudge {
  0%,100%{ transform:translateX(0); } 50%{ transform:translateX(4px); }
}

@media (max-width:760px) {
/* Player on a phone. The app screens are laid out for a desktop
           workspace, so each one keeps only what its own step is about
           and the step text moves to the caption bar under the frame. */
  .dfx-int .vg-side {
    display:none;
  }
  .dfx-int .vg-top {
    padding:7px 12px;
  }
  .dfx-int .ds-topright {
    gap:11px;
  }
  .dfx-int .ds-feedback {
    display:none;
  }
  .dfx-int .vg-page {
    padding:12px 13px; gap:9px;
  }
/* Create Demo screens: the chrome above the form is decorative here */
  .dfx-int .ds-pagehead,
  .dfx-int .ds-wizard,
  .dfx-int .ds-lucky {
    display:none;
  }
  .dfx-int .ds-h2 {
    font-size:19px;
  }
  .dfx-int .ds-lede {
    font-size:11.5px; margin-top:5px;
  }
  .dfx-int .ds-card {
    padding:13px;
  }
  .dfx-int .ds-input,
  .dfx-int .idp-hit {
    font-size:12px;
  }
  .dfx-int .ds-chips {
    gap:5px;
  }
  .dfx-int .ds-chip {
    font-size:10.5px; padding:5px 9px;
  }
  .dfx-int .ds-chips .ds-chip:nth-child(n+4) {
    display:none;
  }
  .dfx-int .ds-textarea {
    font-size:12px; min-height:58px; padding:10px;
  }
  .dfx-int .ds-help,
  .dfx-int .ds-fold {
    display:none;
  }
  .dfx-int .ds-label {
    font-size:11.5px;
  }
/* Generating: the stage list still runs all eight, it just scrolls
           through a shorter window with the descriptions dropped. */
  .dfx-int .ds-gen {
    gap:8px;
  }
  .dfx-int .ds-gen-halo {
    width:42px; height:42px;
  }
  .dfx-int .ds-gen-halo .ds-g,
  .dfx-int .ds-gen-halo .ds-g-ok {
    width:20px; height:20px;
  }
  .dfx-int .ds-gen-t {
    font-size:14px;
  }
  .dfx-int .ds-gen-s {
    font-size:10.5px; margin-top:-4px;
  }
  .dfx-int .ds-bar-row {
    font-size:10.5px;
  }
  .dfx-int .ds-timeline {
    height:122px;
  }
  .dfx-int .ds-timeline-i {
    gap:5px;
  }
  .dfx-int .ds-tl {
    padding:6px 9px; gap:8px; height:39px;
  }
  .dfx-int .ds-tl-i {
    width:24px; height:24px;
  }
  .dfx-int .ds-tl-i .ds-g,
  .dfx-int .ds-tl-i .ds-g-ok {
    width:15px; height:15px;
  }
  .dfx-int .ds-tl-n {
    font-size:11.5px;
  }
  .dfx-int .ds-tl-d {
    display:none;
  }
/* Demo page: stack the panel, keep the embed and the one action */
  .dfx-int .ds-demotitle {
    font-size:14px;
  }
  .dfx-int .ds-status {
    font-size:11px;
  }
  .dfx-int .ds-tabbar {
    padding:7px; border-radius:9px;
  }
  .dfx-int .ds-tabs {
    padding:3px; gap:3px; max-width:none;
  }
/* At this width the icons cost more than they say: with them in,
           "Interactive Demo" truncates to nonsense. Labels win. */
  .dfx-int .ds-tab {
    padding:7px 5px; font-size:9.5px; gap:0;
  }
  .dfx-int .ds-tab svg {
    display:none;
  }
/* The document tab's two columns want 349px inside a 308px pane here,
           so the preview goes and the format list, which is the part that
           actually says what the tab holds, gets the width. */
  .dfx-int .ds-doc-body {
    grid-template-columns:1fr;
  }
  .dfx-int .ds-doc-right {
    display:none;
  }
  .dfx-int .ds-doc {
    padding:10px;
  }
  .dfx-int .ds-fmt i {
    display:none;
  }
/* Not everything fits; Play, Edit and the share link carry the meaning.
           Marked with a class rather than nth-child, which silently pointed at
           the wrong buttons the moment one was removed. */
  .dfx-int .ds-vid-btn.is-opt,
  .dfx-int .ds-share-btn.is-opt {
    display:none;
  }
  .dfx-int .ds-vid-stage {
    padding:10px;
  }
  .dfx-int .ds-vid-play {
    width:40px; height:40px;
  }
  .dfx-int .ds-vid-play svg {
    width:15px; height:15px;
  }
  .dfx-int .ds-vid-cap {
    font-size:9px; bottom:10px; padding:5px 10px;
  }
  .dfx-int .ds-tab-new {
    font-size:7.5px; padding:2px 5px; top:-7px; right:-4px;
  }
  .dfx-int .ds-panel {
    grid-template-columns:1fr; gap:9px;
  }
/* No room for the preview and the pitch side by side; the pitch and
           its button are the point of the step, so the preview goes. */
  .dfx-int .ds-idnew {
    grid-template-columns:1fr; padding:13px; gap:0; align-items:start;
  }
  .dfx-int .ds-idprev {
    display:none;
  }
  .dfx-int .ds-idnew-h {
    font-size:13.5px;
  }
/* The heading and the three bullets already say it; the paragraph is
           what pushed the button below the fold at this height. */
  .dfx-int .ds-idnew-p {
    display:none;
  }
  .dfx-int .ds-idlist {
    gap:6px; margin-top:10px;
  }
  .dfx-int .ds-idlist .l {
    font-size:11px;
  }
  .dfx-int .ds-idhead {
    margin-bottom:11px;
  }
  .dfx-int .ds-idhead-s {
    display:none;
  }
  .dfx-int .ds-idcta {
    margin-top:13px; gap:8px;
  }
  .dfx-int .ds-idnote {
    display:none;
  }
  .dfx-int .ds-actions {
    flex-direction:row;
  }
  .dfx-int .ds-actions > .ds-act {
    display:none;
  }
/* Everything here is flex:1 with min-height:0, so when the page ran out
           of room it shrank the embed to 75px instead of scrolling. Its bar
           alone needs 30px and its slide needs the rest, so it gets a floor and
           .vg-page scrolls past it, which is what that scroller is for. */
  .dfx-int .ds-embed {
    min-height:170px;
  }
/* Once the embed has a floor, something has to give, and it has to be
           the page height rather than the card. .ds-panel was handing its card
           a 138px grid row for 217px of content, and .ds-card overflows
           visibly, so the slide came out of the bottom and sat under the
           Preview button. Sizing the chain to its content instead lets
           .vg-page scroll, which is what that scroller is for. */
  .dfx-int .ds-tabpane,
  .dfx-int .ds-panel {
    flex:0 0 auto;
  }
  .dfx-int .ds-panel .ds-card {
    min-height:auto;
  }
/* The progress meter costs ~100px of a 292px bar, which is the room the
           title needs more. */
  .dfx-int .ds-embed-prog {
    display:none;
  }
  .dfx-int .ds-embed-slide {
    padding:12px; gap:10px;
  }
  .dfx-int .ds-slide-h {
    font-size:13px;
  }
  .dfx-int .ds-slide-cta {
    font-size:10.5px; padding:6px 12px;
  }
  .dfx-int .ds-stats {
    grid-template-columns:1fr 1fr; gap:7px;
  }
  .dfx-int .ds-stat:nth-child(3) {
    display:none;
  }
  .dfx-int .ds-stat-v {
    font-size:15px;
  }
  .dfx-int .vg-feed-row {
    font-size:11px;
  }
  .dfx-int .vg-won-t {
    font-size:16px;
  }
  .dfx-int .vg-won-s {
    font-size:11px;
  }
  .dfx-int .vg-won-check {
    width:42px; height:42px;
  }
  .dfx-int .vg-btn {
    height:26px; padding:0 10px; font-size:11px;
  }
  .dfx-int .idp-hit {
    padding:7px 12px; font-size:11.5px;
  }
  .dfx-int .idp-tt {
    display:none;
  }
  .dfx-int .idp-caption {
    display:block; padding:13px 16px 14px; background:var(--idp-ink);
    font-family:"Inter",sans-serif; font-size:13px; line-height:1.5; color:#fff;
  }
  .dfx-int .idp-caption:empty {
    display:none;
  }
  .dfx-int .idp-stage-note {
    font-size:13px; margin-top:16px;
  }
/* Player chrome has to give up its non-essential bits */
  .dfx-int .idp-pb-cta {
    display:none;
  }
  .dfx-int .idp-pb-url {
    max-width:none; font-size:10px;
  }
  .dfx-int .idp-player-foot {
    gap:8px; padding:10px 12px;
  }
  .dfx-int .idp-foot-label {
    display:none;
  }
  .dfx-int .idp-foot-chip {
    font-size:10.5px; padding:5px 8px;
  }
  .dfx-int .idp-chip-l {
    display:none;
  }
  .dfx-int #idpSound .idp-chip-l {
    display:inline;
  }
  .dfx-int .idp-dots button {
    width:20px;
  }
  .dfx-int .idp-dots button.on {
    width:30px;
  }
  .dfx-int .idp-splash-title {
    font-size:20px;
  }
  .dfx-int .idp-splash-sub {
    font-size:12.5px;
  }
  .dfx-int .idp-splash {
    gap:10px; padding:20px;
  }
  .dfx-int .idp-splash-kicker {
    font-size:9.5px;
  }
  .dfx-int .idp-splash-btn {
    padding:10px 18px; font-size:12.5px;
  }}

@media (prefers-reduced-motion:reduce) {
  .dfx-int .idp-hero-title,
  .dfx-int .idp-hero-sub,
  .dfx-int .idp-hero-ctas,
  .dfx-int .idp-hero-note,
  .dfx-int .idp-player-stage {
    animation:none !important;
  }
  .dfx-int .idp-auto-row,
  .dfx-int .idp-auto-ic,
  .dfx-int .idp-try-hot.is-now::after,
  .dfx-int .idp-brief-go,
  .dfx-int .idp-in-caret,
  .dfx-int .idp-brief-caret,
  .dfx-int .idp-log-row.now b::after,
  .dfx-int .idp-share-bars i,
  .dfx-int .idp-launch i,
  .dfx-int .idp-eq i,
  .dfx-int .idp-ledger-col.in::after,
  .dfx-int .idp-vid-fill,
  .dfx-int .idp-linkchip,
  .dfx-int .idp-orbit-sat,
  .dfx-int .idp-mini-slot b,
  .dfx-int .idp-vid-play,
  .dfx-int .idp-hero-title em::after,
  .dfx-int .idp-anat-cursor,
  .dfx-int .idp-anat-ripple,
  .dfx-int .idp-anat-target::before,
  .dfx-int .ds-gen-halo::after,
  .dfx-int .badge-pulse-ring {
    animation:none !important;
  }
/* The ported stage glyphs. StageMotionStyles disables every one of
           these under reduced motion in the app; the port had not. */
  .dfx-int .dp-clock-hand,
  .dfx-int .dp-rec-dot,
  .dfx-int .dp-rec-ping,
  .dfx-int .dp-scissor-top,
  .dfx-int .dp-scissor-bottom,
  .dfx-int .dp-clip-feed,
  .dfx-int .dp-frame,
  .dfx-int .dp-frame-marker,
  .dfx-int .dp-wave-bar,
  .dfx-int .dp-sync-marker,
  .dfx-int .dp-clap,
  .dfx-int .dp-upload-arrow,
  .dfx-int .dp-draw circle,
  .dfx-int .dp-draw path {
    animation:none !important;
  }
/* The player: keep it usable, drop the movement */
  .dfx-int .vg-anim,
  .dfx-int .vg-anim-l,
  .dfx-int .vg-anim-pop,
  .dfx-int .vg-flash,
  .dfx-int .idp-frame.is-on .vg-confetti i,
  .dfx-int .vg-toast,
  .dfx-int .idp-tt,
  .dfx-int .vg-won-check,
  .dfx-int .idp-tw::before,
  .dfx-int .vg-tr.is-target::before,
  .dfx-int .vg-log-row.now b::after,
  .dfx-int .idp-ripple.go,
  .dfx-int .idp-splash-btn.nudge,
  .dfx-int .idp-tw.seek::before,
  .dfx-int .vg-tr.is-target.seek::before {
    animation:none !important;
  }
  .dfx-int .vg-anim,
  .dfx-int .vg-anim-l,
  .dfx-int .vg-anim-pop {
    opacity:1 !important; transform:none !important;
  }
  .dfx-int .idp-frame {
    transition:opacity .15s ease, visibility .15s !important; transform:none !important;
  }
  .dfx-int .idp-frame.leaving {
    transform:none !important;
  }
  .dfx-int .vg-tr.is-target::before {
    box-shadow:0 0 0 3px rgba(64,67,255,.22) !important;
  }
  .dfx-int .idp-tw::before {
    box-shadow:0 0 0 3px rgba(64,67,255,.22) !important;
  }}/* ── typing, taken back from the port ──────────────────────
   These rules have to sit AFTER the ported block. The source's own
   `.ds-type` carries a clip-path reveal with fill-mode forwards and
   no gate, so at equal specificity it won the cascade and the
   address typed itself on page load behind the Video tab, finishing
   before anyone switched to this panel.

   The reveal is dropped entirely, for both fields. It animates a
   span that always occupies the full width of the finished string,
   which leaves the caret sitting at the end of text nobody has
   typed yet, and on a wrapped line Chrome clips every line to the
   first one. The text is typed in JS instead; all this has to do is
   stay out of the way. */
.dfx-int .ds-type {
  animation: none;
  clip-path: none;
  /* the typed text grows a character at a time, so the box must not
     re-wrap mid-word and jump the caret to the line below */
  word-break: break-word;
}

/* The address field is a flex row with gap:9px, and the caret is a
   flex sibling of the text, so it sat nine pixels clear of the last
   character at every point in the animation and read as a stray mark
   travelling ahead of the words. Pulled back to where a text cursor
   actually sits. The brief is inline, not flex, so it needs nothing. */
.dfx-int .ds-urlfield .ds-caret { margin-left: -7px; }

/* Solid while the characters are arriving, blinking once they stop —
   the way a real cursor behaves in a field being typed into. */
.dfx-int .ds-caret { opacity: 0; }
.dfx-int .is-typing .ds-caret { opacity: 1; animation: none; }
.dfx-int .is-typed .ds-caret { opacity: 1; animation: idpCaret 1.1s steps(1) infinite; }

@keyframes idpCaret { 0%, 100% { opacity: 1; } 50% { opacity: 0; } }

/* ── re-branding the ported frames ─────────────────────────
   The source player demos a photo editor, so its finished-asset
   panes are built around a transparency checkerboard and a cut-out
   plant. The subject here is Demosmith, so the canvas becomes a
   walkthrough frame and the product preview inside the interactive
   demo reuses the same Create Demo figure the written guide places
   in its own pages. These few overrides sit after the port so the
   port itself stays a clean copy of its source. */

/* --ds-ink-2 and --ds-ink-3 are declared on .dfx-int, so unlike the
   app's other tokens they do not get flipped by the dark block on
   .vg. Flip them here or the Video and Document panes keep light-mode
   greys on a dark surface. */
.dfx-int .idp-screen.is-dark .vg {
  --ds-ink-2: #D1D5DB;
  --ds-ink-3: #9CA3AF;
}

/* ── the finished-demo embed on steps 4 and 5 ──────────────
   The embed is flex:1 inside a page that, in this panel, is shorter
   than the hero the source player lives in. Squeezed to 160px, its
   slide got 82px while the two halves inside wanted 111px and 126px:
   they overflowed their parent and printed on top of each other.

   The source hit the same thing on phones and fixed it with a floor
   on the embed plus letting the page scroll instead of the card
   shrinking. It just never needed that on desktop. Here it does, so
   the same treatment applies at every width.

   Belt and braces on top: the preview takes its size from the height
   available and derives its width, rather than taking 44% of the
   width and demanding whatever height 16:11 implies. That way it can
   never be the thing that overflows again. */
.dfx-int .ds-embed { min-height: 192px; }

/* The floor above costs height, and step 5 has a stats row under the
   embed that was falling below the fold because of it. Paid for by
   tightening this step's own spacing rather than by growing the stage,
   which the video and the guide would have paid for too. */
.dfx-int .vg-page { padding: 16px 20px; gap: 12px; }
.dfx-int .ds-tabbar { padding: 6px 10px; }
.dfx-int .ds-tab { padding: 7px 14px; }
.dfx-int .ds-embed-slide { padding: 12px 14px; }
.dfx-int .ds-slide-l { gap: 5px; }
.dfx-int .ds-stats { gap: 8px; }

/* The last 30px that kept step 5's stats below the fold. Taken from
   the card's own padding and the stat tiles rather than from the
   embed or the slide, both of which are now sized exactly to fit
   their contents and have nothing left to give. */
.dfx-int .ds-panel { gap: 10px; }
.dfx-int .ds-panel .ds-card { padding: 10px; }
.dfx-int .ds-stat { padding: 7px 10px; }
.dfx-int .ds-stat-v { font-size: 15px; margin-top: 3px; }

.dfx-int .ds-tabpane,
.dfx-int .ds-panel { flex: 0 0 auto; }

.dfx-int .ds-panel .ds-card { min-height: auto; }

/* Width drives, height derives. The other way round (height:100% with
   width:auto) looks equivalent but is not: max-width then clamps the
   width while the 100% height stands, and the ratio silently breaks —
   on a phone the thumbnail came out 1.10 instead of 1.45. With height
   auto, max-height clamping makes the browser recompute the width from
   the ratio, so the box keeps its shape at every size. */
.dfx-int .ds-slide-r {
  width: 46%;
  height: auto;
  max-height: 100%;
  aspect-ratio: 16 / 11;
}

.dfx-int .ds-slide-l { min-height: 0; overflow: hidden; }

/* The mini Create Demo figure is drawn by us, so none of the port's
   dark rules reach it: in dark mode it sat as a bright white card
   inside a dark preview. It follows the app's theme the way the mock
   it replaced did. Only the copy inside the player is touched — the
   same figure in the written guide is on a page that has no dark
   mode and must stay light. */
.dfx-int .idp-screen.is-dark .dfx-fig {
  --fg-line: #374151;
  --fg-ink: #F9FAFB;
  --fg-muted: #6B7280;
  background: #1F2937;
}

.dfx-int .idp-screen.is-dark .dfx-fig-bar { background: linear-gradient(180deg, #273244, #1F2937); }

.dfx-int .idp-screen.is-dark .dfx-fig-url,
.dfx-int .idp-screen.is-dark .dfx-fig-side,
.dfx-int .idp-screen.is-dark .dfx-fig-head,
.dfx-int .idp-screen.is-dark .dfx-fig-card,
.dfx-int .idp-screen.is-dark .dfx-fig-tile { background: #1F2937; }

.dfx-int .idp-screen.is-dark .dfx-fig-page { background: #111827; }
.dfx-int .idp-screen.is-dark .dfx-fig-side u { background: #374151; }
.dfx-int .idp-screen.is-dark .dfx-fig-side u.on { background: #312E81; }
.dfx-int .idp-screen.is-dark .dfx-fig-tile i { background: #312E81; }
.dfx-int .idp-screen.is-dark .dfx-fig-chips span { color: #9CA3AF; }
.dfx-int .idp-screen.is-dark .dfx-fig-chips span.on { background: #312E81; border-color: #4338CA; color: #C7D2FE; }
.dfx-int .idp-screen.is-dark .dfx-fig-lab { color: #D1D5DB; }

/* The walkthrough's own dark mode must not leave the canvas in a
   light gradient behind the finished video. */
.dfx-int .idp-screen.is-dark .ds-vid-canvas {
  background: linear-gradient(150deg, #1F2937 0%, #111827 100%);
}

.dfx-int .idp-screen.is-dark .ds-vid-shot { background: #1F2937; }
.dfx-int .idp-screen.is-dark .ds-vid-shot span { background: #374151; border-bottom-color: #374151; }

.dfx-int .ds-vid-canvas {
  background: linear-gradient(150deg, #EFEAFB 0%, #E5ECF7 52%, #F4ECE0 100%);
}

.dfx-int .ds-vid-shot {
  position: absolute;
  inset: 14%;
  border-radius: 5px;
  background: #fff;
  box-shadow: 0 1px 2px rgba(16, 16, 28, .1), 0 8px 18px -8px rgba(16, 16, 28, .3);
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.dfx-int .ds-vid-shot span {
  display: block;
  height: 4px;
  background: #EDEDF2;
  border-bottom: 1px solid #E5E7EB;
}

.dfx-int .ds-vid-shot i {
  flex: 1;
  background:
    linear-gradient(90deg, #E5E7EB 22%, transparent 22%) 6px 6px / 100% 3px no-repeat,
    linear-gradient(90deg, #E5E7EB 46%, transparent 46%) 6px 12px / 100% 3px no-repeat,
    linear-gradient(90deg, #EEF2FF 34%, transparent 34%) 6px 20px / 100% 7px no-repeat;
}

/* the preview that lives inside the interactive-demo card */
/* Scoped under .dfx-int so it actually wins: the base .dfx-fig rule
   lives further down the file with the guide, and at equal specificity
   it was overriding this one. The figure rendered at the article's
   10px base inside a 150px box, so every label wrapped and truncated
   and it read as a broken card rather than a thumbnail.

   Sized in container units rather than a fixed px, because this box
   is a percentage of a slide inside an embed inside a grid, and it is
   a different size at every breakpoint. 3.4cqi puts the body text at
   about 5px in a 150px box, which is the illegible texture a real
   thumbnail has. */
.dfx-int .ds-slide-r { container-type: inline-size; }

.dfx-int .dfx-fig--mini {
  font-size: 3.4cqi;
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: none;
  border-radius: 0;
}

.dfx-int .dfx-fig--mini .dfx-fig-in { min-height: 0; height: calc(100% - 2.4em); }
.dfx-int .dfx-fig--mini .dfx-fig-chips { display: none; }

/* nothing inside a thumbnail should wrap */
.dfx-int .dfx-fig--mini .dfx-fig-lab,
.dfx-int .dfx-fig--mini .dfx-fig-field,
.dfx-int .dfx-fig--mini .dfx-fig-url { white-space: nowrap; overflow: hidden; text-overflow: clip; }

/* The head's text block is a flex child, so it defaults to
   min-width:auto and refuses to shrink below its own words. At 320
   that pushed "Create Demo" and its subtitle out past the frame. */
.dfx-fig-head > div { min-width: 0; }
.dfx-fig-t,
.dfx-fig-s { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.dfx-fig-page { min-width: 0; overflow: hidden; }

/* ═══ PANEL 3 — GUIDE ══════════════════════════════════════
   The written walkthrough, and the place the four output formats
   are actually shown rather than listed. The format chips sit in
   the window's title bar next to the filename, which is where
   docusmith.html already puts its format pill, so a visitor who
   has seen that page reads this without being taught.

   Each format gets its own treatment because that is the whole
   point: Markdown shows source, HTML shows the rendered article,
   PDF shows paginated sheets, plain text shows neither styling
   nor pagination. Four views of one document, not one view with
   four labels. */

.dfx-doc {
  display: flex;
  flex-direction: column;
  width: 100%;
  height: 100%;
  border-radius: 20px;
  overflow: hidden;
  background: #fff;
  border: 1px solid var(--dfx-hair);
  box-shadow:
    0 2.29px 2.29px rgba(28, 28, 28, .03),
    0 10px 10px rgba(28, 28, 28, .1),
    0 -6px 6px -5px #fff;
}

.dfx-doc-bar {
  flex: none;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 0 12px;
  height: 40px;
  background: #F4F4F5;
  border-bottom: 1px solid var(--dfx-hair-2);
}

.dfx-fname {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  flex: none;
  font-family: var(--dfx-mono);
  font-size: 11.5px;
  color: var(--dfx-ink-2);
  white-space: nowrap;
}

.dfx-fname svg { width: 12px; height: 12px; opacity: .5; }

/* the format chips. Smaller, lighter and inside the chrome, so
   they read as part of the document window rather than as a
   second level of page navigation competing with .dfx-tabs. */
.dfx-fmts {
  margin-left: auto;
  display: flex;
  gap: 2px;
  padding: 3px;
  border-radius: 100px;
  background: rgba(28, 28, 28, .055);
}

.dfx-fmt {
  padding: 3px 10px;
  border: none;
  border-radius: 100px;
  background: transparent;
  font-family: var(--dfx-mono);
  font-size: 10.5px;
  letter-spacing: .04em;
  color: var(--dfx-ink-3);
  cursor: pointer;
  transition: background .18s ease, color .18s ease;
}

.dfx-fmt:hover { color: var(--dfx-ink); }

.dfx-fmt[aria-selected='true'] {
  background: #fff;
  color: var(--dfx-ink);
  box-shadow: 0 1px 2px rgba(28, 28, 28, .09);
}

/* the scrolling body. Fades at the bottom edge so the document
   reads as continuing past the frame instead of being cut off,
   and so the page itself never has to grow to show more of it. */
.dfx-doc-body {
  position: relative;
  flex: 1;
  min-height: 0;
}

.dfx-doc-body::after {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 44px;
  pointer-events: none;
  background: linear-gradient(to bottom, rgba(255, 255, 255, 0), #fff);
}

.dfx-view {
  display: none;
  height: 100%;
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
}

.dfx-view.is-on { display: block; }

.dfx-view::-webkit-scrollbar { width: 8px; }
.dfx-view::-webkit-scrollbar-thumb {
  background: rgba(28, 28, 28, .14);
  border-radius: 100px;
  border: 2px solid transparent;
  background-clip: content-box;
}

/* ── markdown source ── */
.dfx-md {
  margin: 0;
  padding: 18px 22px 52px;
  font-family: var(--dfx-mono);
  font-size: 12px;
  line-height: 1.85;
  color: var(--dfx-ink-2);
  white-space: pre-wrap;
  word-break: break-word;
}

.dfx-md .h { color: var(--dfx-ink); font-weight: 600; }
.dfx-md .mk { color: rgba(91, 94, 240, .78); }
.dfx-md .q  { color: rgba(28, 28, 28, .42); }

/* ── rendered html ── */
.dfx-html {
  padding: 22px 26px 54px;
  max-width: 660px;
  font-family: var(--dfx-sans);
  color: var(--dfx-ink-2);
}

.dfx-html h1 {
  font-family: var(--font-serif), serif;
  font-size: 27px;
  font-weight: 400;
  letter-spacing: -.02em;
  line-height: 1.15;
  color: var(--dfx-ink);
  margin: 0 0 6px;
}

.dfx-html .meta {
  font-family: var(--dfx-mono);
  font-size: 10.5px;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--dfx-ink-3);
  margin: 0 0 18px;
}

.dfx-html h2 {
  font-size: 14.5px;
  font-weight: 600;
  letter-spacing: -.01em;
  color: var(--dfx-ink);
  margin: 22px 0 7px;
}

.dfx-html p {
  font-size: 13.5px;
  line-height: 1.62;
  margin: 0 0 11px;
}

.dfx-html strong { color: var(--dfx-ink); font-weight: 600; }

.dfx-html code {
  font-family: var(--dfx-mono);
  font-size: 11.5px;
  padding: 1px 5px;
  border-radius: 5px;
  background: rgba(28, 28, 28, .05);
  color: var(--dfx-ink);
}

.dfx-html blockquote {
  margin: 0 0 12px;
  padding: 10px 14px;
  border-left: 2px solid var(--dfx-accent);
  border-radius: 0 8px 8px 0;
  background: rgba(91, 94, 240, .055);
  font-size: 13px;
  line-height: 1.55;
}

.dfx-html blockquote p { margin: 0; }

.dfx-html table {
  width: 100%;
  border-collapse: collapse;
  margin: 4px 0 12px;
  font-size: 12.5px;
}

.dfx-html th,
.dfx-html td {
  text-align: left;
  padding: 7px 10px;
  border-bottom: 1px solid var(--dfx-hair-2);
}

.dfx-html th {
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--dfx-ink-3);
}

.dfx-html td:first-child { color: var(--dfx-ink); font-weight: 500; }

/* ── the figures the run placed in the document ────────────
   A real Demosmith run puts screenshots of the screens it walked
   into the written guide, so the guide here has to carry them too:
   a document whose figures are empty grey boxes is not a document.

   Drawn rather than photographed, like every other product mock on
   this site. Everything inside is sized in em off .dfx-fig's own
   font-size, so one drawing serves the HTML article at one scale
   and a PDF sheet at another without a second copy of the markup. */
.dfx-fig {
  --fg-line: #E5E7EB;
  --fg-ink: #111827;
  --fg-muted: #9CA3AF;
  --fg-indigo: #4F46E5;

  font-size: 10px;
  font-family: 'Inter', sans-serif;
  border-radius: 1em;
  overflow: hidden;
  background: #fff;
  border: 1px solid var(--fg-line);
}

.dfx-fig-bar {
  display: flex;
  align-items: center;
  gap: .5em;
  padding: .7em .9em;
  background: linear-gradient(180deg, #fcfcfd, #f4f4f6);
  border-bottom: 1px solid var(--fg-line);
}

.dfx-fig-bar i { width: .65em; height: .65em; border-radius: 50%; display: block; }
.dfx-fig-bar i:nth-child(1) { background: #ff5f57; }
.dfx-fig-bar i:nth-child(2) { background: #febc2e; }
.dfx-fig-bar i:nth-child(3) { background: #28c840; }

.dfx-fig-url {
  margin-left: .6em;
  padding: .25em .7em;
  border-radius: .5em;
  background: #fff;
  border: 1px solid var(--fg-line);
  font-size: .85em;
  color: var(--fg-muted);
}

.dfx-fig-in { display: flex; min-height: 10em; }

.dfx-fig-side {
  width: 6.4em;
  flex: none;
  padding: .8em .6em;
  border-right: 1px solid var(--fg-line);
  background: #fff;
}

.dfx-fig-mark {
  width: 1.7em;
  height: 1.7em;
  border-radius: .5em;
  background: var(--fg-indigo);
  margin-bottom: .8em;
}

.dfx-fig-side u {
  display: block;
  height: .55em;
  margin-bottom: .55em;
  border-radius: .3em;
  background: #EFEFF2;
  text-decoration: none;
}

.dfx-fig-side u.on { background: #E0E7FF; }
.dfx-fig-side u.s { width: 62%; }

.dfx-fig-page { flex: 1; min-width: 0; padding: .9em 1em; background: #F9FAFB; }

.dfx-fig-head {
  display: flex;
  align-items: center;
  gap: .6em;
  padding: .6em .7em;
  margin-bottom: .8em;
  border-radius: .7em;
  background: #fff;
  border: 1px solid var(--fg-line);
}

.dfx-fig-head i { width: 1.7em; height: 1.7em; border-radius: .5em; background: var(--fg-indigo); flex: none; }
.dfx-fig-t { font-size: .95em; font-weight: 700; color: var(--fg-ink); letter-spacing: -.01em; }
.dfx-fig-s { font-size: .8em; color: var(--fg-muted); margin-top: .1em; }

.dfx-fig-card {
  padding: .8em;
  border-radius: .7em;
  background: #fff;
  border: 1px solid var(--fg-line);
}

.dfx-fig-lab { font-size: .8em; font-weight: 600; color: #374151; display: block; margin-bottom: .45em; }

/* the field the step tells you to fill, wearing the focus ring it
   would have at the moment the screenshot was taken */
.dfx-fig-field {
  padding: .55em .7em;
  border-radius: .5em;
  border: 1px solid var(--fg-indigo);
  box-shadow: 0 0 0 .25em rgba(79, 70, 229, .13);
  font-size: .9em;
  color: var(--fg-ink);
}

.dfx-fig-chips { display: flex; gap: .4em; margin-top: .7em; flex-wrap: wrap; }

.dfx-fig-chips span {
  padding: .3em .7em;
  border-radius: 99px;
  border: 1px solid var(--fg-line);
  font-size: .78em;
  color: #6B7280;
}

.dfx-fig-chips span.on { background: #EEF2FF; border-color: #C7D2FE; color: var(--fg-indigo); }

.dfx-fig-tiles { display: grid; grid-template-columns: repeat(3, 1fr); gap: .5em; }

.dfx-fig-tile {
  padding: .6em;
  border-radius: .6em;
  background: #fff;
  border: 1px solid var(--fg-line);
}

.dfx-fig-tile i { display: block; height: 2.2em; border-radius: .4em; background: #EEF2FF; margin-bottom: .5em; }
.dfx-fig-tile b { display: block; font-size: .82em; font-weight: 600; color: var(--fg-ink); }
.dfx-fig-tile s { display: block; font-size: .72em; color: var(--fg-muted); text-decoration: none; margin-top: .1em; }

/* the figure plus its caption, as the document places it */
.dfx-shot { margin: 4px 0 14px; }

.dfx-shot-cap {
  margin-top: 7px;
  font-size: 11px;
  color: var(--dfx-ink-3);
}

/* ── pdf sheets ── */
.dfx-pdf {
  padding: 18px 0 52px;
  background: #EDEDEF;
}

.dfx-sheet {
  width: min(430px, 88%);
  margin: 0 auto 16px;
  padding: 30px 34px;
  background: #fff;
  border-radius: 2px;
  box-shadow: 0 1px 2px rgba(28, 28, 28, .1), 0 8px 22px -10px rgba(28, 28, 28, .28);
  font-family: var(--dfx-sans);
  color: var(--dfx-ink-2);
}

.dfx-sheet-hd,
.dfx-sheet-ft {
  display: flex;
  justify-content: space-between;
  font-family: var(--dfx-mono);
  font-size: 8px;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: rgba(28, 28, 28, .34);
}

.dfx-sheet-hd {
  padding-bottom: 9px;
  margin-bottom: 16px;
  border-bottom: 1px solid var(--dfx-hair-2);
}

.dfx-sheet-ft {
  padding-top: 9px;
  margin-top: 18px;
  border-top: 1px solid var(--dfx-hair-2);
}

.dfx-sheet h1 {
  font-family: var(--font-serif), serif;
  font-size: 19px;
  font-weight: 400;
  line-height: 1.2;
  color: var(--dfx-ink);
  margin: 0 0 12px;
}

.dfx-sheet h2 {
  font-size: 11.5px;
  font-weight: 600;
  color: var(--dfx-ink);
  margin: 14px 0 5px;
}

.dfx-sheet p {
  font-size: 10.5px;
  line-height: 1.6;
  margin: 0 0 8px;
}

/* the same drawing as the HTML view, two thirds the size, because a
   sheet is narrower than an article column */
.dfx-sheet .dfx-fig { font-size: 6.6px; }
.dfx-sheet .dfx-shot { margin: 4px 0 10px; }

.dfx-sheet .dfx-shot-cap {
  margin-top: 5px;
  font-size: 8.5px;
  color: rgba(28, 28, 28, .42);
  font-style: italic;
}

/* ── plain text ── */
.dfx-txt {
  margin: 0;
  padding: 18px 22px 52px;
  font-family: var(--dfx-mono);
  font-size: 12px;
  line-height: 1.75;
  color: var(--dfx-ink-2);
  white-space: pre;
  overflow-x: auto;
}

/* ── the window footer ──
   One fact per format. It is here to show that the four chips are
   four real files with different properties, not one file wearing
   four labels. */
.dfx-doc-foot {
  flex: none;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 0 14px;
  height: 36px;
  background: #FAFAFB;
  border-top: 1px solid var(--dfx-hair-2);
  font-family: var(--dfx-mono);
  font-size: 10.5px;
  color: var(--dfx-ink-3);
}

.dfx-doc-foot .lang {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  white-space: nowrap;
}

.dfx-doc-foot .lang svg { width: 11px; height: 11px; }

/* ═══ THE SWITCHER ═════════════════════════════════════════
   .billing-toggle's shape, because the site already owns that
   idiom for a segmented control and a second one would just be a
   second idiom. Below the stage on purpose: the artifact leads
   and the control follows, so the section reads "here is the
   demo, and it is also these" rather than "choose one". */

.dfx-tabs {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  padding: 4px;
  border-radius: 100px;
  background: rgb(236, 236, 236);
  max-width: 100%;
}

.dfx-tab {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 8px 18px;
  border: none;
  border-radius: 100px;
  background: transparent;
  font-family: var(--dfx-sans);
  font-size: 15px;
  font-weight: 500;
  letter-spacing: -.15px;
  color: rgba(28, 28, 28, .5);
  white-space: nowrap;
  cursor: pointer;
  transition: background .2s ease, color .2s ease;
}

.dfx-tab:hover { color: rgba(28, 28, 28, .78); }

.dfx-tab[aria-selected='true'] {
  background: rgb(28, 28, 28);
  color: rgb(246, 246, 246);
}

.dfx-tab svg { width: 15px; height: 15px; flex: none; }

.dfx-cap {
  min-height: 20px;
  margin: 0;
  font-family: var(--dfx-sans);
  font-size: 14px;
  line-height: 1.4;
  color: var(--dfx-ink-3);
  text-align: center;
  max-width: 560px;
  transition: opacity .2s ease;
}

.dfx-cap.fading { opacity: 0; }


/* ═══ RESPONSIVE ═══════════════════════════════════════════
   The player's own stylesheet already carries its internal
   breakpoints. What is left here is the stage height it now sits
   in, which the source page expressed as an aspect ratio on
   .idp-screen and which belongs to .dfx-stage instead. */

@media (max-width: 1120px) {
  /* the band /interactive-demos also treats specially: too narrow for
     the app to breathe at 16:10, too wide for the phone layout */
  .dfx-stage { aspect-ratio: auto; height: clamp(560px, 58vw, 640px); }
  .dfx-assets { gap: 8px; }
}

/* The sidebar goes at 900, not at the source player's own 760.
   It is 224px, and step 5 lays its preview and actions out as
   `1fr 178px` needing about 580px of page column. With the sidebar
   still up at 800px wide the column is 429px, the grid overflows its
   own container, and the actions and their tooltip hang outside the
   frame. Giving the page those 224px back is what fixes it; the
   sidebar is furniture, the step is the point. */
@media (max-width: 900px) {
  .dfx-int .vg-side { display: none; }
  /* nothing left for it to collapse, so it stops offering to */
  .dfx-int .ds-collapse { display: none; }
}

@media (max-width: 760px) {
  .dfx-tab { padding: 8px 14px; font-size: 14px; }
  .dfx-tab svg { display: none; }
  .dfx-html { padding: 18px 20px 50px; }

  /* the chips row and the full-screen switch are the first things to
     go from the player's own footer at this width */
  .dfx-int .idp-chip-l { display: none; }
  .dfx-int .idp-foot-right { gap: 6px; }
}

@media (max-width: 600px) {
  /* a 244px card is most of a phone screen; the nudge in placeTip keeps
     whatever width it has inside the frame, this just stops it filling
     the whole thing */
  .dfx-int .idp-tt { width: min(244px, 74vw); }
}

/* ── the phone ─────────────────────────────────────────────
   Most visitors arrive on one, so this is the layout that matters
   most, not a fallback. The source player hides a lot below 760
   because on its own page the screen drops to a 5:6 box; here the
   stage is a fixed height we control, so the things that make the
   app recognisable are earned back and only the genuinely
   unaffordable ones stay hidden. */
@media (max-width: 600px) {
  /* .demo-section already pays 20px a side; .dfx paying another 16
     left the frame 303px wide inside a 375px phone */
  .dfx { padding: 0; gap: 14px; }
  .dfx-stage { aspect-ratio: auto; height: 600px; }

  /* An address bar with nothing in it but three traffic lights does
     not read as a shared link, which is the whole framing of this
     panel. The address stays and truncates; the CTA keeps its icon. */
  .dfx-int .idp-pb-url {
    display: flex;
    max-width: none;
    font-size: 10px;
    padding: 0 8px;
  }
  .dfx-int .idp-pb-cta { display: inline-flex; padding: 0 9px; }
  .dfx-int .idp-pb-cta span { display: none; }
  .dfx-int .idp-player-bar { padding: 9px 11px; gap: 8px; }

  /* "Create Demo" is the app's identity and the step counter is the
     clearest progress signal on a screen where the dots are 26px of
     hairline. Both are hidden by the source at this width; both come
     back, compacted to pay for themselves. */
  .dfx-int .ds-pagehead { display: flex; padding: 9px 11px; gap: 9px; }
  .dfx-int .ds-pagehead-ic { width: 26px; height: 26px; border-radius: 8px; }
  .dfx-int .ds-pagehead-ic svg { width: 14px; height: 14px; }
  .dfx-int .vg-h1 { font-size: 14px; }
  .dfx-int .vg-sub { font-size: 10.5px; }
  .dfx-int .ds-stepcount { display: none; }
  .dfx-int .idp-foot-label { display: inline; font-size: 11px; }

  /* the wizard fits once its connectors stop being 74px each */
  .dfx-int .ds-wizard { display: flex; }
  .dfx-int .ds-wz-line { width: 26px; margin: 0 2px 18px; }
  .dfx-int .ds-wz b { width: 28px; height: 28px; }
  .dfx-int .ds-wz b svg { width: 13px; height: 13px; }
  .dfx-int .ds-wz span { font-size: 10px; }

  /* the caption replaces the tooltip here, so it has to stay short
     enough to leave the app the room it needs */
  .dfx .idp-caption { padding: 9px 14px 11px; font-size: 12px; line-height: 1.4; }

  .dfx-int .ds-h2 { font-size: 20px; }
  .dfx-int .ds-lede { font-size: 12px; margin-top: 5px; }
  .dfx-int .vg-page { padding: 13px 14px; gap: 11px; }

  /* the source line stacks rather than scrolling sideways */
  .dfx-source {
    flex-direction: column;
    align-items: stretch;
    border-radius: 18px;
    text-align: center;
  }
  .dfx-pill { padding: 9px 14px; justify-content: center; }
  .dfx-pill--prompt { padding: 0 14px 10px; }
  .dfx-plus { display: none; }

  .dfx-tabs { padding: 3px; }
  .dfx-tab { padding: 8px 11px; font-size: 13px; }
  .dfx-cap { font-size: 13px; }

  /* full screen is the one footer chip a phone has no use for */
  .dfx-int #dfxFull { display: none; }

  /* three columns of prose do not fit; let the cells wrap instead of
     giving the article its own sideways scroll */
  .dfx-html table { table-layout: fixed; }
  .dfx-html th, .dfx-html td { padding: 6px 6px; word-break: break-word; }

  .dfx-fmts { margin-left: 0; }
  .dfx-fname span { display: none; }
  .dfx-doc-foot .lang { display: none; }
  .dfx-sheet { width: 92%; padding: 22px 20px; }
}

/* A phone in landscape, and the shorter phones in portrait, give the
   page less height than the stage wants. A 560px player in a 380px
   viewport can never be seen whole: the visitor reads the app with the
   caption and the step controls off screen below them. Tie the stage
   to the viewport in that case and let the app's own page scroll,
   which revealTarget already drives. */
@media (max-height: 700px) {
  .dfx-stage { height: min(600px, 88vh); }
  .dfx .idp-caption {
    padding: 8px 14px 9px;
    font-size: 11.5px;
    line-height: 1.35;
    max-height: 3.2em;
    overflow: hidden;
  }
}

/* The player's own reduced-motion handling comes with the port. This
   covers the shell around it. */
@media (prefers-reduced-motion: reduce) {
  .dfx-panel,
  .dfx-panel.is-on { transition: opacity .01s linear, visibility 0s; transform: none; }
  .dfx-int .idp-frame.beat-2 [data-beat='2'] { animation: none; }
  .dfx-int .is-typing .ds-type { animation: none; clip-path: none; }
  .dfx-int .is-typing .ds-caret { animation: none; opacity: 1; }
}
