/* Hero prototypes, 3 Oct 2026 (?v=1-3). Layout only; the videos and timing are the live hero's. */
.hero .hero__lead { display: none; }
.hv { display: none; }
.hero[data-hv="1"] .hv--1, .hero[data-hv="2"] .hv--2, .hero[data-hv="3"] .hv--3 { display: block; }
.hs-no { display: none; }

/* Left-aligned, sitting in the lower part of the screen, on the page's content edge */
.hero[data-hv] .hero__content { align-items: flex-end; padding-bottom: clamp(5rem, 11vh, 8rem); }
.hero[data-hv] .hero__content .inner { align-items: flex-start; text-align: left; max-width: none; }   /* on the screen's gutter, not the centred content column: the words sit hard left (Anna, 4 Oct 2026) */
/* A second scrim in from the left, under the words, so they read over bright footage; it is gone by mid-screen */
.hero[data-hv] .hero__scrim {
  background:
    linear-gradient(to right, rgb(14 12 11 / 0.86) 0%, rgb(14 12 11 / 0.62) 30%, rgb(14 12 11 / 0.22) 52%, rgb(14 12 11 / 0) 68%),   /* a notch darker (Anna, 4 Oct) */
    linear-gradient(to bottom, rgb(14 12 11 / 0.6) 0%, rgb(14 12 11 / 0.32) 38%, rgb(14 12 11 / 0.42) 70%, rgb(14 12 11 / 0.78) 100%);
}
.hero[data-hv] .actions { justify-content: flex-start; margin-top: var(--s-6); }
.hv__proof { margin: var(--s-4) 0 0; max-width: 46ch; font-size: calc((var(--step--1)) * 1.2); color: var(--oat); }
.hero .hv__title { margin: 0; margin-inline: 0; max-width: 17ch; font-size: calc((clamp(2.5rem, 4.6vw, 4.25rem)) * 1.2); line-height: 1.02; letter-spacing: -0.03em; }

