/* ===========================================================================
   Capability dial, rebuilt from Figma
   File gSV4KtGZpMu6vyC3mE0B27, page "Website", frames `infocircle-section`
   (600:2211, 594:7320, 594:7385, 594:8284: one frame per state 01 to 04;
   the fifth capability, Automations, was dropped on 17.09.).

   Mechanic: the section is several viewports tall and a viewport-high stage
   sticks while it scrolls through. Scroll progress maps onto the steps with
   a plateau on every point (slow there, quick in between); the wheel turns
   continuously, entry and collage fade in, hold, fade out and the next pair
   follows after a gap. dial.js drives `--s` and the inline opacity/blur.

   Same canvas recipe as the hero: a 1728 x 1117 composition, `--u` is one
   design pixel, every object sits at its Figma coordinate. The section
   backgrounds are Figma's shader renders (assets/dial/bg), exported like the
   hero wash, because "Pattern refraction" needs WebGPU.
   =========================================================================== */

.dial {
    container-type: inline-size;
    position: relative;
    /* one viewport for the first stop, 2.4 more per step; dial.js spends most
       of each step's scroll on the point itself and little on the way */
    height: calc((1 + 3 * 2.4) * 100svh);
    background: #fff;
    --accent: #f86126;
    --ring-alpha: 0.5;
    /* angle between two numbers on the rim (Figma draws 30, wider reads
       better while the wheel turns) */
    --arc: 45deg;
}

.dial__stage {
    position: sticky;
    top: 0;
    height: 100svh;
    display: grid;
    /* a fixed track, so a canvas taller than the stage is centred on it
       instead of pushing the track open and hanging from the top */
    grid-template-rows: 100%;
    grid-template-columns: 100%;
    place-items: center;
    overflow: hidden;
    isolation: isolate;
}

/* ---- backgrounds: one wash per state, crossfaded by dial.js ------------- */

.dial__wash {
    position: absolute;
    inset: 0;
    background: center / cover no-repeat;
    opacity: 0;
    pointer-events: none;
    /* The stage clips, so a coloured field would meet the white sections above
       and below on a ruled line. It dissolves into the page instead: opaque
       through the middle two thirds, gone at both edges. */
    -webkit-mask-image: linear-gradient(180deg,
        rgba(0, 0, 0, 0) 0%, #000 16%, #000 84%, rgba(0, 0, 0, 0) 100%);
    mask-image: linear-gradient(180deg,
        rgba(0, 0, 0, 0) 0%, #000 16%, #000 84%, rgba(0, 0, 0, 0) 100%);
}

.dial__wash--1 { background-image: url('/assets/dial/bg/wash-1.jpg'); }
.dial__wash--2 { background-image: url('/assets/dial/bg/wash-2.jpg'); }
.dial__wash--3 { background-image: url('/assets/dial/bg/wash-3.jpg'); }
.dial__wash--4 { background-image: url('/assets/dial/bg/wash-4.jpg'); }

/* ---- canvas ------------------------------------------------------------- */

.dial__canvas {
    /* Width-first, unlike the hero: the frame edge has to be the screen edge,
       so the circle is half outside on the left and the 03 collage runs off
       on the right, as in Figma. On flat screens the stage clips a little of
       the top and bottom instead (nothing sits there). */
    --fig-w: 100cqw;
    position: relative;
    width: var(--fig-w);
    aspect-ratio: 1728 / 1117;
    /* one design pixel; --fu is the same value for parts that need a scaled
       copy of --u (the 03 chat bar is the hero bar at 108.3 %) */
    --fu: calc(var(--fig-w) / 1728);
    --u: var(--fu);
    font-family: 'Archivo', system-ui, sans-serif;
    /* nothing is clipped at the frame: the circle runs on to the screen edge
       and the entries travel past the canvas; the stage does the clipping */
    overflow: visible;
}

.dial__canvas [data-fig] {
    position: absolute;
}

/* ---- the dial ----------------------------------------------------------- */

/* Circle: 800 at (-443, 159), 1px black. Its centre is (-43, 559). */
.dial__ring,
.dial__wheel {
    left: calc(-443 * var(--u));
    top: calc(159 * var(--u));
    width: calc(800 * var(--u));
    height: calc(800 * var(--u));
    border-radius: 50%;
}

.dial__ring {
    border: 1px solid #000;
    pointer-events: none;
}

.dial__wheel {
    /* turns with the scroll itself, number to number, no snapping */
    transform: rotate(calc(var(--s, 0) * -1 * var(--arc)));
    will-change: transform;
}

/* One 800 x 36 row per number, centred on the circle and turned by --arc
   each; the label starts 415px from the centre, 15px outside the rim. */
.dial__num {
    position: absolute;
    left: 0;
    top: calc(382 * var(--u));
    width: calc(800 * var(--u));
    height: calc(36 * var(--u));
    margin: 0;
    padding: 0;
    border: 0;
    background: none;
    transform: rotate(calc(var(--i) * var(--arc)));
    pointer-events: none;
}

.dial__num span {
    position: absolute;
    left: calc(815 * var(--u));
    top: 0;
    display: block;
    padding: 0 calc(6 * var(--u));
    margin-left: calc(-6 * var(--u));
    font-size: calc(32 * var(--u));
    line-height: calc(36 * var(--u));
    letter-spacing: calc(-1.28 * var(--u));
    color: #858282;
    cursor: pointer;
    pointer-events: auto;
    transition: color 0.35s ease, transform 0.45s cubic-bezier(0.22, 1, 0.36, 1);
}

/* The active number sits 20px further out to leave room for the dot. */
.dial__num.is-active span {
    color: #141414;
    transform: translateX(calc(20 * var(--u)));
}

/* The dot stays at the rim while the wheel turns under it: a 44 box centred
   on the rim's rightmost point, 20.56 dot, 37 ring at 2.06. */
.dial__dot {
    left: calc(335 * var(--u));
    top: calc(537 * var(--u));
    width: calc(44 * var(--u));
    height: calc(44 * var(--u));
    pointer-events: none;
}

.dial__dot::before {
    content: '';
    position: absolute;
    left: calc(3 * var(--u));
    top: calc(3 * var(--u));
    width: calc(37 * var(--u));
    height: calc(37 * var(--u));
    border-radius: 50%;
    border: calc(2.056 * var(--u)) solid
        color-mix(in srgb, var(--accent) calc(var(--ring-alpha) * 100%), transparent);
    box-sizing: border-box;
    transition: border-color 0.35s ease;
}

.dial__dot::after {
    content: '';
    position: absolute;
    left: calc(11.722 * var(--u));
    top: calc(11.722 * var(--u));
    width: calc(20.556 * var(--u));
    height: calc(20.556 * var(--u));
    border-radius: 50%;
    background: var(--accent);
    box-shadow: 0 calc(4.111 * var(--u)) calc(10.278 * var(--u))
        color-mix(in srgb, var(--accent) 20%, transparent);
    transition: background-color 0.35s ease, box-shadow 0.35s ease;
}

/* ---- entries: the Capability Entry component at (517, 420) -------------- */

.dial__entry {
    /* The block carries a slightly smaller unit of its own, the way the 03
       chat bar does, so the eyebrow, the title, the copy and the tags shrink
       together instead of one size at a time. Position stays in --fu: scaling
       the unit must not drag the block back towards the wheel. Moved right by
       as much as the scale takes off its width, so its right edge stays where
       it was and the product shot keeps its distance. */
    --u: calc(var(--fu) * 0.9);
    left: calc(622 * var(--fu));
    top: calc(420 * var(--fu));
    width: calc(560 * var(--u));
    margin: 0;
    will-change: transform, filter, opacity;
}

.dial__eyebrow {
    margin: 0 0 calc(12 * var(--u));
    font-size: calc(12 * var(--u));
    line-height: calc(18.6 * var(--u));
    letter-spacing: calc(1.2 * var(--u));
    text-transform: uppercase;
    color: #171717;
    white-space: nowrap;
}

.dial__title {
    margin: 0 0 calc(18 * var(--u));
    font-weight: 400;
    font-size: calc(56 * var(--u));
    line-height: calc(58 * var(--u));
    letter-spacing: calc(-0.48 * var(--u));
    color: #212121;
}

.dial__desc {
    width: calc(440 * var(--u));
    margin: 0 0 calc(26 * var(--u));
    /* Held at the size it had before the block took a smaller unit: display
       type carries the change, running copy has a floor and this frame is
       already at 13px on a 1400 laptop. */
    font-size: calc(17.8 * var(--u));
    line-height: calc(27.5 * var(--u));
    color: #6b6b70;
}

.dial__tags {
    display: flex;
    flex-wrap: wrap;
    gap: calc(8 * var(--u));
    margin: 0;
    padding: 0;
    list-style: none;
}

.dial__tag {
    padding: calc(7 * var(--u)) calc(14 * var(--u));
    border: 1px solid #c5c1b9;
    border-radius: 999px;
    font-size: calc(13 * var(--u));
    line-height: calc(20.15 * var(--u));
    color: #212121;
    white-space: nowrap;
}

/* ---- visuals: the product, one collage per state ----------------------- */

.dial__visual {
    position: absolute;
    inset: 0;
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    transform: translateY(var(--vdrift, 0px));
    will-change: opacity, filter, transform;
}

.dial__visual.is-near {
    visibility: visible;
}

.dial__visual [data-fig] {
    position: absolute;
}

.dial__cursor {
    width: calc(63 * var(--u));
    height: calc(63 * var(--u));
}

/* SF Pro is what the product renders in; the fallbacks are the platform UI
   font, the same stack the hero uses. */
.dial__sf {
    font-family: -apple-system, 'SF Pro Text', system-ui, sans-serif;
}

.dial__inter {
    font-family: 'Inter', system-ui, sans-serif;
}

/* -- 01: an agenda drafted in chat, on its Figma coordinates (the agenda
   text runs 118px past the frame edge, as designed) ------------------------ */

/* The messages window: the panel above the bar. The thread inside is a
   full-canvas layer shifted back by the window's own offset, so every
   message keeps its Figma coordinate while the window does the clipping.
   Scrolling the thread is what a real chat does; nothing fades away. */
.dial__v1-clip {
    left: calc(1182 * var(--u));
    top: calc(198 * var(--u));
    width: calc(646 * var(--u));
    height: calc(462 * var(--u));
    overflow: hidden;
}

.dial__v1-thread {
    position: absolute;
    left: calc(-1182 * var(--u));
    top: calc(-198 * var(--u));
    width: calc(1728 * var(--u));
    height: calc(1117 * var(--u));
    will-change: transform;
}

.dial__v1-panel {
    left: calc(1182 * var(--u));
    top: calc(198 * var(--u));
    width: calc(646 * var(--u));
    height: calc(642 * var(--u));
    background: rgba(255, 254, 254, 0.4);
    border-radius: calc(21.415 * var(--u));
}

.dial__v1-ask,
.dial__v1-ask2 {
    left: calc(1200 * var(--u));
    top: calc(211 * var(--u));
    width: calc(621 * var(--u));
    height: calc(114 * var(--u));
    box-sizing: border-box;
    padding: calc(19.987 * var(--u)) calc(37.119 * var(--u)) calc(18 * var(--u));
    background: #ffe2d7;
    border-radius: calc(21.415 * var(--u));
    display: flex;
    align-items: flex-end;
}

/* The second exchange, placed on the SAME bottom rhythm as the first.
   A thread grows downward, so it must not reuse the first pair's top edge:
   that left the answer 174 above the bar where the design has 47.5, a hole
   the eye reads as a broken layout. Measured at 1512: the bubble is 75 tall
   with its one line, the confirmation 147.4, the bar starts at 670. So the
   confirmation ends at 622.5 like the agenda does, the bubble keeps the
   design's 39 between question box and answer (both bubbles carry the same
   18 bottom padding, so equal box gaps read as equal text gaps), and the
   pair sits just above the bar. */
.dial__v1-ask2 {
    top: calc(661 * var(--u));
    height: auto;
}

.dial__v1-ask p,
.dial__v1-ask2 p {
    width: calc(582.583 * var(--u));
    margin: 0;
    font-weight: 500;
    font-size: calc(31.44 * var(--u));
    line-height: normal;
    color: #212529;
}

.dial__v1-answer,
.dial__v1-reply {
    left: calc(1228 * var(--u));
    top: calc(348 * var(--u));
    width: calc(618 * var(--u));
    margin: 0;
    font-weight: 500;
    font-size: calc(30.074 * var(--u));
    line-height: calc(49.162 * var(--u));
    color: #212529;
}

.dial__v1-answer strong,
.dial__v1-reply strong {
    display: block;
    font-weight: 700;
}

.dial__v1-reply p {
    margin: 0;
}

/* AFTER the shared `.dial__v1-answer, .dial__v1-reply` block, or the 348 it
   sets would win on source order and the confirmation would keep the first
   answer's top edge. */
.dial__v1-reply {
    top: calc(775 * var(--u));
}

/* The second exchange sits exactly where the first one is and is hidden
   until the send click hands the thread over to it. */
.dial__v1-ask2,
.dial__v1-reply strong,
.dial__v1-reply p {
    opacity: 0;
}

/* Figma holds an empty 49px paragraph here that its renderer collapses, so
   the list follows the headline directly. */
.dial__v1-answer ol {
    margin: 0;
    padding: 0 0 0 calc(45.111 * var(--u));
    line-height: calc(45.065 * var(--u));
}

.dial__v1-answer li {
    margin: 0;
}

.dial__chat {
    background: #fff;
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
    box-sizing: border-box;
}

.dial__v1-chat {
    left: calc(1200 * var(--u));
    top: calc(670 * var(--u));
    width: calc(637.073 * var(--u));
    height: calc(151.732 * var(--u));
    padding: calc(21 * var(--u)) calc(22.41 * var(--u)) calc(23.624 * var(--u));
    gap: calc(21 * var(--u));
    border-radius: calc(27.919 * var(--u));
    box-shadow: 0 calc(1.748 * var(--u)) calc(8.739 * var(--u))
        calc(3.496 * var(--u)) rgba(168, 168, 168, 0.2);
}

.dial__v1-chat .dial__chat-ph {
    height: calc(33.058 * var(--u));
    font-weight: 400;
    font-size: calc(30 * var(--u));
}

.dial__chat-ph {
    margin: 0;
    color: #62666b;
    line-height: normal;
    white-space: nowrap;
}

/* The text caret after the typed line: Vector 1386, a 53 tall stroke. */
.dial__caret {
    width: calc(3 * var(--u));
    height: calc(53 * var(--u));
}

.dial__v1-caret {
    /* The line's end, measured: dial.js writes --type-w from the glyphs. The
       fallback is what the frame was authored with. */
    left: calc((1222.41 + var(--type-w, 271.09)) * var(--u));
    top: calc(677 * var(--u));
}

.dial__v1-cursor {
    left: calc(1145 * var(--u));
    top: calc(867 * var(--u));
}

/* The chat bar's bottom row, the hero's measurements. Everything is in --u,
   so the 03 bar only redefines --u to get the larger copy. */
.dial__row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    height: calc(51.224 * var(--u));
}

.dial__row-left,
.dial__row-right {
    display: flex;
    align-items: center;
}

.dial__row-left { gap: calc(6.403 * var(--u)); }
.dial__row-right { gap: calc(12.806 * var(--u)); }

.dial__row-btn {
    width: calc(51.224 * var(--u));
    height: calc(51.224 * var(--u));
    display: block;
}

.dial__row-pill {
    position: relative;
    height: calc(51.224 * var(--u));
}

.dial__row-pill > * {
    position: absolute;
}

.dial__row-pill--ask { width: calc(172.079 * var(--u)); }
.dial__row-pill--model { width: calc(153.671 * var(--u)); }

.dial__row-pill .dial__row-chev {
    width: calc(38.418 * var(--u));
    height: calc(38.418 * var(--u));
    top: calc(6.404 * var(--u));
}

.dial__row-pill .dial__row-lock {
    width: calc(19.895 * var(--u));
    height: calc(25.385 * var(--u));
    left: calc(32.475 * var(--u));
    top: calc(11.326 * var(--u));
}

.dial__row-pill span {
    font-family: -apple-system, 'SF Pro Text', system-ui, sans-serif;
    font-weight: 500;
    font-size: calc(19.209 * var(--u));
    color: #62666b;
    top: calc(14.409 * var(--u));
    white-space: nowrap;
}

.dial__row-pill--ask span { left: calc(64.476 * var(--u)); }
.dial__row-pill--ask .dial__row-chev { left: calc(138.464 * var(--u)); }
.dial__row-pill--model span { left: calc(17.608 * var(--u)); }
.dial__row-pill--model .dial__row-chev { left: calc(102.446 * var(--u)); }

.dial__row-icon {
    position: relative;
    flex: none;
    width: calc(38.418 * var(--u));
    height: calc(38.418 * var(--u));
}

.dial__row-icon img {
    position: absolute;
    display: block;
}

.dial__row-icon--mic img {
    left: calc(8.142 * var(--u));
    top: calc(3.733 * var(--u));
    width: calc(22.144 * var(--u));
    height: calc(29.485 * var(--u));
}

.dial__row-icon--audio img {
    left: calc(5.601 * var(--u));
    top: calc(4 * var(--u));
    width: calc(25.611 * var(--u));
    height: calc(28.813 * var(--u));
}

/* -- 02: the Ask first menu ------------------------------------------------ */

/* Rectangle 205: the open pill, white at 80 %. */
.dial__v2-pill {
    left: calc(1152 * var(--u));
    top: calc(371 * var(--u));
    width: calc(285 * var(--u));
    height: calc(73.286 * var(--u));
    background: rgba(255, 255, 255, 0.8);
    border-radius: calc(51.571 * var(--u));
}

.dial__v2-pill img,
.dial__v2-pill span {
    position: absolute;
}

/* the lock glyph is 25.72 x 33.07 at (39.42, 19); the export carries the
   stroke overhang, so it is placed 0.8 up and left of that */
.dial__v2-pill .dial__v2-lock {
    left: calc(38.165 * var(--u));
    top: calc(17.74 * var(--u));
    width: calc(28.235 * var(--u));
    height: calc(35.584 * var(--u));
}

.dial__v2-pill span {
    left: calc(81.752 * var(--u));
    top: calc(16.284 * var(--u));
    width: calc(137 * var(--u));
    height: calc(43 * var(--u));
    font-weight: 400;
    font-size: calc(35.286 * var(--u));
    line-height: calc(43 * var(--u));
    text-align: center;
    color: #212529;
    white-space: nowrap;
}

/* The mode the pill starts on. Same optical box as the lock, contained so
   the small export is not stretched into it. */
.dial__v2-pill .dial__v2-bolt {
    left: calc(38.165 * var(--u));
    top: calc(17.74 * var(--u));
    width: calc(28.235 * var(--u));
    height: calc(35.584 * var(--u));
    object-fit: contain;
}

/* the chosen mode waits underneath and is faded in on the pick */
.dial__v2-pill .dial__v2-label--to,
.dial__v2-pill .dial__v2-lock {
    opacity: 0;
}

/* the caret points up while the menu is open; Figma has it 7px below the
   text's centre line, here it sits on it */
.dial__v2-pill .dial__v2-caret {
    left: calc(243 * var(--u));
    top: calc(32.2 * var(--u));
    width: calc(19.271 * var(--u));
    height: calc(11.129 * var(--u));
    transform: rotate(180deg);
}

/* Group 2756: the menu surface (364.39 x 203 at 1263, 434.71) is an export
   that includes its drop shadow, hence the larger box. */
.dial__v2-menu {
    left: calc(1252.18 * var(--u));
    top: calc(425.88 * var(--u));
    width: calc(386.049 * var(--u));
    height: calc(224.656 * var(--u));
}

.dial__v2-item-icon {
    width: calc(18.936 * var(--u));
    height: calc(23.308 * var(--u));
}

.dial__v2-icon-1 { left: calc(1292.92 * var(--u)); top: calc(463.7 * var(--u)); }
.dial__v2-icon-2 {
    left: calc(1294.53 * var(--u));
    top: calc(553.31 * var(--u));
    width: calc(18.814 * var(--u));
    height: calc(23.315 * var(--u));
}

.dial__v2-name,
.dial__v2-hint {
    left: calc(1330.91 * var(--u));
    margin: 0;
    line-height: normal;
    white-space: nowrap;
}

.dial__v2-name {
    font-weight: 700;
    font-size: calc(23.189 * var(--u));
    color: #212529;
}

.dial__v2-hint {
    font-weight: 400;
    font-size: calc(21.532 * var(--u));
    color: rgba(73, 80, 87, 0.76);
}

.dial__v2-name--1 { top: calc(461.216 * var(--u)); }
.dial__v2-hint--1 { top: calc(497.888 * var(--u)); }
.dial__v2-name--2 { top: calc(550.658 * var(--u)); }
.dial__v2-hint--2 { top: calc(587.793 * var(--u)); }

.dial__v2-cursor {
    left: calc(1583 * var(--u));
    top: calc(488.715 * var(--u));
}

/* -- 03: the Commands panel, everything in the accent ink #dc7479. This one
   keeps Figma's overhang: panel, cards and chat bar run past the frame's
   right edge and are cut by the screen edge (at 1728 that IS the frame). -- */

/* What the pair does when the palette drops.

   While the palette is open the overhang is Figma's own: the palette is a
   wide column and the frame cuts it. With only the card and the bar left
   there is nothing left to justify a cut, so the two step in off the edge
   far enough to stand whole, and the card moves onto the bar's middle.

   203 is the bar's 179 of overhang plus 24 of air. It is the smallest move
   that puts the bar fully on screen, which keeps the collage on the
   right-hand side it is drawn on rather than walking it into the text.
   152 is half the difference between the card's 340 and the bar's 648.

   The pair also drops. Closing the gap the palette left behind pulled it up
   against the top of the frame, with the whole lower half empty under it.
   358 is not a free choice: pulled in this far the bar is only just clear of
   the text column, so it can sit above the title or below the tags and
   nowhere in between. Below is the one that answers "too high" while keeping
   its margin to the frame. */
.dial__visual--3 { --v3-pull: 203; --v3-card-x: 152; --v3-drop: 358; }

.dial__v3-card {
    left: calc(1261 * var(--u));
    top: calc(138 * var(--u));
    width: calc(340 * var(--u));
    height: calc(135 * var(--u));
    box-sizing: border-box;
    padding: calc(24.863 * var(--u)) calc(27.123 * var(--u));
    display: flex;
    gap: calc(18.082 * var(--u));
    align-items: flex-start;
    background: #fff;
    border-radius: calc(25.63 * var(--u));
    filter: drop-shadow(0 calc(3.138 * var(--u)) calc(7.846 * var(--u)) rgba(252, 134, 139, 0.2));
    color: #dc7479;
}

.dial__v3-card-icon {
    flex: none;
    position: relative;
    width: calc(54.246 * var(--u));
    height: calc(54.246 * var(--u));
}

.dial__v3-card-icon img {
    position: absolute;
    left: calc(3.39 * var(--u));
    top: calc(2.145 * var(--u));
    width: calc(47.466 * var(--u));
    height: calc(49.956 * var(--u));
}

.dial__v3-card-text {
    width: calc(228.062 * var(--u));
    display: flex;
    flex-direction: column;
    gap: calc(4.521 * var(--u));
}

.dial__v3-card-text b {
    font-weight: 700;
    font-size: calc(27.123 * var(--u));
    line-height: calc(29.836 * var(--u));
}

.dial__v3-card-text p {
    margin: 0;
    font-weight: 500;
    font-size: calc(24.863 * var(--u));
    line-height: calc(31.079 * var(--u));
}

.dial__v3-panel {
    left: calc(1259 * var(--u));
    top: calc(296 * var(--u));
    /* the same 648 the chat bar below is, and off the same left edge: the
       palette is that bar opened upwards, so the two share a silhouette */
    width: calc(648 * var(--u));
    height: calc(597 * var(--u));
    box-sizing: border-box;
    padding: 0 calc(21.968 * var(--u)) calc(21.968 * var(--u));
    display: flex;
    flex-direction: column;
    background: rgba(255, 255, 255, 0.8);
    border-radius: calc(25.629 * var(--u));
    filter: drop-shadow(0 calc(14.645 * var(--u)) calc(29.29 * var(--u)) #ffdfe1);
    color: #dc7479;
}

.dial__v3-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: calc(21.968 * var(--u)) 0 calc(7 * var(--u));
}

.dial__v3-head b {
    display: block;
    padding: calc(3.661 * var(--u)) calc(7.323 * var(--u)) calc(7.323 * var(--u));
    font-weight: 700;
    font-size: calc(21.968 * var(--u));
    line-height: calc(32.951 * var(--u));
    white-space: nowrap;
}

.dial__v3-close {
    flex: none;
    width: calc(40.274 * var(--u));
    height: calc(40.274 * var(--u));
    display: grid;
    place-items: center;
}

.dial__v3-close img {
    width: calc(23.798 * var(--u));
    height: calc(23.798 * var(--u));
}

.dial__v3-search-wrap {
    padding: 0 calc(3.661 * var(--u));
}

.dial__v3-search {
    height: calc(62.241 * var(--u));
    box-sizing: border-box;
    padding: calc(10.984 * var(--u)) calc(21.968 * var(--u));
    display: flex;
    align-items: center;
    gap: calc(14.645 * var(--u));
    background: #fff;
    border: calc(1.831 * var(--u)) solid #ffe5e6;
    border-radius: calc(181.232 * var(--u));
}

.dial__v3-search img {
    width: calc(25.629 * var(--u));
    height: calc(25.629 * var(--u));
}

.dial__v3-search span {
    font-weight: 400;
    font-size: calc(21.968 * var(--u));
    line-height: calc(32.951 * var(--u));
    color: #994c4f;
    white-space: nowrap;
}

.dial__v3-sub {
    display: block;
    padding: calc(18.306 * var(--u)) calc(7.323 * var(--u)) calc(10.984 * var(--u));
    font-weight: 600;
    font-size: calc(20.137 * var(--u));
    line-height: calc(30.205 * var(--u));
}

.dial__v3-grid {
    display: flex;
    flex-direction: column;
    gap: calc(14.645 * var(--u));
}

/* Command Card: 604 wide in a 525 column, so it runs off the panel and the
   frame edge, exactly as in the design. */
.dial__v3-cmd {
    width: calc(604.065 * var(--u));
    box-sizing: border-box;
    padding: calc(14.645 * var(--u)) calc(21.968 * var(--u)) calc(14.645 * var(--u)) calc(25.629 * var(--u));
    display: flex;
    align-items: center;
    gap: calc(20.137 * var(--u));
    background: #fff;
    border-radius: calc(6 * var(--u));
    filter: drop-shadow(0 calc(7.323 * var(--u)) calc(9.153 * var(--u)) rgba(220, 116, 121, 0.2));
}

.dial__v3-cmd + .dial__v3-cmd {
    filter: drop-shadow(0 calc(5.492 * var(--u)) calc(5.492 * var(--u)) rgba(252, 134, 139, 0.2));
}

.dial__v3-cmd-icon {
    flex: none;
    position: relative;
    width: calc(36.613 * var(--u));
    height: calc(34.782 * var(--u));
}

.dial__v3-cmd-icon img {
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
}

.dial__v3-cmd-icon--chase img {
    width: calc(28.832 * var(--u));
    height: calc(35.354 * var(--u));
}

.dial__v3-cmd-icon--report img {
    width: calc(35.344 * var(--u));
    height: calc(35.354 * var(--u));
}

.dial__v3-cmd-text {
    flex: 1 1 0;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: calc(3.661 * var(--u));
}

.dial__v3-cmd-text b {
    font-weight: 700;
    font-size: calc(21.97 * var(--u));
    line-height: calc(24.164 * var(--u));
}

.dial__v3-cmd-text p {
    margin: 0;
    font-weight: 500;
    font-size: calc(20.14 * var(--u));
    line-height: calc(25.171 * var(--u));
}

/* the 03 chat bar is the hero bar at 108.29 % (55.47 buttons, 41.6 icons)
   and runs off the frame like the panel above it */
.dial__v3-chat {
    --u: calc(var(--fu) * 1.08286);
    left: calc(1259 * var(--fu));
    top: calc(745.945 * var(--fu));
    width: calc(648 * var(--fu));
    height: calc(164.526 * var(--fu));
    padding: calc(39.917 * var(--fu)) calc(24.267 * var(--fu)) calc(25.581 * var(--fu));
    gap: calc(11.215 * var(--fu));
    border-radius: calc(30.232 * var(--fu));
    box-shadow: 0 calc(1.893 * var(--fu)) calc(9.463 * var(--fu))
        calc(3.785 * var(--fu)) rgba(220, 162, 162, 0.2);
}

.dial__v3-chat .dial__chat-ph {
    height: calc(61.783 * var(--fu));
    display: flex;
    align-items: center;
    font-weight: 400;
    font-size: calc(35 * var(--fu));
}

.dial__v3-chat .dial__row {
    width: calc(600.374 * var(--fu));
}

.dial__v3-caret {
    /* Same measured end as 01; authored at 123.23, which left a space between
       the slash command and the caret that typed it. */
    left: calc((1283.27 + var(--type-w, 123.23)) * var(--u));
    top: calc(763.91 * var(--u));
}

/* The armed skill: what the pick leaves on the bar, on the line the typed
   text was on. Sized off --fu, like everything else in this bar. */
.dial__v3-chip {
    position: absolute;
    left: calc(24.267 * var(--fu));
    top: calc(22 * var(--fu));
    display: inline-flex;
    align-items: center;
    gap: calc(12 * var(--fu));
    height: calc(48 * var(--fu));
    padding: 0 calc(18 * var(--fu));
    /* a pill, like every other chip on the page */
    border-radius: 999px;
    background: rgba(252, 134, 139, 0.16);
    color: #cf636a;
    font-size: calc(25 * var(--fu));
    line-height: 1;
    white-space: nowrap;
    opacity: 0;
}

.dial__v3-chip code { font-family: inherit; font-weight: 500; }
.dial__v3-chip-x { font-size: calc(27 * var(--fu)); opacity: 0.66; }

/* On the first skill in the list, not beside the bar: the beat this collage
   plays is picking Chase Payment, so the hand is where the pick happens. */
.dial__v3-cursor {
    left: calc(1424 * var(--u));
    top: calc(528 * var(--u));
}

/* -- 04: the Groups tree ---------------------------------------------------- */

.dial__v4-btn {
    left: calc(1388 * var(--u));
    top: calc(276 * var(--u));
    width: calc(266 * var(--u));
    height: calc(85.417 * var(--u));
    /* A decoration inside the picture, not a control: at full size its label
       sets nearly as large as the section's own headline. The narrow layout
       already knew this and scaled it; the wide one needed the same, gentler.
       Origin at the TOP RIGHT, because the button's right edge is flush with
       the groups panel below it and that line is what holds the picture
       together. */
    transform: scale(0.85);
    transform-origin: 100% 0;
}

.dial__v4-btn img {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
}

.dial__v4-btn span {
    position: absolute;
    margin: 0;
    font-weight: 700;
    line-height: normal;
    text-align: center;
    color: #fff;
    white-space: nowrap;
}

.dial__v4-btn .dial__v4-plus {
    left: calc(35.558 * var(--u));
    top: calc(18.221 * var(--u));
    width: calc(25 * var(--u));
    font-size: calc(36.445 * var(--u));
    line-height: calc(44 * var(--u));
}

.dial__v4-btn .dial__v4-label {
    left: calc(72.89 * var(--u));
    top: calc(22.777 * var(--u));
    width: calc(157 * var(--u));
    font-size: calc(29.611 * var(--u));
    line-height: calc(36 * var(--u));
}

.dial__v4-panel {
    left: calc(1280 * var(--u));
    top: calc(387 * var(--u));
    width: calc(374 * var(--u));
    height: calc(355.607 * var(--u));
}

/* every glyph and label at its own Figma coordinate */
.dial__v4-icon {
    width: calc(21.336 * var(--u));
    height: calc(21.336 * var(--u));
}

.dial__v4-new { left: calc(1601.88 * var(--u)); top: calc(411.53 * var(--u)); width: calc(18.426 * var(--u)); height: calc(18.426 * var(--u)); }
.dial__v4-folder { left: calc(1307.99 * var(--u)); top: calc(410.76 * var(--u)); width: calc(20.661 * var(--u)); height: calc(19.926 * var(--u)); }
.dial__v4-chev-down { left: calc(1434.09 * var(--u)); top: calc(423.02 * var(--u)); width: calc(14.249 * var(--u)); height: calc(7.971 * var(--u)); transform: rotate(180deg); }

.dial__v4-text {
    margin: 0;
    font-weight: 400;
    font-size: calc(21.459 * var(--u));
    line-height: calc(26 * var(--u));
    color: #212529;
    white-space: nowrap;
}

.dial__v4-head { left: calc(1336.713 * var(--u)); top: calc(410.761 * var(--u)); }
.dial__v4-row { left: calc(1365.836 * var(--u)); }

.dial__v4-icon--sales { left: calc(1332.116 * var(--u)); top: calc(453.677 * var(--u)); }
.dial__v4-row--sales { top: calc(454.446 * var(--u)); }
.dial__v4-icon--customers { left: calc(1332.116 * var(--u)); top: calc(501.194 * var(--u)); }
.dial__v4-row--customers { top: calc(501.962 * var(--u)); }
.dial__v4-icon--finance { left: calc(1334.334 * var(--u)); top: calc(548.71 * var(--u)); width: calc(17.025 * var(--u)); height: calc(21.337 * var(--u)); }
.dial__v4-row--finance { top: calc(549.479 * var(--u)); }
.dial__v4-icon--projects { left: calc(1332.116 * var(--u)); top: calc(596.226 * var(--u)); }
.dial__v4-row--projects { top: calc(596.995 * var(--u)); }
.dial__v4-icon--team { left: calc(1332.116 * var(--u)); top: calc(643.743 * var(--u)); }
.dial__v4-row--team { top: calc(644.511 * var(--u)); }
.dial__v4-icon--marketing { left: calc(1332.115 * var(--u)); top: calc(693.486 * var(--u)); width: calc(21.336 * var(--u)); height: calc(16.669 * var(--u)); }
.dial__v4-row--marketing { top: calc(692.028 * var(--u)); }

/* the row chevrons are the forward icon turned a quarter, at 55 % */
.dial__v4-chev {
    width: calc(14.249 * var(--u));
    height: calc(7.971 * var(--u));
    transform: rotate(90deg);
    opacity: 0.55;
}

.dial__v4-chev--sales { left: calc(1444.135 * var(--u)); top: calc(460.651 * var(--u)); }
.dial__v4-chev--customers { left: calc(1499.635 * var(--u)); top: calc(508.167 * var(--u)); }
.dial__v4-chev--finance { left: calc(1468.414 * var(--u)); top: calc(555.684 * var(--u)); }
.dial__v4-chev--projects { left: calc(1472.704 * var(--u)); top: calc(603.2 * var(--u)); }
.dial__v4-chev--team { left: calc(1500.647 * var(--u)); top: calc(650.716 * var(--u)); }
.dial__v4-chev--marketing { left: calc(1490.989 * var(--u)); top: calc(698.233 * var(--u)); }

/* Each team row is one node for the motion below: the wrapper spans the whole
   collage, so the icon, the label and the chevron keep resolving their Figma
   coordinates against the same box they always did. */
.dial__v4-grp {
    position: absolute;
    inset: 0;
    pointer-events: none;
}

.dial__v4-cursor {
    left: calc(1548 * var(--u));
    top: calc(463 * var(--u));
}

/* ---- reduced motion: no blur, no drift ------------------------------------ */

@media (prefers-reduced-motion: reduce) {
    .dial__num span,
    .dial__dot::before,
    .dial__dot::after {
        transition: none;
    }
}

/* ---- narrow screens: the five entries as a plain list --------------------- */

/* ---- phones: the same stepper, the circle moved to the top ---------------
   As on the reference at phone width: the section still captures a run of
   scroll with a sticky viewport-high stage, but the circle is bigger than the
   screen and sits above it, so only its bottom arc crosses the top and the
   numbers ride along that. The entry sits underneath; the product collages
   are far too wide for 390px and are left out. */

@media (max-width: 900px) {
    .dial {
        /* 20 degrees between numbers, so three of them stay on screen on a
           390px-wide arc instead of one. */
        --arc: 20deg;
        height: calc((1 + 3 * 1.9) * 100svh);
    }

    .dial__canvas {
        position: absolute;
        inset: 0;
        width: 100%;
        height: 100%;
        aspect-ratio: auto;
        --fig-w: 100cqw;
        --u: 1px;
        --fu: 1px;
    }

    /* 800 across, its centre 260px above the screen, so only the bottom of
       the arc crosses the top and everything else is off screen. */
    .dial__ring,
    .dial__wheel {
        left: 50%;
        top: -660px;
        width: 800px;
        height: 800px;
        margin-left: -400px;
    }

    /* The active number lands at the circle's lowest point, not its right. */
    .dial__wheel {
        transform: rotate(calc(90deg - var(--s, 0) * var(--arc)));
    }

    /* The wheel carries a 90 degree base rotation here, so every number is
       turned back by the same amount: the active one reads upright at the
       bottom of the arc, its neighbours lean with the curve, exactly as on
       the wide layout. */
    .dial__num span {
        font-size: 26px;
        transform: rotate(-90deg);
        transform-origin: 50% 50%;
    }

    .dial__num.is-active span {
        transform: translateX(14px) rotate(-90deg);
    }

    .dial__dot {
        left: 50%;
        top: 118px;
        margin-left: -22px;
    }

    /* Clear of the number, which hangs just under the arc at ~183. Stacked,
       the block is measured in px and takes the plain unit back. It starts as
       soon as the number is clear: every pixel above the collage is one the
       illustration does not get, and on a 664px screen it was living on 134. */
    .dial__entry {
        --u: var(--fu);
        left: 24px;
        top: 206px;
        width: calc(100% - 48px);
    }

    .dial__title {
        font-size: clamp(28px, 7.8vw, 36px);
        line-height: 1.04;
    }

    .dial__desc {
        width: auto;
        font-size: 15px;
        line-height: 22px;
    }

    /* The collage keeps its Figma geometry and is fitted into the box under
       the entry. dial.js measures each group once (its children's union box
       in Figma px) and, per viewport, the box that is left between the
       tallest entry and the bottom of the stage; --vk is the scale that fits
       the group into that box on both axes, --vtx/--vty the shift that puts
       its top-left on the 24px gutter under the entry. Nothing is cut off
       and the gap to the text is the same in every state. The drift stays
       unscaled, so it reads the same as on the wide layout. */
    .dial__visual {
        transform: translateY(var(--vdrift, 0px))
            translate(var(--vtx, 0px), var(--vty, 0px))
            scale(var(--vk, 1));
        transform-origin: 0 0;
    }

    /* No step in from the frame here: dial.js already scales the group to
       fit the screen, so nothing is cut and pulling it left would only take
       it off that centre. The card still travels to the bar's middle. */
    /* With the palette gone the wide layout lifts the bar 415 of ITS OWN
       units (--u, the frame's unit times 1.08286) to meet the caption card,
       so what is left reads as a compact pair. There is no card here, it is
       hidden, and no room to spare: the full lift left the bar alone in the
       middle of the screen with a field of nothing under it. The drop takes
       most of it back (449.4 is the whole lift, 415 x 1.08286 in --fu), and
       what is left moves the bar 174 up into the space the palette leaves,
       so it sits centred in the picture's own box rather than at either end.
       Set here rather than by overriding the animation, because that rule
       sits later in the file and a media query adds no specificity. */
    .dial__visual--3 { --v3-pull: 0; --v3-drop: 275.4; }

    /* The caption card above the palette carries two lines of type that the
       fit puts at four pixels here: unreadable, and it costs the palette a
       quarter of its size, because the fit scales the whole group to the
       union of its pieces. The entry's own copy already says what a skill
       is, so on a phone the picture shows the palette and the chat bar. */
    .dial__visual--3 .dial__v3-card {
        display: none;
    }

    /* 01 hangs its pointer 108 design px BELOW the chat bar, and the fit
       measures the union, so that tail pushed the bar up the screen and
       scaled the picture down for a 21px arrow. The phone shows the panel
       and the bar; the pointer is a desktop gesture anyway. */
    .dial__visual--1 .dial__v1-cursor {
        display: none;
    }

    /* The palette is the chat bar opened upwards, and at this scale the two
       met with no air at all: the bar read as the panel's last row rather
       than as the thing the panel came out of. The bar drops to 790 and the
       palette ends at 766, which leaves a clear 24 design px between them.
       The height for that comes out of the palette, not out of the group:
       the fit is bound by HEIGHT here, so a taller union would only shrink
       the whole picture again (it did: 215 wide became 126). The palette
       gives up its second row for it, and one row still reads as a list
       under a search field. */
    .dial__visual--3 .dial__v3-panel {
        height: auto;
        padding-bottom: calc(22 * var(--fu));
    }

    .dial__visual--3 .dial__v3-grid .dial__v3-cmd:nth-child(2) {
        display: none;
    }

    .dial__visual--3 .dial__v3-chat {
        top: calc(644 * var(--fu));
    }

    /* The typing caret is a figure of the frame, not a child of the bar, so
       moving the bar left it behind: it sat under the line it belongs to and
       hung past the bar's own edge. It travels the same 102. */
    .dial__visual--3 .dial__v3-caret {
        top: calc(662 * var(--u));
    }


    /* 04 is the tallest collage: six teams make the tree 467 deep. Hiding
       three of them let the rest sit larger, but the point of the picture is
       that every team has its own group, and a list of three does not make
       it. All six stay and the fit scales the group down to suit; the card
       is then narrower than the gutter, which is the better trade.

       The button is the one part the fit does not suit. Blown up with the
       rest, "New group" sets at 30px, the same size as the section's own
       headline, and a decoration in the picture shouts as loud as the title.
       It keeps its own two thirds and lines up with the card's left edge;
       its top is moved down so the gap to the card stays the 25 it has on
       the wide layout. */
    .dial__v4-btn {
        left: calc(1280 * var(--u));
        top: calc(305 * var(--u));
        transform: scale(0.66);
        transform-origin: 0 0;
    }
}

/* ---- arrival -------------------------------------------------------------
   dial.js sets `is-revealed` the first time the section is on screen. The
   ring draws itself, the numbers arrive one after the other and the dot
   lands last. The entry and the collage are left alone: their opacity is
   owned by the scroll mapping. */

.dial__canvas {
    opacity: 0;
    transform: translateY(calc(18 * var(--u)));
    transition: opacity 700ms ease, transform 900ms cubic-bezier(0.22, 1, 0.36, 1);
}

.dial.is-revealed .dial__canvas {
    opacity: 1;
    transform: none;
}

.dial__ring {
    opacity: 0;
    transform: scale(0.96);
    transform-origin: 50% 50%;
    transition: opacity 800ms ease 120ms, transform 1100ms cubic-bezier(0.22, 1, 0.36, 1) 120ms;
}

.dial.is-revealed .dial__ring {
    opacity: 1;
    transform: none;
}

.dial__num span {
    opacity: 0;
    transition: opacity 500ms ease, color 0.35s ease,
        transform 0.45s cubic-bezier(0.22, 1, 0.36, 1);
}

.dial.is-revealed .dial__num span { opacity: 1; }
.dial.is-revealed .dial__num:nth-child(1) span { transition-delay: 280ms; }
.dial.is-revealed .dial__num:nth-child(2) span { transition-delay: 380ms; }
.dial.is-revealed .dial__num:nth-child(3) span { transition-delay: 480ms; }
.dial.is-revealed .dial__num:nth-child(4) span { transition-delay: 580ms; }

.dial__dot {
    opacity: 0;
    transform: scale(0.6);
    transform-origin: 50% 50%;
    transition: opacity 400ms ease 620ms,
        transform 700ms cubic-bezier(0.34, 1.56, 0.64, 1) 620ms;
}

.dial.is-revealed .dial__dot {
    opacity: 1;
    transform: none;
}

@media (prefers-reduced-motion: reduce) {
    .dial__canvas,
    .dial__ring,
    .dial__num span,
    .dial__dot {
        transition-duration: 200ms;
        transition-delay: 0ms;
        transform: none;
    }
}

/* On phones the wheel carries its own base rotation, so the reveal must not
   overwrite its transform. */
@media (max-width: 900px) {
    .dial.is-revealed .dial__ring {
        transform: none;
    }
}

/* ===========================================================================
   Collages in motion
   ---------------------------------------------------------------------------
   Each collage is a still of the product; on its own it only shows the end of
   an interaction. These rules replay the interaction that produced it, once,
   when the step has fully arrived, and then leave the collage exactly as it
   was drawn. dial.js adds `is-live` at full presence and takes it off when the
   step leaves, which is what rearms the loop for the next visit.

   Two rules keep this out of dial.js's way. Everything here animates a CHILD:
   the collage box itself carries the scroll's opacity, blur and --vdrift, and
   is not ours to touch. And every animation is declared only under `.is-live`
   and ends on the child's authored value, so a collage that never goes live,
   or loses the class mid-flight, simply shows the finished frame. Nothing is
   hidden by a base rule, so nothing can go missing if the motion never runs.

   One timing language for all four: the hero's arrival (700ms, the same
   curve, a 16u lift) with a 90ms stagger, and one 480ms out-and-back for
   anything that answers a click. Only transform and opacity move. The blink
   and the typewriter's steps are the two allowed non-eased exceptions.

   Paste at the END of this file: the reduced-motion block at the bottom wins
   on source order, not specificity.
   =========================================================================== */

.dial {
    --dv-in: cubic-bezier(0.22, 1, 0.36, 1);   /* arrivals */
    --dv-out: cubic-bezier(0.32, 0.72, 0, 1);  /* state changes */
    --dv-dur: 700ms;                           /* one entrance, hero's length */
    --dv-step: 90ms;                           /* one stagger */
    --dv-beat: 480ms;                          /* one answer to a click */
}

/* -- nothing is painted before its turn ------------------------------------
   A collage fades in as a whole (dial.js writes its opacity) and only arms
   `is-live` once it is fully there. Everything with an entrance animation was
   therefore shown finished during that fade, then snapped back to zero when
   the animation armed: the content appeared, vanished and came back. These
   parts start at the value their entrance animation begins on, so the fade-in
   carries only the frame and the choreography owns the reveal. The class is
   held until the collage has left again (dial.js), so the way out keeps what
   was played. */

.dial__v1-ask,
.dial__v1-answer strong,
.dial__v1-answer li,
.dial__v1-caret,
.dial__v1-cursor,
.dial__v1-chat .dial__chat-ph,
.dial__v2-menu,
.dial__v2-item-icon,
.dial__v2-name,
.dial__v2-hint,
.dial__v2-cursor,
.dial__v3-card,
.dial__v3-panel,
.dial__v3-cmd,
.dial__v3-caret,
.dial__v3-cursor,
.dial__v3-chat .dial__chat-ph,
.dial__v4-grp,
.dial__v4-cursor {
    opacity: 0;
}

/* the head chevron is turned down in the design and turns there on play, so
   its resting state before the turn is the collapsed one */
.dial__v4-chev-down {
    transform: rotate(90deg);
}

/* -- the shared moves ----------------------------------------------------- */

@keyframes dv-rise {
    from { opacity: 0; transform: translateY(calc(16 * var(--u))); }
    to { opacity: 1; transform: none; }
}

/* a disclosure opens downward, so its rows come from under the head */
@keyframes dv-unfold {
    from { opacity: 0; transform: translateY(calc(-10 * var(--u))); }
    to { opacity: 1; transform: none; }
}

@keyframes dv-fade {
    from { opacity: 0; }
    to { opacity: 1; }
}

/* a pointer drifts in from where it came, as in the hero */
@keyframes dv-cursor-in {
    from { opacity: 0; transform: translate(calc(-22 * var(--u)), calc(26 * var(--u))); }
    to { opacity: 1; transform: none; }
}

/* the row under the pointer answers the press and comes back to rest */
@keyframes dv-press {
    0% { transform: none; animation-timing-function: cubic-bezier(0.32, 0.72, 0, 1); }
    38% { transform: translateY(calc(3 * var(--u))); animation-timing-function: cubic-bezier(0.22, 1, 0.36, 1); }
    100% { transform: none; }
}

/* the match is picked out of the list, then the list settles again */
@keyframes dv-lift {
    0% { transform: none; animation-timing-function: cubic-bezier(0.32, 0.72, 0, 1); }
    38% { transform: translateY(calc(-5 * var(--u))) scale(1.02); animation-timing-function: cubic-bezier(0.22, 1, 0.36, 1); }
    100% { transform: none; }
}

@keyframes dv-dim {
    0% { opacity: 1; animation-timing-function: cubic-bezier(0.32, 0.72, 0, 1); }
    38% { opacity: 0.4; animation-timing-function: cubic-bezier(0.22, 1, 0.36, 1); }
    100% { opacity: 1; }
}

@keyframes dv-pop {
    0% { transform: none; animation-timing-function: cubic-bezier(0.32, 0.72, 0, 1); }
    38% { transform: scale(1.14); animation-timing-function: cubic-bezier(0.22, 1, 0.36, 1); }
    100% { transform: none; }
}

/* -- 01: asked in plain words, answered, and the follow-up typed ----------
   The reading order is the product's own: the person's question, then the
   headline Aimee writes, then the agenda one line at a time, and only then
   the follow-up going into the same bar. The typing is a white patch the
   width of the placeholder shrinking away under the caret, because a real
   text reveal would have to animate width, which is layout. */

/* The pointer drifts in with the question, waits under the bar while the
   follow-up is typed (1260 + 880 = 2140), then travels to the send button
   and presses it. Rest is at 1145/867 with the tip at 6%/3% of the 63 box,
   the send button's centre at 1789/772.5, so the tip lands at 1786/770 after
   a 637/-99 move. dv-v1-send is `forwards`, not `both`, so its 0% does not
   pin the pointer at rest during the drift-in it shares the element with. */
.dial__visual--1.is-live .dial__v1-cursor {
    transform-origin: 6% 3%;
    animation:
        dv-cursor-in var(--dv-dur) var(--dv-in) both,
        dv-v1-send 1000ms linear 2350ms forwards;
}

/* the button answers the press at the moment the pointer is down (2350 +
   70% of 1000 = 3050) */
.dial__visual--1.is-live .dial__v1-chat .dial__row-right .dial__row-btn:last-child {
    animation: dv-pop var(--dv-beat) var(--dv-out) 3050ms forwards;
}

@keyframes dv-v1-send {
    0% { transform: none; animation-timing-function: cubic-bezier(0.22, 1, 0.36, 1); }
    70% { transform: translate(calc(637 * var(--u)), calc(-99 * var(--u))); animation-timing-function: cubic-bezier(0.32, 0.72, 0, 1); }
    82% { transform: translate(calc(637 * var(--u)), calc(-99 * var(--u))) scale(0.92); animation-timing-function: cubic-bezier(0.22, 1, 0.36, 1); }
    100% { transform: translate(calc(637 * var(--u)), calc(-99 * var(--u))); }
}

.dial__visual--1.is-live .dial__v1-answer strong { --in-delay: calc(3 * var(--dv-step)); }
.dial__visual--1.is-live .dial__v1-answer li:nth-child(1) { --in-delay: calc(4 * var(--dv-step)); }
.dial__visual--1.is-live .dial__v1-answer li:nth-child(2) { --in-delay: calc(5 * var(--dv-step)); }
.dial__visual--1.is-live .dial__v1-answer li:nth-child(3) { --in-delay: calc(6 * var(--dv-step)); }

/* -- after the send click (pointer down at 3050, released at 3350) the
   thread scrolls, exactly as the product does: the bar empties, the sent
   bubble comes into view from below, the confirmation follows, and the first
   exchange slides up under the window's top edge instead of disappearing.
   Two steps, measured: 114 brings the bubble's bottom onto the answer's old
   baseline, 300 does the same for the confirmation. */
.dial__visual--1.is-live .dial__v1-ask {
    animation: dv-rise var(--dv-dur) var(--dv-in) both;
}

.dial__visual--1.is-live .dial__v1-thread {
    animation: dv-v1-scroll 1500ms 3400ms forwards;
}

@keyframes dv-v1-scroll {
    0% { transform: none; animation-timing-function: cubic-bezier(0.32, 0.72, 0, 1); }
    33% { transform: translateY(calc(-114 * var(--u))); animation-timing-function: linear; }
    60% { transform: translateY(calc(-114 * var(--u))); animation-timing-function: cubic-bezier(0.32, 0.72, 0, 1); }
    100% { transform: translateY(calc(-300 * var(--u))); }
}

/* The stagger rides `--in-delay`, NOT `animation-delay`: a separate
   animation-delay declaration applies to every animation in the shorthand's
   list, so it would pull the leave animation forward too and the lines would
   vanish before they were read. */
.dial__visual--1.is-live .dial__v1-answer strong,
.dial__visual--1.is-live .dial__v1-answer li {
    animation: dv-rise var(--dv-dur) var(--dv-in) var(--in-delay, 0ms) both;
}

/* the typed line and its caret go with the message */
.dial__visual--1.is-live .dial__v1-chat .dial__chat-ph {
    animation:
        dv-fade 1ms linear both,
        dv-v1-clear 260ms ease 3400ms forwards;
}

.dial__visual--1.is-live .dial__v1-ask2 {
    animation: dv-fade 260ms ease 3400ms forwards;
}

.dial__visual--1.is-live .dial__v1-reply strong {
    animation: dv-rise var(--dv-dur) var(--dv-in) 4250ms forwards;
}

.dial__visual--1.is-live .dial__v1-reply p {
    animation: dv-rise var(--dv-dur) var(--dv-in) 4340ms forwards;
}

@keyframes dv-v1-clear {
    to { opacity: 0; }
}

/* The patch spans the bar's text origin (1200 + 22.41 padding) to the caret
   at 1493.5, which is 271.09, and retreats toward its right edge one step per
   character of "Add it to the calendar". The caret rides the same 22 steps,
   so the two cannot come apart. `position: relative` only anchors the patch;
   it moves nothing. */
.dial__visual--1.is-live .dial__v1-chat .dial__chat-ph {
    position: relative;
}

.dial__visual--1.is-live .dial__v1-chat .dial__chat-ph::after {
    content: "";
    position: absolute;
    left: 0;
    top: calc(-8 * var(--u));
    width: calc(var(--type-w, 271.09) * var(--u));
    height: calc(48 * var(--u));
    background: #fff;
    transform-origin: 100% 50%;
    /* one step per character of the line (22 in "Add it to the calendar");
       dial.js counts the copy, so a translation steps its own letters */
    animation: dv-type 880ms steps(var(--type-n, 22), end) 1260ms both;
}

.dial__visual--1.is-live .dial__v1-caret {
    animation:
        dv-fade 200ms ease 1260ms both,
        dv-type-caret 880ms steps(var(--type-n, 22), end) 1260ms both,
        dv-blink 1060ms step-end 2200ms infinite,
        dv-v1-clear 260ms ease 3400ms forwards;
}

/* dial.js replaces dv-type and dv-type-caret (and 03's dv-v3-type-name and
   dv-v3-caret-name) with one keyframe per character, measured from the
   glyphs; the equal steps here are the fallback without script. */
@keyframes dv-type {
    from { transform: scaleX(1); }
    to { transform: scaleX(0); }
}

@keyframes dv-type-caret {
    from { transform: translateX(calc(-1 * var(--type-w, 271.09) * var(--u))); }
    to { transform: none; }
}

@keyframes dv-blink {
    0% { opacity: 1; }
    50% { opacity: 0; }
    100% { opacity: 1; }
}

/* -- 02: nothing is written without a yes ---------------------------------
   The still shows the permission menu already open with the pointer on
   "Ask first", which is the end of a choice nobody watched being made. So the
   menu grows out of the pill, the two modes arrive as rows, and the pointer
   comes in from outside, hesitates over "Bypass" and presses the safe one
   instead. The hesitation is the whole point of the beat. */

.dial__visual--2.is-live .dial__v2-menu {
    transform-origin: 11% 6%;
    animation:
        dv-open var(--dv-dur) var(--dv-in) both,
        dv-v2-close 300ms var(--dv-out) 1720ms forwards;
}

/* a row moves as a row: its icon, name and hint share one delay */
.dial__visual--2.is-live .dial__v2-icon-2,
.dial__visual--2.is-live .dial__v2-name--2,
.dial__visual--2.is-live .dial__v2-hint--2 {
    animation:
        dv-rise var(--dv-dur) var(--dv-in) calc(3 * var(--dv-step)) both,
        dv-v2-close 300ms var(--dv-out) 1720ms forwards;
}

/* the chosen row arrives first and then answers the press. dv-press is
   `forwards`, not `both`, or its 0% would apply from time 0 and flatten the
   arrival it shares the element with. */
.dial__visual--2.is-live .dial__v2-icon-1,
.dial__visual--2.is-live .dial__v2-name--1,
.dial__visual--2.is-live .dial__v2-hint--1 {
    animation:
        dv-rise var(--dv-dur) var(--dv-in) calc(2 * var(--dv-step)) both,
        dv-press var(--dv-beat) var(--dv-out) 1220ms forwards,
        dv-v2-close 300ms var(--dv-out) 1720ms forwards;
}

.dial__visual--2.is-live .dial__v2-cursor {
    transform-origin: 6% 3%;
    animation:
        dv-v2-pick 1260ms var(--dv-in) calc(2 * var(--dv-step)) both,
        dv-v2-close 300ms var(--dv-out) 1720ms forwards;
}

/* The press lands at 1220 and runs 480. The pill then takes the chosen mode,
   the menu closes behind it and the caret turns back down, so the frame that
   rests carries the label exactly once. */
.dial__visual--2.is-live .dial__v2-label--from,
.dial__visual--2.is-live .dial__v2-bolt {
    animation: dv-v2-swap-out 200ms ease 1400ms forwards;
}

.dial__visual--2.is-live .dial__v2-label--to,
.dial__visual--2.is-live .dial__v2-lock {
    animation: dv-fade 220ms ease 1440ms forwards;
}

.dial__visual--2.is-live .dial__v2-caret {
    animation: dv-v2-caret 320ms var(--dv-out) 1720ms forwards;
}

@keyframes dv-v2-swap-out {
    to { opacity: 0; }
}

@keyframes dv-v2-close {
    to { opacity: 0; transform: translateY(calc(-10 * var(--u))) scale(0.97); }
}

@keyframes dv-v2-caret {
    to { transform: rotate(0deg); }
}

@keyframes dv-open {
    from { opacity: 0; transform: translateY(calc(-12 * var(--u))) scale(0.96); }
    to { opacity: 1; transform: none; }
}

/* in from the menu's lower right, a look at "Bypass" (one row is 89.44
   apart), then up to "Ask first" and a press. It ends on its Figma spot, on
   the row it chose. */
@keyframes dv-v2-pick {
    0% { opacity: 0; transform: translate(calc(64 * var(--u)), calc(140 * var(--u))); }
    32% { opacity: 1; transform: translate(calc(6 * var(--u)), calc(89 * var(--u))); }
    48% {
        opacity: 1;
        transform: translate(calc(6 * var(--u)), calc(89 * var(--u)));
        animation-timing-function: cubic-bezier(0.32, 0.72, 0, 1);
    }
    72% {
        opacity: 1;
        transform: none;
        animation-timing-function: cubic-bezier(0.32, 0.72, 0, 1);
    }
    82% {
        opacity: 1;
        transform: scale(0.92);
        animation-timing-function: cubic-bezier(0.22, 1, 0.36, 1);
    }
    100% { opacity: 1; transform: none; }
}

/* -- 03: the slash opens the palette, the name picks the skill -----------
   The bar starts empty. The pointer drifts in, a "/" is typed, and on that
   slash the Commands palette grows out of the bar from below while the Skills
   card lands beside it and the team's two skills render into the list. Then
   "Chase" is typed, the match is lifted out and the rest steps back. The
   highlight is not held, so the finished frame stays the frame that was
   designed.

   Typing is the 01 recipe: a white patch over the typed line, retreating
   toward its right edge in character steps. The slash goes first, on its
   own, then the name one character per step. The patch's width, the
   slash's share of it and the step count come from dial.js (--type-w,
   --type-lead, --type-rest), measured from the copy, so a translation
   types as cleanly as "/Chase" (123.23 wide, the slash 11.73, five
   letters, as authored). The patch and the caret ride the same steps, so
   they cannot come apart. Everything in --fu: the bar carries a scaled --u
   of its own. */

.dial__visual--3.is-live .dial__v3-cursor {
    animation:
        dv-cursor-in var(--dv-dur) var(--dv-in) 1500ms both,
        dv-cursor-press 260ms var(--dv-out) 2200ms forwards,
        dv-fade-out 220ms var(--dv-in) 2440ms forwards;
}

/* the hand dips into the click the row answers with dv-lift */
@keyframes dv-cursor-press {
    0% { transform: none; animation-timing-function: cubic-bezier(0.32, 0.72, 0, 1); }
    45% { transform: translate(calc(1 * var(--u)), calc(3 * var(--u))) scale(0.9); }
    100% { transform: none; }
}

.dial__visual--3.is-live .dial__v3-chat {
    animation: dv-v3-bar-rise 520ms var(--dv-in) 2480ms forwards;
}

.dial__visual--3.is-live .dial__v3-chat .dial__chat-ph {
    position: relative;
    animation:
        dv-fade 1ms linear both,
        dv-fade-out 180ms var(--dv-in) 2440ms forwards;
}

/* the chip lands where the typing was, a beat after the click */
.dial__visual--3.is-live .dial__v3-chip {
    animation: dv-v3-arm 340ms cubic-bezier(0.34, 1.4, 0.64, 1) 2560ms both;
}

@keyframes dv-v3-arm {
    from { opacity: 0; transform: translateY(calc(6 * var(--fu))) scale(0.92); }
    to { opacity: 1; transform: none; }
}

.dial__visual--3.is-live .dial__v3-chat .dial__chat-ph::after {
    content: "";
    position: absolute;
    left: 0;
    top: calc(-6 * var(--fu));
    /* as wide as the typed line, measured (123.23 is "/Chase" as authored):
       a fixed width left the end of a longer line uncovered */
    width: calc(var(--type-w, 123.23) * var(--fu));
    height: calc(54 * var(--fu));
    background: #fff;
    transform-origin: 100% 50%;
    animation:
        dv-v3-type-slash 120ms steps(1, end) 300ms both,
        dv-v3-type-name 520ms steps(var(--type-rest, 5), end) 1500ms forwards;
}

.dial__visual--3.is-live .dial__v3-caret {
    animation:
        dv-fade 200ms ease 300ms both,
        dv-v3-caret-slash 120ms steps(1, end) 300ms both,
        dv-v3-caret-name 520ms steps(var(--type-rest, 5), end) 1500ms forwards,
        dv-blink 1060ms step-end 2100ms infinite,
        dv-fade-out 180ms var(--dv-in) 2440ms forwards;
}

/* on the slash (typed at 420) the palette comes up out of the bar and the
   card lands with it; the skills render into the list one after the other */
.dial__visual--3.is-live .dial__v3-panel {
    transform-origin: 50% 100%;
    animation:
        dv-v3-open var(--dv-dur) var(--dv-in) 560ms both,
        dv-v3-shut 420ms var(--dv-in) 2480ms forwards;
}

/* the pick taken: the palette drops back into the bar it came out of */
@keyframes dv-v3-shut {
    to { opacity: 0; transform: translateY(calc(64 * var(--u))) scale(0.96); }
}

@keyframes dv-fade-out { to { opacity: 0; } }

/* The palette took up the middle of the picture; with it gone, the bar would
   sit alone at the bottom under a field of nothing. It comes up to meet the
   card instead, so what is left is a compact pair near the top: the skill,
   and the bar it is now armed on. */
@keyframes dv-v3-bar-rise {
    /* 415, not the 448 that would put the bar right under the card: at phone
       scale a 10px gap let the two white bodies read as one shape. The x is
       in --fu, the frame's own unit, not the bar's scaled --u, so it matches
       the card's step to the same centre. */
    to {
        transform: translate(calc(-1 * var(--v3-pull) * var(--fu)),
                             calc(-415 * var(--u) + var(--v3-drop) * var(--fu)));
    }
}

/* The card sat on the palette's left edge, which left it hanging off to one
   side of the much wider bar once the palette dropped. It steps right onto
   the bar's centre on the same beat the palette falls. */
.dial__visual--3.is-live .dial__v3-card {
    animation:
        dv-rise var(--dv-dur) var(--dv-in) 560ms both,
        dv-v3-card-centre 520ms var(--dv-in) 2480ms forwards;
}

@keyframes dv-v3-card-centre {
    from { transform: none; }
    to {
        transform: translate(calc((var(--v3-card-x) - var(--v3-pull)) * var(--fu)),
                             calc(var(--v3-drop) * var(--fu)));
    }
}

.dial__visual--3.is-live .dial__v3-cmd:first-child {
    animation:
        dv-rise var(--dv-dur) var(--dv-in) 740ms both,
        dv-lift var(--dv-beat) var(--dv-out) 2200ms forwards,
        dv-fade-out 260ms var(--dv-in) 2480ms forwards;
}

.dial__visual--3.is-live .dial__v3-cmd + .dial__v3-cmd {
    animation:
        dv-rise var(--dv-dur) var(--dv-in) 830ms both,
        dv-dim var(--dv-beat) var(--dv-out) 2200ms forwards,
        dv-fade-out 260ms var(--dv-in) 2480ms forwards;
}

.dial__visual--3.is-live .dial__v3-cmd:first-child .dial__v3-cmd-icon {
    animation: dv-pop var(--dv-beat) var(--dv-out) 2260ms forwards;
}

/* The slash is the line's first character, typed on its own: the cover
   gives up its share of the width (11.73 of "/Chase"'s 123.23 as authored,
   measured by dial.js) and the caret moves the same distance. */
@keyframes dv-v3-type-slash {
    from { transform: scaleX(1); }
    to { transform: scaleX(calc(1 - var(--type-lead, 11.73) / var(--type-w, 123.23))); }
}

@keyframes dv-v3-type-name {
    from { transform: scaleX(calc(1 - var(--type-lead, 11.73) / var(--type-w, 123.23))); }
    to { transform: scaleX(0); }
}

@keyframes dv-v3-caret-slash {
    from { transform: translateX(calc(-1 * var(--type-w, 123.23) * var(--fu))); }
    to { transform: translateX(calc((var(--type-lead, 11.73) - var(--type-w, 123.23)) * var(--fu))); }
}

@keyframes dv-v3-caret-name {
    /* one slash in from the start: the caret has typed "/" and waits */
    from { transform: translateX(calc((var(--type-lead, 11.73) - var(--type-w, 123.23)) * var(--fu))); }
    to { transform: none; }
}

/* the palette pops up from the bar: more travel than dv-grow, from below */
@keyframes dv-v3-open {
    from { opacity: 0; transform: translateY(calc(64 * var(--u))) scale(0.96); }
    to { opacity: 1; transform: none; }
}

/* -- 04: each team keeps its own context ----------------------------------
   The still is an open tree, which reads as a list until you see it open. The
   pointer presses the head, the head chevron turns from collapsed to
   expanded, and the six teams come out from under it one after another. The
   pointer then drops onto Sales, where the design parks it.

   The six rows are wrapped per team in a full-canvas layer (see index.html):
   that keeps every glyph on its own Figma coordinate while one transform and
   one opacity carry icon, label and chevron together, and it holds the whole
   collage to eight animated nodes instead of eighteen. */

.dial__v4-grp {
    position: absolute;
    inset: 0;
}

.dial__visual--4.is-live .dial__v4-grp {
    animation: dv-unfold var(--dv-dur) var(--dv-in) both;
}

.dial__visual--4.is-live .dial__v4-grp--sales { animation-delay: calc(7 * var(--dv-step)); }
.dial__visual--4.is-live .dial__v4-grp--customers { animation-delay: calc(8 * var(--dv-step)); }
.dial__visual--4.is-live .dial__v4-grp--finance { animation-delay: calc(9 * var(--dv-step)); }
.dial__visual--4.is-live .dial__v4-grp--projects { animation-delay: calc(10 * var(--dv-step)); }
.dial__visual--4.is-live .dial__v4-grp--team { animation-delay: calc(11 * var(--dv-step)); }
.dial__visual--4.is-live .dial__v4-grp--marketing { animation-delay: calc(12 * var(--dv-step)); }

/* the head chevron is the row chevrons' glyph: at 90deg it points right, like
   theirs, at its authored 180deg it points down */
.dial__visual--4.is-live .dial__v4-chev-down {
    animation: dv-turn var(--dv-beat) var(--dv-out) 570ms both;
}

.dial__visual--4.is-live .dial__v4-cursor {
    transform-origin: 6% 3%;
    animation: dv-v4-open 1700ms var(--dv-in) both;
}

@keyframes dv-turn {
    from { transform: rotate(90deg); }
    to { transform: rotate(180deg); }
}

/* up to the head chevron (109.4 left, 36.9 up of where the design parks the
   pointer), a press, a wait while the teams unfold, then down onto Sales */
@keyframes dv-v4-open {
    0% { opacity: 0; transform: translate(calc(-90 * var(--u)), calc(-18 * var(--u))); }
    26% {
        opacity: 1;
        transform: translate(calc(-109 * var(--u)), calc(-37 * var(--u)));
        animation-timing-function: cubic-bezier(0.32, 0.72, 0, 1);
    }
    33% {
        opacity: 1;
        transform: translate(calc(-109 * var(--u)), calc(-37 * var(--u))) scale(0.92);
        animation-timing-function: cubic-bezier(0.22, 1, 0.36, 1);
    }
    40% { opacity: 1; transform: translate(calc(-109 * var(--u)), calc(-37 * var(--u))); }
    66% {
        opacity: 1;
        transform: translate(calc(-109 * var(--u)), calc(-37 * var(--u)));
        animation-timing-function: cubic-bezier(0.32, 0.72, 0, 1);
    }
    100% { opacity: 1; transform: none; }
}

/* ---- reduced motion: the finished frame, no motion ----------------------
   Every animation above is declared only under `.is-live` and every one of
   them ends on the value the collage was authored with, so switching them all
   off leaves each collage exactly as it is drawn: the agenda written out and
   the follow-up in the bar, the menu open on "Ask first", the palette listing
   both skills, the tree open on six teams. Nothing else has to be restored.
   This block must stay last in the file; it wins on source order. */

@media (prefers-reduced-motion: reduce) {
    .dial__visual--1.is-live .dial__v1-ask,
    .dial__visual--1.is-live .dial__v1-cursor,
    .dial__visual--1.is-live .dial__v1-answer strong,
    .dial__visual--1.is-live .dial__v1-answer li,
    .dial__visual--1.is-live .dial__v1-caret,
    .dial__visual--1.is-live .dial__v1-thread,
    .dial__visual--1.is-live .dial__v1-chat .dial__chat-ph,
    .dial__visual--1.is-live .dial__v1-ask2,
    .dial__visual--1.is-live .dial__v1-reply strong,
    .dial__visual--1.is-live .dial__v1-reply p,
    .dial__visual--1.is-live .dial__v1-chat .dial__row-right .dial__row-btn:last-child,
    .dial__visual--2.is-live .dial__v2-menu,
    .dial__visual--2.is-live .dial__v2-icon-1,
    .dial__visual--2.is-live .dial__v2-name--1,
    .dial__visual--2.is-live .dial__v2-hint--1,
    .dial__visual--2.is-live .dial__v2-icon-2,
    .dial__visual--2.is-live .dial__v2-name--2,
    .dial__visual--2.is-live .dial__v2-hint--2,
    .dial__visual--2.is-live .dial__v2-cursor,
    .dial__visual--2.is-live .dial__v2-label--from,
    .dial__visual--2.is-live .dial__v2-label--to,
    .dial__visual--2.is-live .dial__v2-bolt,
    .dial__visual--2.is-live .dial__v2-lock,
    .dial__visual--2.is-live .dial__v2-caret,
    .dial__visual--3.is-live .dial__v3-card,
    /* the bar's rise and slide were the one pair this block missed: with them
       still running the bar climbed out from under an open palette */
    .dial__visual--3.is-live .dial__v3-chat,
    .dial__visual--3.is-live .dial__v3-chat .dial__chat-ph,
    .dial__visual--3.is-live .dial__v3-chip,
    .dial__visual--3.is-live .dial__v3-caret,
    .dial__visual--3.is-live .dial__v3-cursor,
    .dial__visual--3.is-live .dial__v3-panel,
    .dial__visual--3.is-live .dial__v3-cmd:first-child,
    .dial__visual--3.is-live .dial__v3-cmd + .dial__v3-cmd,
    .dial__visual--3.is-live .dial__v3-cmd:first-child .dial__v3-cmd-icon,
    .dial__visual--4.is-live .dial__v4-grp,
    .dial__visual--4.is-live .dial__v4-chev-down,
    .dial__visual--4.is-live .dial__v4-cursor {
        animation: none;
    }

    .dial__visual--1.is-live .dial__v1-chat .dial__chat-ph::after,
    .dial__visual--3.is-live .dial__v3-chat .dial__chat-ph::after {
        content: none;
    }
}
@media (prefers-reduced-motion: reduce) {
    /* Nothing plays, so the collage shows the outcome: the mode taken, the
       menu already closed. */
    .dial__visual--2 .dial__v2-label--from,
    .dial__visual--2 .dial__v2-bolt,
    .dial__visual--2 .dial__v2-menu,
    .dial__visual--2 .dial__v2-item-icon,
    .dial__visual--2 .dial__v2-name,
    .dial__visual--2 .dial__v2-hint,
    .dial__visual--2 .dial__v2-cursor {
        opacity: 0;
    }

    .dial__visual--2 .dial__v2-label--to,
    .dial__visual--2 .dial__v2-lock {
        opacity: 1;
    }

    .dial__visual--2 .dial__v2-caret {
        transform: rotate(0deg);
    }
}

/* ---- German copy ------------------------------------------------------------
   The mockups show the module's own German terms, which run longer than the
   English ones in boxes sized for English. Only the boxes grow; the type and
   every Figma edge that holds the picture together stay where they are. */

/* The titles: "Gruppen & Gedächtnis" sets 1 px wider than the column it
   shares with "Groups & Memory" and broke onto a second line for that pixel.
   Every English title is one line, so the German ones stay on one too. */
html[lang="de"] .dial__title { white-space: nowrap; }

/* "Erst fragen" in the chat bars of 01 and 03: as in the hero's bar. */
html[lang="de"] .dial__row-pill--ask { width: calc(196.079 * var(--u)); }
html[lang="de"] .dial__row-pill--ask .dial__row-chev { left: calc(162.464 * var(--u)); }

/* 02: "Übergehen" and "Erst fragen" need 186 of the label's 137 (measured:
   185.6 and 183.8; the English box is its longer label's width too). The pill
   grows 49 to the right, where the menu below still reaches further, and the
   caret keeps its 24 of air after the label. */
html[lang="de"] .dial__v2-pill { width: calc(334 * var(--u)); }
html[lang="de"] .dial__v2-pill span { width: calc(186 * var(--u)); }
html[lang="de"] .dial__v2-pill .dial__v2-caret { left: calc(292 * var(--u)); }

/* 03: this bar has no room for "Erst fragen" at all. In English its two
   groups are 5 design px apart; the German pill is 26 wider, which would push
   them 21 into each other. The bar grows those 26 to the LEFT, and so does the
   palette, which is the same bar opened upwards, so the right edge keeps its
   24 to the frame after the pull; the card steps 13 further so the pair stays
   centred on one axis. What starts at the bar's left edge moves with it: the
   typing caret, the pointer on the first skill, and the command cards, which
   fill the palette's column. */
html[lang="de"] .dial__visual--3 { --v3-card-x: 139; }
html[lang="de"] .dial__v3-panel { left: calc(1233 * var(--u)); width: calc(674 * var(--u)); }
html[lang="de"] .dial__v3-cmd { width: calc(630.065 * var(--u)); }
html[lang="de"] .dial__v3-chat { left: calc(1233 * var(--fu)); width: calc(674 * var(--fu)); }
html[lang="de"] .dial__v3-chat .dial__row { width: calc(626.374 * var(--fu)); }
html[lang="de"] .dial__v3-caret { left: calc((1257.27 + var(--type-w, 123.23)) * var(--u)); }
html[lang="de"] .dial__v3-cursor { left: calc(1398 * var(--u)); }

/* 04: "Neue Gruppe" needs 191 of the label's 157. The button grows 34 to the
   LEFT, so its right edge stays flush with the groups panel below, and its
   ground is drawn here instead of stretching the SVG, whose corners would
   turn oval. */
html[lang="de"] .dial__v4-btn {
    left: calc(1354 * var(--u));
    width: calc(300 * var(--u));
    border-radius: calc(18.2223 * var(--u));
    background: #1AD3BB;
}
html[lang="de"] .dial__v4-btn img { display: none; }
html[lang="de"] .dial__v4-btn .dial__v4-label { width: calc(191 * var(--u)); }

/* 04: the groups tree. In English every chevron sits about 23.5 design px
   after its label (22.6 to 24.5, measured); the German labels are longer or
   shorter, so their chevrons sit 23.5 after the German words. */
html[lang="de"] .dial__v4-chev-down { left: calc(1448.4 * var(--u)); }
html[lang="de"] .dial__v4-chev--sales { left: calc(1468.4 * var(--u)); }
html[lang="de"] .dial__v4-chev--customers { left: calc(1466.7 * var(--u)); }
html[lang="de"] .dial__v4-chev--finance { left: calc(1481.3 * var(--u)); }
html[lang="de"] .dial__v4-chev--projects { left: calc(1472.4 * var(--u)); }
html[lang="de"] .dial__v4-chev--team { left: calc(1559.2 * var(--u)); }

/* The narrow layout lines the button up with the card's LEFT edge instead
   (scaled from its top left), so there it keeps that edge and grows right. */
@media (max-width: 900px) {
    html[lang="de"] .dial__v4-btn { left: calc(1280 * var(--u)); }
}