/* 1. Credit roll: a small lead-in, the service large, one more fading in below */
.hv--1 .hv__lead { margin: 0 0 var(--s-2); font-family: var(--display); font-size: calc((clamp(1.25rem, 1.8vw, 1.6rem)) * 1.2); color: var(--paper); }
.hv--1 .hs--roll { --line: 1.02em; height: calc(var(--line) * 2); margin: 0; font-size: calc((clamp(3rem, 6.2vw, 5.75rem)) * 1.2);
  -webkit-mask-image: linear-gradient(to bottom, #000 55%, transparent); mask-image: linear-gradient(to bottom, #000 55%, transparent); }

/* 2. What and proof: the headline says the offer, a client says it's worth it, the services sit as a row */
.hv--2 .hv__quote { margin: var(--s-5) 0 0; padding-left: var(--s-4); border-left: 1px solid var(--clay); }
.hv--2 .hv__quote blockquote { margin: 0; font-family: var(--display); font-size: calc((var(--step-1)) * 1.2); color: var(--paper); }
.hv--2 .hv__quote figcaption { margin-top: var(--s-2); font-size: calc((var(--step--2)) * 1.2); letter-spacing: 0.14em; text-transform: uppercase; color: var(--oat); }
.hs--inline, .hs--index { height: auto; overflow: visible; -webkit-mask-image: none; mask-image: none; display: flex; flex-wrap: wrap; gap: var(--s-2) var(--s-5);
  font-family: var(--body, inherit); font-size: calc((var(--step--1)) * 1.2); letter-spacing: 0.12em; text-transform: uppercase; line-height: 1.5; }
.hs--inline li, .hs--index li { translate: none; height: auto; opacity: 0.55; }
.hs--inline { margin: var(--s-6) 0 0; }
.hs--inline li.is-on { opacity: 1; text-decoration: underline; text-underline-offset: 6px; text-decoration-thickness: 1px; }

/* 3. Index: the headline and buttons above, the services as numbered tabs along the foot, each with its own progress line */
.hero[data-hv="3"] .hero__progress { display: none !important; }
.hero[data-hv="3"] .hero__content { padding-bottom: clamp(9rem, 20vh, 12rem); }
.hv--3 .hs--index { position: absolute; left: 0; right: 0; bottom: clamp(1.5rem, 4vh, 2.5rem); margin: 0 auto; width: min(var(--max, 76rem), 100% - 2 * var(--gutter, 1.5rem));
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--s-5); }
.hv--3 .hs--index li { padding-top: var(--s-3); border-top: 1px solid rgb(244 240 237 / 0.25); position: relative; }
.hv--3 .hs--index li.is-on { border-top-color: var(--paper); }
.hv--3 .hs-no { display: block; margin-bottom: var(--s-1); font-family: var(--display); font-size: calc((var(--step-1)) * 1.2); letter-spacing: 0; }
@media (max-width: 48rem) { .hv--3 .hs--index { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
/* the index bar lines up with the content edge: the .inner box minus its gutter */
.hv--3 .hs--index { width: min(var(--max), 100%); padding-inline: var(--gutter); box-sizing: border-box; }

/* 4. Mix (Anna, 3 Oct): Index's layout, Credit roll's moving word at headline size, no subtext,
   and five tabs named exactly like the What I make panels further down */
.hero[data-hv="4"] .hv--4 { display: block; }
.hero[data-hv="4"] .hero__progress { display: none !important; }
.hero[data-hv="4"] .hero__content { padding-bottom: clamp(9rem, 20vh, 12rem); }
.hv__roll { display: block; }
.hv__rollwin { display: block; height: 1.02em; overflow: hidden; }
.hv__rolltrack { display: flex; flex-direction: column; translate: 0 calc(var(--i, 0) * -1.02em); transition: translate 1100ms cubic-bezier(0.22, 1, 0.36, 1); }   /* moves, then settles softly and rests; no hard stop */
.hv__rolltrack span { display: block; height: 1.02em; color: var(--oat); }
.hv--4 .hs--index { position: absolute; left: 0; right: 0; bottom: clamp(1.5rem, 4vh, 2.5rem); margin: 0 auto; width: min(var(--max), 100%); padding-inline: var(--gutter); box-sizing: border-box;
  display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: var(--s-5); }
.hv--4 .hs--index li { padding-top: var(--s-3); border-top: 1px solid rgb(244 240 237 / 0.25); }
.hv--4 .hs--index li.is-on { border-top-color: var(--paper); }
.hv--4 .hs-no { display: block; margin-bottom: var(--s-1); font-family: var(--display); font-size: calc((var(--step-1)) * 1.2); letter-spacing: 0; }
@media (prefers-reduced-motion: reduce) { .hv__rolltrack { transition: none; } }
@media (max-width: 48rem) { .hv--4 .hs--index { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

/* Fix, 3 Oct: the tabs sat on top of the buttons when the screen was short or a label wrapped.
   They now sit in the flow under the buttons, five across, so nothing can overlap. */
.hv--3 .hs--index, .hv--4 .hs--index {
  position: static; width: 100%; padding-inline: 0; margin: clamp(2.5rem, 7vh, 4.5rem) 0 0;
  grid-template-columns: repeat(5, minmax(0, 1fr));
}
.hero[data-hv="3"] .hero__content, .hero[data-hv="4"] .hero__content { padding-bottom: clamp(1.5rem, 4vh, 2.5rem); }
.hero[data-hv="3"] .hv--3, .hero[data-hv="4"] .hv--4 { display: contents; }   /* its parts join the column, so the buttons can sit between headline and tabs */
.hero[data-hv="3"] .actions, .hero[data-hv="4"] .actions { order: 3; }
.hv--3 .hs--index, .hv--4 .hs--index { order: 4; }
@media (max-width: 48rem) { .hv--3 .hs--index, .hv--4 .hs--index { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

/* Credit roll, revised (Anna, 3 Oct): every service in view, the playing one a little larger at full
   opacity, the rest smaller and dimmed. The list itself stays put; the highlight moves on by itself with the videos. */
.hv--1 .hs--roll { height: auto; overflow: visible; -webkit-mask-image: none; mask-image: none; margin: var(--s-2) 0 0;
  font-size: calc((clamp(1.6rem, 2.6vw, 2.4rem)) * 1.2); --line: 1.25em; }
.hv--1 .hs--roll li { translate: none; height: var(--line); opacity: 0.38; transform-origin: left center; scale: 1;
  transition: opacity 600ms ease, scale 700ms cubic-bezier(0.16, 1, 0.3, 1); }
.hv--1 .hs--roll li.is-on { opacity: 1; scale: 1.22; }
.hv--1 .hs--roll li:not(.is-on):hover { opacity: 0.7; }

/* Credit roll as a carousel (Anna, 3 Oct): the services run from bottom to top without end. The playing one
   sits in the middle row, larger and at full opacity; the others pass above and below, dimmed and fading out. */
.hero[data-hv="1"] .hv--1 .hs--roll { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
.roll { --line: 1.3em; position: relative; height: calc(var(--line) * 5); overflow: hidden; margin: var(--s-1) 0 0;
  font-family: var(--display); font-size: calc((clamp(1.6rem, 2.6vw, 2.4rem)) * 1.2); line-height: var(--line); letter-spacing: -0.02em;
  -webkit-mask-image: linear-gradient(to bottom, transparent, #000 30%, #000 70%, transparent);
          mask-image: linear-gradient(to bottom, transparent, #000 30%, #000 70%, transparent); }
.roll__track { translate: 0 calc(var(--pos, 0) * var(--line) * -1); transition: translate 1100ms cubic-bezier(0.22, 1, 0.36, 1); }   /* moves, then settles softly and rests; no hard stop */
.roll__track.is-jump { transition: none; }
.roll button { all: unset; display: block; height: var(--line); cursor: pointer; color: var(--paper); opacity: 0.38;
  transform-origin: left center; transition: opacity 1100ms cubic-bezier(0.22, 1, 0.36, 1), scale 1100ms cubic-bezier(0.22, 1, 0.36, 1); }
.roll button.is-on { opacity: 1; scale: 1.22; }
.roll button:not(.is-on):hover { opacity: 0.7; }
@media (prefers-reduced-motion: reduce) { .roll__track, .roll button { transition: none; } }

/* Seamless switching (Anna, 3 Oct): the videos dissolve into each other slowly instead of wiping across */
.hero[data-hv] .hero__media .bg { transition-duration: 1200ms; }

/* Credit roll proportions (3 Oct). One scale, ratio 1.333 (a perfect fourth), set from the services size:
     services   S = clamp(30px, 2.9vw, 42px)   Times, -0.02em, leading 1.12 (tight, so the list reads as one block)
     playing    S x 1.15 by scale, full opacity; the rest 32%, fading out towards the edges
     lead-in    S / 1.333^2 ~ 0.56S  Inter, small capitals spacing, so it labels the list instead of competing with it
     gaps       lead to list S x 0.4; list to buttons S x 1.2
   Five rows show, the playing one in the middle. */
.hv--1 .hv__lead { margin: 0 0 calc(var(--svc) * 0.4); font-family: var(--body, inherit); font-size: calc((calc(var(--svc) * 0.42)) * 1.2);
  letter-spacing: 0.16em; text-transform: uppercase; color: var(--oat); }
.hv--1 { --svc: clamp(1.875rem, 2.9vw, 2.625rem); }
.roll { --line: 1.12em; font-size: calc((var(--svc)) * 1.2); letter-spacing: -0.02em; margin: 0; height: calc(var(--line) * 5);
  -webkit-mask-image: linear-gradient(to bottom, transparent 0%, #000 34%, #000 66%, transparent 100%);
          mask-image: linear-gradient(to bottom, transparent 0%, #000 34%, #000 66%, transparent 100%); }
.roll button { opacity: 0.32; }
.roll button.is-on { opacity: 1; scale: 1.15; }
.hero[data-hv="1"] .actions { margin-top: calc(var(--svc) * 1.2); }
/* Four rows: one above (a hint of what passed), the playing one, two below; the lead-in stays clear of the list */
.roll { height: calc(var(--line) * 4);
  -webkit-mask-image: linear-gradient(to bottom, rgb(0 0 0 / 0.35) 0%, #000 25%, #000 55%, transparent 100%);
          mask-image: linear-gradient(to bottom, rgb(0 0 0 / 0.35) 0%, #000 25%, #000 55%, transparent 100%); }
.hv--1 .hv__lead { margin-bottom: calc(var(--svc) * 0.5); }
.hero[data-hv="1"] .actions { margin-top: calc(var(--svc) * 2.2); }   /* more air between the list and the buttons (Anna, 3 Oct) */
.hero[data-hv="1"] { --svc: clamp(1.875rem, 2.9vw, 2.625rem); }   /* the buttons sit outside the text block, so the scale lives on the hero */
.hero .hv--1 .hv__lead { max-width: none; white-space: nowrap; }   /* the label is now an h1, which inherited a narrow width and wrapped */

/* 4 Oct (Anna): nothing clipped on the right, and the other services readable at a glance */
.roll { width: max-content; max-width: 100%; padding-right: 3em; box-sizing: content-box;   /* room for the playing line's 1.15 scale */
  height: calc(var(--line) * 5);   /* one above, the playing one, three below */
  -webkit-mask-image: linear-gradient(to bottom, rgb(0 0 0 / 0.75) 0%, #000 20%, #000 70%, rgb(0 0 0 / 0.45) 100%);
          mask-image: linear-gradient(to bottom, rgb(0 0 0 / 0.75) 0%, #000 20%, #000 70%, rgb(0 0 0 / 0.45) 100%); }
.roll button { opacity: 0.62; }
.roll button.is-on { opacity: 1; }
.roll button:not(.is-on):hover { opacity: 0.85; }
.roll button { opacity: 0.58; }   /* 4 Oct: the unselected lines quieter than the playing one, but they are buttons, so they stay legible over footage */
.roll button:not(.is-on):hover { opacity: 0.75; }
.roll { font-size: calc((calc(var(--svc) * 0.72)) * 1.2); }   /* 4 Oct: the list 20% smaller, then another 10% (Anna); the label and spacing keep their sizes */
/* A picked service answers fast; the automatic cycle keeps its slower, softer timing */
.hero.is-quick .roll__track { transition-duration: 480ms; }
.hero.is-quick .roll button { transition-duration: 300ms; }
.hero.is-quick .hero__media .bg { transition-duration: 450ms; }
.hero[data-hv="1"] .hv--1 { cursor: ns-resize; }   /* hints that the list scrolls */
.hero[data-hv="1"] .hv--1 .roll button { cursor: pointer; }

/* 4 Oct (Anna): the list shouldn't look finished. Lines further down soften and blur, and half of one more line
   shows at the foot, out of focus, as if it's waiting to come up. */
.roll { height: calc(var(--line) * 5.6);
  -webkit-mask-image: linear-gradient(to bottom, rgb(0 0 0 / 0.75) 0%, #000 18%, #000 58%, transparent 100%);
          mask-image: linear-gradient(to bottom, rgb(0 0 0 / 0.75) 0%, #000 18%, #000 58%, transparent 100%); }
.roll button { transition: opacity 1100ms cubic-bezier(0.22, 1, 0.36, 1), scale 1100ms cubic-bezier(0.22, 1, 0.36, 1), filter 1100ms cubic-bezier(0.22, 1, 0.36, 1); }
.roll button[data-off="2"] { filter: blur(0.6px); }
.roll button[data-off="3"] { filter: blur(1.6px); opacity: 0.35; }
.roll button[data-off="4"] { filter: blur(3px); opacity: 0.25; }
.roll button.is-on { filter: none; }
/* 4 Oct: one more line in view (six and a half rows); the blur moves one line further down */
.roll { height: calc(var(--line) * 6.6); }
.roll button[data-off="3"] { filter: blur(0.6px); opacity: 0.45; }
.roll button[data-off="4"] { filter: blur(1.6px); opacity: 0.35; }
.roll button[data-off="5"] { filter: blur(3px); opacity: 0.25; }
.roll button[data-off="2"] { filter: none; }
/* 4 Oct: one cursor for the whole list. The up-down arrows are a resize cursor and only showed on the label and
   gaps; the list now shows the ordinary pointing hand everywhere, top to bottom, and the label shows the normal arrow. */
.hero[data-hv="1"] .hv--1 { cursor: auto; }
.hero[data-hv="1"] .roll, .hero[data-hv="1"] .roll * { cursor: pointer; }
/* Scrolling with the wheel: short moves, so fast turns stay in step with the hand */
.hero.is-wheel .roll__track { transition-duration: 260ms; transition-timing-function: cubic-bezier(0.25, 1, 0.5, 1); }
.hero.is-wheel .roll button { transition-duration: 220ms; }
.hero.is-wheel .hero__media .bg { transition-duration: 300ms; }
/* Edge glide: linear and as long as each step, so the movement is continuous; the final settle stays soft */
.hero.is-edge .roll__track { transition: translate var(--edge-step, 420ms) linear; }
.hero.is-edge .roll button { transition-duration: 260ms; }

/* Outcome line under the list (4 Oct): Inter, quiet, one line's payoff. A 200ms blur-fade hides the text swap. */
.hv__outcome { margin: calc(var(--svc) * 0.5) 0 0; max-width: 40ch; min-height: 3em; font-size: calc((var(--step-0)) * 1.2); line-height: 1.45; color: var(--paper);
  transition: opacity 200ms cubic-bezier(0.23, 1, 0.32, 1), filter 200ms cubic-bezier(0.23, 1, 0.32, 1); }
.hv__outcome.is-swapping { opacity: 0; filter: blur(4px); }
.hero:not([data-hv="1"]) .hv__outcome { display: none; }
.hero[data-hv="1"] .actions { margin-top: calc(var(--svc) * 1.2); }
@media (prefers-reduced-motion: reduce) { .hv__outcome { transition: opacity 200ms linear; } .hv__outcome.is-swapping { filter: none; } }
/* Outcome line in Times (Anna, 4 Oct): the same voice as the list, a clear step smaller than the services */
.hv__outcome { font-family: var(--display); font-size: calc((calc(var(--svc) * 0.58)) * 1.2); line-height: 1.3; letter-spacing: -0.005em; max-width: 34ch; color: var(--paper); }
/* One line, and quieter than the list (Anna, 4 Oct): warm Oat at 75%, a touch smaller, so the playing service leads */
.hv__outcome { white-space: nowrap; max-width: none; min-height: 0; font-size: calc((calc(var(--svc) * 0.52)) * 1.2); color: var(--oat); opacity: 0.75; }
.hv__outcome.is-swapping { opacity: 0; }
@media (max-width: 56rem) { .hv__outcome { white-space: normal; max-width: 34ch; } }   /* phones and narrow windows may wrap rather than run off the screen */
/* The loop's copy swap must always be instant, whatever timing mode the hero is in (wheel, edge, quick) */
.hero .roll .roll__track.is-jump, .hero .roll .roll__track.is-jump * { transition: none !important; }

/* 4 Oct quick wins ----------------------------------------------------------------------------------------- */
/* The quote promise: small and quiet, under the buttons */
/* The promise line under the buttons came out on 4 Oct 2026: a fifth text size in the hero, and the two working days
   are already promised in the closing section and on About. */
/* The line button, on footage: a Paper border at half strength (as on About), since the Umber one vanished on dark film */
.hero[data-hv] .btn--line { border-color: rgb(248 239 230 / 0.55); }
@media (hover: hover) and (pointer: fine) { .hero[data-hv] .btn--line:hover { border-color: var(--paper); color: var(--paper); background: rgb(248 239 230 / 0.08); } }
/* The playing service shows its time: a hairline under it fills over the 4s, and pauses when the cycle is held */
.hero[data-hv="1"] .hero__progress { display: none !important; }
.roll button { position: relative; }
.roll button.is-on::after { content: ""; position: absolute; left: 0; right: 0; bottom: 0.08em; height: 1px; background: currentColor; opacity: 0.6;
  transform-origin: left; transform: scaleX(0); animation: hv-fill 4s linear forwards; }
.hero:has(.hero__progress.is-held) .roll button.is-on::after, .hero.is-edge .roll button.is-on::after, .hero.is-wheel .roll button.is-on::after { animation-play-state: paused; }
@keyframes hv-fill { to { transform: scaleX(1); } }
/* Buttons press in slightly */
.hero .btn { transition: transform 140ms cubic-bezier(0.23, 1, 0.32, 1), background-color 200ms ease, color 200ms ease; }
.hero .btn:active { transform: scale(0.97); }
/* Hover only where there is a real mouse */
@media not ((hover: hover) and (pointer: fine)) { .roll button:not(.is-on):hover { opacity: 0.45; } }
@media (prefers-reduced-motion: reduce) { .roll button.is-on::after { animation: none; transform: scaleX(1); } .hero .btn:active { transform: none; } }
/* 4 Oct: the hairline now follows the carousel's own clock. The progress bars stay rendered but invisible (a hidden
   element's animation doesn't run), and the hairline restarts with the same duration whenever a bar starts. */
.hero[data-hv="1"] .hero__progress { display: flex !important; opacity: 0; pointer-events: none; }
.roll button.is-on::after { animation: none; }
.roll.is-filling button.is-on::after { animation: hv-fill var(--fill, 4s) linear forwards; }

/* 5 Oct (Anna): "Video production" without Sydney, set as the headline above the list, a step larger than the
   services (list 0.8 x scale, label 1.15 x scale), in Times like the list */
.hero .hv--1 .hv__lead { font-family: var(--display); font-size: calc((calc(var(--svc) * 1.15)) * 1.2); letter-spacing: -0.02em; text-transform: none;
  line-height: 1.05; color: var(--paper); margin-bottom: calc(var(--svc) * 0.35); }

/* 5 Oct (Anna): the title is a full sentence and must not blend with the list. Title: Paper white, largest, up to
   two lines. List: warm Oat (the playing line in full Oat, the rest dimmed), so the eye reads title, then choice. */
.hero .hv--1 .hv__lead { max-width: 21ch; white-space: normal; font-size: calc((calc(var(--svc) * 1.05)) * 1.2); line-height: 1.08; margin-bottom: calc(var(--svc) * 0.7); }
.roll button { color: var(--oat); }
.hero .hv--1 .hv__lead { max-width: 22ch; font-size: calc((calc(var(--svc) * 1.5)) * 1.2); line-height: 1.02; }   /* 4 Oct (Anna): bigger; the shorter line breaks as "Video that wins your / next client." */

/* 4 Oct (Anna): "wins" carries the sentence, so it is set in Times italic, same size and weight; no colour, since the
   footage carries the colour and the palette has no accent */
.hero .hv--1 .hv__win { font-style: italic; font-weight: inherit; letter-spacing: -0.01em; }

/* The label follows the playing service, so the button used to resize (and push the icons) on every slide. Fixed to the widest label ("See social media work"). */
.hero .hv__work { box-sizing: border-box; min-width: 15.6em; text-align: center; }

/* 10 Oct 2026 (Anna, prototypes/hero-outcome a.html): the outcome line was missed at the foot of the list, so it moves
   up under the headline as its second half, bigger, italic, full Paper, with a soft shadow to hold over any video.
   It is always exactly two lines tall (Anna: "keep only two rows, otherwise everything else moves around it"):
   every line in hero.js must fit two lines at every width, and the box never grows or shrinks between videos. */
.hero[data-hv="1"] .hv--1 { display: flex; flex-direction: column; }
.hv--1 .hv__lead { order: 0; }
.hv--1 .hv__outcome {
  order: 1; margin: var(--s-3) 0 var(--s-4);
  white-space: normal; max-width: 34ch; height: 2.5em; min-height: 0; overflow: hidden;
  font-style: italic; font-size: calc((calc(var(--svc) * 0.66)) * 1.2); line-height: 1.25; color: var(--paper); opacity: 1;
  text-shadow: 0 1px 18px rgb(14 12 11 / 0.85), 0 0 2px rgb(14 12 11 / 0.6);
}
.hv--1 .hs--roll, .hv--1 > .roll { order: 2; }
@media (max-width: 24rem) { .hv--1 .hv__outcome { font-size: calc((1.0625rem) * 1.2); } }   /* the smallest phones: still two lines */
.hero__progress { max-width: calc(100% - 2rem); } .hero__progress i { flex: 0 1 auto; min-width: 0; }   /* 10 Oct: ten videos; the (hidden) bar must not widen small phones */
/* 10 Oct 2026 (Anna: "the text change needs to be smoother"): a slow crossfade timed with the video's 1.2s dissolve,
   no blur. Out in 450ms, the new line in over 750ms (hero.js swaps the text at 450ms). */
.hv--1 .hv__outcome { transition: opacity 500ms cubic-bezier(0.33, 0, 0.2, 1); filter: none; }   /* Anna: 750ms was a bit too slow */
.hv--1 .hv__outcome.is-swapping { opacity: 0; filter: none; transition: opacity 300ms cubic-bezier(0.4, 0, 1, 1); }

/* 11 Oct 2026 (Emil review): a 2px blur while the outcome line swaps, so the old and new lines read as one movement. */
.hv--1 .hv__outcome { transition: opacity 500ms cubic-bezier(0.33, 0, 0.2, 1), filter 500ms cubic-bezier(0.33, 0, 0.2, 1); }
.hv--1 .hv__outcome.is-swapping { filter: blur(2px); transition: opacity 300ms cubic-bezier(0.4, 0, 1, 1), filter 300ms cubic-bezier(0.4, 0, 1, 1); }
@media (prefers-reduced-motion: reduce) { .hv--1 .hv__outcome.is-swapping { filter: none; } }
