/* Discover Copeel — the one long page that shows the app.
   Built on the tokens of /assets/site.css. Motion is driven by discover.js
   through two hooks: `.is-visible` on [data-reveal] once it enters the
   viewport, and `--p` (0 → 1) on [data-progress] while it crosses it. Without
   JavaScript, or with reduced motion, everything is simply shown. */

.discover {
  overflow-x: clip;
}

.discover .eyebrow {
  margin: 0 0 12px;
  color: var(--accent, var(--brand));
  font-size: 17px;
  font-weight: 600;
  letter-spacing: -0.01em;
}

.discover h2 {
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--text-headline);
  font-weight: 700;
  line-height: 1.06;
  letter-spacing: -0.03em;
  text-wrap: balance;
}

.d-title {
  max-width: 20ch;
  margin-inline: auto !important;
  text-align: center;
}

.tile {
  border-radius: 32px;
  background: var(--bg-alt);
}

/* Reveal ------------------------------------------------------------------ */

.js [data-reveal] {
  opacity: 0;
  translate: 0 28px;
  transition:
    opacity 0.9s var(--ease-apple),
    translate 0.9s var(--ease-apple);
  transition-delay: calc(var(--i, 0) * 90ms);
}

.js [data-reveal].is-visible {
  opacity: 1;
  translate: 0 0;
}

/* iPhone ------------------------------------------------------------------ */

/* An iPhone 17 Pro drawn around a 603 × 1311 capture. The width is the only
   input: everything inside is in container units of the frame. */
.phone {
  container-type: inline-size;
  width: var(--phone-w, 300px);
  flex: none;
}

.phone-body {
  position: relative;
  padding: 3.6cqw;
  border-radius: 16.5cqw;
  background: linear-gradient(160deg, #6d6a66 0%, #3b3a38 45%, #5b5955 100%);
  box-shadow:
    inset 0 0 0 1px rgba(255, 255, 255, 0.18),
    inset 0 0 0 2px rgba(0, 0, 0, 0.35),
    0 40px 80px -30px rgba(14, 26, 36, 0.45),
    0 18px 36px -18px rgba(14, 26, 36, 0.3);
}

.phone-body img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 603 / 1311;
  border-radius: 13cqw;
  background: #f2f2f7;
  user-select: none;
  -webkit-user-drag: none;
}

.phone-island {
  position: absolute;
  top: calc(3.6cqw + 2.6cqw);
  left: 50%;
  width: 29cqw;
  height: 8.4cqw;
  border-radius: 999px;
  background: #000;
  translate: -50% 0;
}

/* Hero -------------------------------------------------------------------- */

.d-hero {
  position: relative;
  isolation: isolate;
  margin-top: calc(var(--header-h) * -1);
  padding: calc(var(--header-h) + 64px) 20px 0;
  text-align: center;
}

.d-hero::before {
  content: "";
  position: absolute;
  inset: 0 0 30%;
  z-index: -1;
  background: var(--wash);
}

.d-hero::after {
  content: "";
  position: absolute;
  inset-inline: 0;
  bottom: 30%;
  z-index: -1;
  height: 200px;
  background: linear-gradient(180deg, transparent, var(--bg));
}

.d-hero-copy {
  max-width: 900px;
  margin: 0 auto;
}

.d-hero h1 {
  margin: 0 auto;
  max-width: 18ch;
  font-family: var(--font-display);
  font-size: var(--text-display);
  font-weight: 700;
  line-height: 1.02;
  letter-spacing: -0.035em;
  text-wrap: balance;
}

.d-hero .lead {
  max-width: 40ch;
  margin: 20px auto 28px;
  color: var(--ink-secondary);
  font-size: var(--text-lead);
  line-height: 1.4;
  letter-spacing: -0.012em;
  text-wrap: pretty;
}

.d-hero .reveal + .reveal:last-child {
  margin: 0;
}

/* Two phones, the second behind the first. They part as the page scrolls,
   all the way until the block has left the screen. */
.d-hero-phones {
  --p: 0;
  position: relative;
  display: flex;
  justify-content: center;
  height: clamp(500px, 68vw, 760px);
  margin: clamp(40px, 6vw, 72px) -20px 0;
  overflow: clip;
  perspective: 1600px;
  -webkit-mask-image: linear-gradient(180deg, #000 62%, transparent);
  mask-image: linear-gradient(180deg, #000 62%, transparent);
}

.d-hero-phones .phone {
  --phone-w: clamp(220px, 30vw, 330px);
  position: absolute;
  /* Room above for the tilt and for the lift on scroll: nothing is cut. */
  top: 64px;
  animation: phone-in 1.1s var(--ease-apple) both;
}

.hero-front {
  z-index: 1;
  translate: calc(var(--phone-w) * 0.22 + var(--p) * min(130px, 12vw)) calc(var(--p) * -90px);
  rotate: calc(4deg - var(--p) * 9deg);
  animation-delay: 0.1s !important;
}

.hero-back {
  translate: calc(var(--phone-w) * -0.32 - var(--p) * min(170px, 16vw)) calc(40px + var(--p) * 30px);
  rotate: calc(-7deg - var(--p) * 8deg);
  opacity: 0.96;
  animation-delay: 0.2s !important;
}

@keyframes phone-in {
  from {
    opacity: 0;
    transform: translateY(120px) scale(0.94);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

/* Statement --------------------------------------------------------------- */

/* One sentence that fills with ink, word by word, as it is read. */
.d-statement {
  padding: clamp(96px, 16vw, 200px) 20px;
}

.d-statement p {
  max-width: 22ch;
  margin: 0 auto;
  font-family: var(--font-display);
  font-size: clamp(2.25rem, 1.2rem + 4.4vw, 4.5rem);
  font-weight: 700;
  line-height: 1.08;
  letter-spacing: -0.035em;
  text-align: center;
  text-wrap: balance;
}

.d-statement .word {
  opacity: calc(0.16 + var(--w, 1) * 0.84);
  transition: opacity 0.25s linear;
}

/* Story ------------------------------------------------------------------- */

/* Four chapters, each told by three pieces of the app laid on its grey, as
   the onboarding does. On wide screens the panel stays pinned while the text
   scrolls past it and its pieces change with the chapter; on phones each
   chapter carries its own panel. */
.d-story {
  position: relative;
  max-width: var(--container);
  margin: 0 auto;
  padding: 0 20px;
}

.story-stage {
  display: none;
}

.story-step {
  padding: 48px 0 72px;
  text-align: center;
}

.story-step h2 {
  max-width: 16ch;
  margin-inline: auto;
}

.story-text {
  max-width: 34ch;
  margin: 16px auto 32px;
  color: var(--ink-secondary);
  font-size: var(--text-lead);
  line-height: 1.4;
  letter-spacing: -0.012em;
  text-wrap: pretty;
}

/* The app's grouped background, with a halo in the chapter's colour. The
   colour is a registered property, so it glides from one chapter's to the
   next in step with the slide instead of switching. */
@property --halo {
  syntax: "<color>";
  inherits: false;
  initial-value: #0fa968;
}

.stage-panel {
  container-type: inline-size;
  position: relative;
  isolation: isolate;
  overflow: hidden;
  padding: clamp(24px, 6vw, 40px);
  border-radius: 36px;
  background: #f2f2f7;
}

.stage-panel::before {
  content: "";
  position: absolute;
  top: -30%;
  right: -30%;
  z-index: -1;
  width: 90%;
  aspect-ratio: 1;
  border-radius: 50%;
  background: radial-gradient(circle, color-mix(in srgb, var(--accent, var(--green)) 32%, transparent), transparent 66%);
}

/* In the pinned panel the halo is an element of its own, so its colour
   can glide without restyling the scenes. */
.story-stage .stage-panel::before {
  content: none;
}

.stage-halo {
  position: absolute;
  top: -30%;
  right: -30%;
  z-index: -1;
  width: 90%;
  aspect-ratio: 1;
  border-radius: 50%;
  background: radial-gradient(circle, color-mix(in srgb, var(--halo) 32%, transparent), transparent 66%);
  opacity: 0;
  pointer-events: none;
  will-change: opacity;
}

.stage-halo:first-child {
  opacity: 1;
}

.story-inline {
  max-width: 460px;
  margin: 0 auto;
}

.scene {
  display: flex;
  flex-direction: column;
  gap: 3.24cqw;
  text-align: start;
}

/* A piece of the app: its corners are already cut, the shadow follows them. */
.el {
  display: block;
  width: 100%;
  height: auto;
  filter: drop-shadow(0 16px 28px rgba(14, 26, 36, 0.1)) drop-shadow(0 2px 5px rgba(14, 26, 36, 0.05));
  user-select: none;
  -webkit-user-drag: none;
}

/* A row of pieces with the app's 12 pt gap; each width comes from the
   generator, so every piece is shown at the same scale. */
.el-row {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
}

/* Live: the Home widgets rebuilt in HTML from the app's measures. 1 pt of
   the app's 370 pt content width is var(--pt), so the scene scales as one. */
.scene-live {
  --pt: calc(100cqw / 370);
  --secondary: rgba(60, 60, 67, 0.6);
  --tertiary: rgba(60, 60, 67, 0.3);
  --green: #0fa968;
  --rounded: ui-rounded, "SF Pro Rounded", -apple-system, BlinkMacSystemFont, system-ui, sans-serif;
  gap: calc(12 * var(--pt));
  color: #000;
  font-family: -apple-system, BlinkMacSystemFont, "SF Pro Text", system-ui, sans-serif;
  line-height: 1.2;
}

.scene-live p {
  margin: 0;
}

.w-card {
  position: relative;
  border-radius: calc(18 * var(--pt));
  background: #fff;
  box-shadow: 0 calc(4 * var(--pt)) calc(16 * var(--pt)) rgba(0, 0, 0, 0.05);
}

.w-head {
  display: flex;
  align-items: center;
  gap: calc(8 * var(--pt));
}

.w-ico {
  display: grid;
  flex: none;
  place-items: center;
}

.w-ico svg {
  width: calc(16 * var(--pt));
  height: calc(16 * var(--pt));
}

.w-title {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  font-size: calc(13 * var(--pt));
  font-weight: 600;
  white-space: nowrap;
  text-overflow: ellipsis;
}

.w-chev {
  display: grid;
  color: var(--tertiary);
}

.w-chev svg {
  width: calc(12 * var(--pt));
  height: calc(12 * var(--pt));
}

.w-chev.w-q {
  color: rgba(60, 60, 67, 0.18);
}

.w-green {
  color: var(--green);
}

.w-blue {
  color: #0062e6;
}

/* The charging banner. */
.w-banner {
  display: flex;
  flex-direction: column;
  gap: calc(16 * var(--pt));
  padding: calc(18 * var(--pt));
}

.w-banner .w-ico svg {
  width: calc(14 * var(--pt));
  height: calc(14 * var(--pt));
}

.w-banner-title {
  font-size: calc(15 * var(--pt));
}

.w-body {
  display: flex;
  flex-direction: column;
  gap: calc(10 * var(--pt));
}

.w-figure-row,
.w-figure {
  display: flex;
  align-items: baseline;
  gap: calc(8 * var(--pt));
}

.w-fig32,
.w-fig38 {
  display: inline-block;
  font-family: var(--rounded);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  line-height: 1;
}

.w-fig32 {
  font-size: calc(32 * var(--pt));
}

.w-fig38 {
  font-size: calc(38 * var(--pt));
}

.w-unit {
  color: var(--secondary);
  font-size: calc(20 * var(--pt));
  font-weight: 600;
}

.w-timer {
  margin-left: auto;
  color: var(--secondary);
  font-size: calc(15 * var(--pt));
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

/* A new figure rolls in from below, as numericText does: short travel,
   soft fade, so it reads as a tick rather than a jump. */
.is-rolling {
  animation: roll 0.6s var(--ease-apple);
}

@keyframes roll {
  from {
    opacity: 0.2;
    translate: 0 22%;
    filter: blur(1px);
  }
}

.w-caption {
  display: flex;
  justify-content: space-between;
  gap: calc(8 * var(--pt));
  color: var(--secondary);
  font-size: calc(13 * var(--pt));
  white-space: nowrap;
}

/* Bars: the track, the fill, the charge-limit tick, and while charging the
   band of light that crosses the fill (ChargingFlowOverlay). */
.w-track {
  position: relative;
  flex: none;
  height: calc(8 * var(--pt));
  border-radius: 999px;
  background: #e5e5ea;
}

.w-fill {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  width: max(calc(8 * var(--pt)), calc(var(--level) * 100%));
  overflow: hidden;
  border-radius: 999px;
  background: var(--green);
  transition: width 0.5s ease-in-out;
}

.w-mark {
  position: absolute;
  top: 0;
  bottom: 0;
  left: calc(var(--target) * 100% - 1 * var(--pt));
  width: calc(2 * var(--pt));
  border-radius: 999px;
  background: rgba(0, 0, 0, 0.18);
}

.w-flow {
  position: absolute;
  inset: 0;
  background: linear-gradient(to bottom right, rgba(255, 255, 255, 0.045), rgba(255, 255, 255, 0.01), rgba(255, 255, 255, 0.035));
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);
}

.w-flow i {
  position: absolute;
  top: 0;
  bottom: 0;
  left: calc(-44 * var(--pt));
  width: calc(44 * var(--pt));
  background: linear-gradient(
    90deg,
    rgba(255, 255, 255, 0) 0%,
    rgba(255, 255, 255, 0.03) 22%,
    rgba(255, 255, 255, 0.12) 38%,
    rgba(255, 255, 255, 0.22) 50%,
    rgba(255, 255, 255, 0.12) 62%,
    rgba(255, 255, 255, 0.03) 78%,
    rgba(255, 255, 255, 0) 100%
  );
  mix-blend-mode: plus-lighter;
  /* A 1.9 s crossing every 5.8 s, on the same clock for every bar. */
  animation: flow 5.8s linear infinite;
  animation-delay: var(--flow-delay, 0s);
}

@keyframes flow {
  0% {
    left: calc(-44 * var(--pt));
  }
  32.76%,
  100% {
    left: 100%;
  }
}

/* The four square modules. */
.w-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: calc(12 * var(--pt));
}

.w-square {
  display: flex;
  flex-direction: column;
  gap: calc(8 * var(--pt));
  aspect-ratio: 1;
  padding: calc(16 * var(--pt));
}

.w-figure {
  gap: calc(2 * var(--pt));
  margin-top: auto !important;
}

.w-tyre-row {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  margin-top: auto;
}

.w-tyre-grid {
  display: grid;
  grid-template-columns: repeat(2, calc(42 * var(--pt)));
  gap: calc(14 * var(--pt));
}

.w-tyre {
  font-family: var(--rounded);
  font-size: calc(20 * var(--pt));
  font-weight: 500;
  font-variant-numeric: tabular-nums;
  text-align: center;
}

.w-badge {
  display: grid;
  place-items: center;
  width: calc(26 * var(--pt));
  height: calc(26 * var(--pt));
  border-radius: 50%;
  background: rgba(15, 169, 104, 0.12);
  color: var(--green);
}

.w-badge svg {
  width: calc(12 * var(--pt));
  height: calc(12 * var(--pt));
}

.w-location {
  gap: 0;
  overflow: hidden;
  padding: 0;
}

.w-location .w-head {
  padding: calc(16 * var(--pt)) calc(16 * var(--pt)) calc(10 * var(--pt));
}

.w-map {
  position: relative;
  flex: 1;
  overflow: hidden;
  background: #efeff4;
}

.w-map img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* The map dissolves under the header. */
.w-map::after {
  content: "";
  position: absolute;
  inset: 0 0 auto;
  height: calc(30 * var(--pt));
  background: linear-gradient(#fff, rgba(255, 255, 255, 0));
}

.w-temperature {
  padding: calc(14 * var(--pt));
}

.w-orange {
  color: #ff9500;
}

.w-readings {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  margin-top: auto;
}

.w-readings .w-figure {
  gap: calc(2 * var(--pt));
  margin: 0 !important;
}

.w-outside {
  text-align: end;
}

.w-outside .w-figure {
  justify-content: flex-end;
}

.w-fig26 {
  color: var(--secondary);
  font-family: var(--rounded);
  font-size: calc(26 * var(--pt));
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  line-height: 1;
}

.w-deg {
  font-size: calc(20 * var(--pt));
  font-weight: 600;
}

.w-deg-small {
  color: var(--tertiary);
  font-size: calc(16 * var(--pt));
  font-weight: 500;
}

.w-label {
  display: flex;
  align-items: center;
  gap: calc(4 * var(--pt));
  margin-top: calc(2 * var(--pt)) !important;
  color: var(--secondary);
  font-size: calc(11 * var(--pt));
  white-space: nowrap;
}

.w-label-faint {
  justify-content: flex-end;
  color: var(--tertiary);
}

.w-label svg {
  width: calc(11 * var(--pt));
  height: calc(11 * var(--pt));
}

.w-temp-bar {
  flex: none;
  height: calc(7 * var(--pt));
  border-radius: calc(4 * var(--pt));
  background: linear-gradient(90deg, rgba(255, 149, 0, 0.4), #ff9500);
}

.w-sentry {
  gap: calc(10 * var(--pt));
}

.w-sentry-state {
  margin-top: auto !important;
  color: var(--green);
  font-family: var(--rounded);
  font-size: calc(30 * var(--pt));
  font-weight: 700;
}

/* Charts: the ChartCard of the trip and charge screens, in SVG at the app's
   measures (a 16 pt card around a 338 × 160 pt chart). While a finger is on
   it, the title and figures give way to a bubble with the time and the value
   under the cursor, as in Health. discover.js draws and scrubs it. */
.w-chart {
  --pt: calc(100cqw / 370);
  --secondary: rgba(60, 60, 67, 0.6);
  position: relative;
  padding: calc(16 * var(--pt));
  border-radius: calc(16 * var(--pt));
  background: #fff;
  color: #000;
  font-family: -apple-system, BlinkMacSystemFont, "SF Pro Text", system-ui, sans-serif;
  line-height: 1.2;
  box-shadow:
    0 16px 28px rgba(14, 26, 36, 0.1),
    0 2px 5px rgba(14, 26, 36, 0.05);
}

.w-chart p {
  margin: 0;
}

.w-chart-head {
  position: relative;
  padding-bottom: calc(16 * var(--pt));
}

.w-chart-header {
  display: flex;
  flex-direction: column;
  gap: calc(12 * var(--pt));
  transition: opacity 0.2s ease;
}

.w-chart-title {
  font-size: calc(17 * var(--pt));
  font-weight: 600;
  line-height: 1.3;
}

.w-chart-summary {
  display: flex;
  gap: calc(24 * var(--pt));
}

.w-figure-sum {
  display: flex;
  flex-direction: column;
  gap: calc(2 * var(--pt));
}

.w-figure-sum span,
.w-readout > span {
  color: var(--secondary);
  font-size: calc(12 * var(--pt));
  font-weight: 500;
}

.w-figure-sum b {
  font-size: calc(17 * var(--pt));
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  line-height: 1.3;
}

/* The bubble is centred between the card's top edge and the chart. */
.w-readout-zone {
  position: absolute;
  inset: calc(-16 * var(--pt)) 0 0;
  display: flex;
  align-items: center;
  pointer-events: none;
}

.w-readout {
  display: flex;
  flex-direction: column;
  gap: calc(2 * var(--pt));
  padding: calc(8 * var(--pt)) calc(12 * var(--pt));
  border-radius: calc(10 * var(--pt));
  background: #f2f2f7;
  white-space: nowrap;
  opacity: 0;
  translate: var(--bubble-x, 0) 0;
  transition: opacity 0.2s ease;
}

.w-readout b {
  color: var(--chart);
  font-size: calc(22 * var(--pt));
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  line-height: 1.25;
}

.w-chart.is-scrubbing .w-chart-header {
  opacity: 0;
}

.w-chart.is-scrubbing .w-readout {
  opacity: 1;
}

.w-chart-svg {
  display: block;
  width: 100%;
  height: auto;
  overflow: visible;
}

.w-grid line {
  stroke: #e5e5ea;
  stroke-width: 0.5;
}

.w-axis text {
  fill: rgba(60, 60, 67, 0.3);
  font-size: 11px;
  font-variant-numeric: tabular-nums;
}

.w-line {
  fill: none;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.w-cursor {
  opacity: 0;
  transition: opacity 0.2s ease;
}

.w-cursor line {
  stroke: #c7c7cc;
  stroke-width: 1;
}

.w-chart.is-scrubbing .w-cursor {
  opacity: 1;
}

@media (min-width: 900px) {
  .d-story {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: 64px;
    padding: 0 32px;
  }

  .story-stage {
    position: sticky;
    top: 0;
    display: grid;
    place-items: center;
    height: 100vh;
    height: 100svh;
  }

  .story-stage .stage-panel {
    display: grid;
    /* The trip scene is the tallest, 1.6 times its width: with the 40 px
       padding, the panel never outgrows the screen. */
    width: min(100%, 500px, calc((100svh - 220px) * 0.62 + 80px));
  }

  .story-stage .scene {
    grid-area: 1 / 1;
    align-self: center;
  }

  .stage-halo {
    grid-area: 1 / 1;
  }

  /* A carousel: the chapter being read slides in whole from below while
     the one before leaves upwards (the other way when scrolling back).
     Scenes sit one panel height apart (--shift, set by discover.js), so
     the two move together and the panel is never empty. */
  .js .story-stage .scene {
    translate: 0 var(--shift, 120%);
    transition: translate 0.9s cubic-bezier(0.65, 0, 0.35, 1);
    will-change: translate;
  }

  .js .story-stage .scene.is-before {
    translate: 0 calc(-1 * var(--shift, 120%));
  }

  .js .story-stage .scene.is-active {
    translate: none;
  }

  .js .story-stage .scene.is-jumping {
    transition: none;
  }

  /* Driven by the scroll itself (discover.js): no transitions to lag. */
  .is-linked .story-stage .scene,
  .is-linked .stage-halo {
    transition: none !important;
  }

  .story-steps {
    grid-column: 2;
    grid-row: 1;
  }

  .story-step {
    display: flex;
    flex-direction: column;
    justify-content: center;
    min-height: 100vh;
    min-height: 100svh;
    padding: 0;
    text-align: start;
  }

  .story-step h2,
  .story-text {
    margin-inline: 0;
  }

  .story-text {
    margin-bottom: 0;
  }

  .story-inline {
    display: none;
  }

  /* The pause: each chapter's text stops in the middle of the screen for a
     third of a screen of scroll, then moves on. Sticky positioning holds it
     there (the browser's own scrolling, so it never trembles): the copy
     sticks with its centre on the middle of the screen (top 50 %, lifted
     by half its height), and the space after it is the length of the
     pause. Nothing is forced; the scroll keeps its pace. */
  .js .story-step {
    display: block;
    min-height: 0;
    padding-top: 50vh;
    padding-top: 50svh;
  }

  .js .story-step::after {
    content: "";
    display: block;
    height: 33vh;
    height: 33svh;
  }

  .js .story-copy {
    position: sticky;
    top: 50vh;
    top: 50svh;
    translate: 0 -50%;
  }

  /* The words scroll freely, as text does; the pinned scenes follow them
     (discover.js): the readable chapter's text is lit, the others dim. */
  .js .story-step {
    opacity: 0.25;
  }

  .js .story-step.is-active {
    opacity: 1;
  }
}

/* More -------------------------------------------------------------------- */

.d-more {
  max-width: var(--container);
  margin: 0 auto;
  padding: clamp(96px, 14vw, 160px) 20px 0;
}

.bento {
  display: grid;
  gap: 16px;
  margin-top: clamp(40px, 6vw, 64px);
}

.bento-tile {
  position: relative;
  overflow: hidden;
  padding: 32px 28px;
}

.bento-tile h3 {
  margin: 0;
  font-family: var(--font-display);
  font-size: clamp(1.375rem, 1.1rem + 0.8vw, 1.75rem);
  font-weight: 700;
  line-height: 1.15;
  letter-spacing: -0.022em;
  text-wrap: balance;
}

.bento-tile > p:not(.eyebrow),
.bento-copy > p:not(.eyebrow) {
  max-width: 34ch;
  margin: 10px 0 0;
  color: var(--ink-secondary);
  font-size: 17px;
  line-height: 1.45;
  text-wrap: pretty;
}

/* Pieces of the app on the app's own grey. */
.bento-app {
  background: #f2f2f7;
}

.bento-visual {
  position: relative;
  margin-top: 32px;
}

.bento-roadtrip {
  container-type: inline-size;
  width: min(440px, 100%);
  margin-inline: auto;
}

.bento-app {
  display: flex;
  flex-direction: column;
}

/* The road trip's map, in SVG: land and borders, the loop on real roads,
   the app's markers. When the tile comes in, the route draws itself leg by
   leg and each marker lands as the line reaches it. */
.rt-map {
  position: relative;
  border-radius: calc(18 * var(--pt));
}

.rt-map svg {
  display: block;
  width: 100%;
  height: auto;
  clip-path: inset(0 round calc(18 * var(--pt)));
}

/* Plans' colours at this scale: deep blue sea, paler along the shore,
   green land, fine mauve-grey borders, no line along the coast. */
.rt-water {
  fill: #3fb2ef;
}

.rt-shallows {
  fill: none;
  stroke: #8fd6f0;
  stroke-width: 3.2;
  stroke-linejoin: round;
}

.rt-land {
  fill: #c5eb9f;
}

.rt-borders {
  fill: none;
  stroke: #b49fb0;
  stroke-width: 0.5;
  stroke-linejoin: round;
}

/* The road trip's summary, in HTML at the app's measures (370 pt wide). */
.bento-roadtrip .scene {
  --pt: calc(100cqw / 370);
  gap: calc(12 * var(--pt));
}

.rt-card {
  position: relative;
  padding: calc(16 * var(--pt));
  border-radius: calc(18 * var(--pt));
  background: #fff;
  color: #000;
  font-family: -apple-system, BlinkMacSystemFont, "SF Pro Text", system-ui, sans-serif;
  line-height: 1.2;
}

/* Every shadow of the stack on one plane, under all the cards: none of
   them is half covered by the card after it, the map's included. */
.bento-roadtrip .scene {
  isolation: isolate;
}

.rt-card::before,
.rt-map::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  border-radius: inherit;
  box-shadow:
    0 16px 28px rgba(14, 26, 36, 0.1),
    0 2px 5px rgba(14, 26, 36, 0.05);
}

.rt-card p {
  margin: 0;
}

.rt-caption {
  color: rgba(60, 60, 67, 0.6);
  font-size: calc(13 * var(--pt));
  font-weight: 500;
}

.rt-figure {
  display: flex;
  gap: calc(5 * var(--pt));
  align-items: baseline;
  margin-top: calc(2 * var(--pt)) !important;
  color: #0062e6;
  font-family: ui-rounded, "SF Pro Rounded", -apple-system, BlinkMacSystemFont, system-ui, sans-serif;
  font-weight: 700;
}

.rt-figure span {
  font-size: calc(34 * var(--pt));
  font-variant-numeric: tabular-nums;
  line-height: 1.2;
}

.rt-figure small {
  font-size: calc(20 * var(--pt));
  font-weight: 600;
}

.rt-counts {
  margin-top: calc(4 * var(--pt)) !important;
  color: rgba(60, 60, 67, 0.6);
  font-size: calc(15 * var(--pt));
}

.rt-tiles {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: calc(12 * var(--pt));
}

.rt-tile-head {
  display: flex;
  gap: calc(8 * var(--pt));
  align-items: center;
  font-size: calc(13 * var(--pt));
  font-weight: 600;
}

.rt-tile-head span {
  display: grid;
}

.rt-tile-head svg {
  width: calc(14 * var(--pt));
  height: calc(14 * var(--pt));
}

.rt-tile-value {
  margin-top: calc(8 * var(--pt)) !important;
  font-family: ui-rounded, "SF Pro Rounded", -apple-system, BlinkMacSystemFont, system-ui, sans-serif;
  font-size: calc(24 * var(--pt));
  font-variant-numeric: tabular-nums;
  font-weight: 700;
  white-space: nowrap;
}

.rt-tile-detail {
  margin-top: calc(2 * var(--pt)) !important;
  color: rgba(60, 60, 67, 0.6);
  font-size: calc(12 * var(--pt));
}

.rt-casing,
.rt-leg {
  fill: none;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.rt-casing {
  stroke: #fff;
  stroke-width: 3;
  opacity: 0.9;
}

.rt-leg {
  stroke: #0062e6;
  stroke-width: 1.5;
}

.rt-marker {
  filter: drop-shadow(0 0.5px 0.8px rgba(0, 0, 0, 0.25));
}

.rt-marker text {
  fill: #fff;
  font: 700 5.6px -apple-system, BlinkMacSystemFont, "SF Pro Text", system-ui, sans-serif;
  text-anchor: middle;
}

.js [data-reveal] .rt-casing {
  opacity: 0;
  transition: opacity 0.6s ease 0.2s;
}

.js [data-reveal] .rt-leg {
  stroke-dasharray: 1;
  stroke-dashoffset: 1;
}

.js [data-reveal] .rt-marker {
  opacity: 0;
  scale: 0.4;
}

.js .is-visible .rt-casing {
  opacity: 0.9;
}

.js .is-visible .rt-leg {
  animation: rt-leg var(--d) linear var(--t) forwards;
}

.js .is-visible .rt-marker {
  animation: rt-marker 0.45s cubic-bezier(0.34, 1.56, 0.64, 1) var(--t) forwards;
}

@keyframes rt-leg {
  to {
    stroke-dashoffset: 0;
  }
}

@keyframes rt-marker {
  to {
    opacity: 1;
    scale: 1;
  }
}

/* Sentry, Bluetooth key, range at 100 %: pieces of the app in HTML, at
   its measures (370 pt, 1 pt = var(--pt)), on the app's grey. */
.bento-sentry,
.bento-key,
.bento-battery-card {
  container-type: inline-size;
  width: min(440px, 100%);
  margin-inline: auto;
}

.s-scene,
.k-scene,
.bt-card {
  --pt: calc(100cqw / 370);
  --secondary: rgba(60, 60, 67, 0.6);
  --tertiary: rgba(60, 60, 67, 0.3);
  color: #000;
  font-family: -apple-system, BlinkMacSystemFont, "SF Pro Text", system-ui, sans-serif;
  line-height: 1.25;
  text-align: start;
}

:is(.s-scene, .k-scene, .bt-card) p {
  margin: 0;
}

:is(.s-scene, .k-scene, .bt-card) svg {
  display: block;
}

/* Range at 100 %: the Battery Health card. */
.bt-card {
  padding: calc(16 * var(--pt));
  border-radius: calc(16 * var(--pt));
  background: #fff;
  box-shadow:
    0 16px 28px rgba(14, 26, 36, 0.1),
    0 2px 5px rgba(14, 26, 36, 0.05);
}

.bt-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-size: calc(17 * var(--pt));
}

.bt-head b {
  font-weight: 600;
}

.bt-head span {
  color: var(--secondary);
}

.bt-head svg {
  width: calc(17 * var(--pt));
  height: calc(17 * var(--pt));
}

.bt-figure {
  margin-top: calc(6 * var(--pt)) !important;
  font-size: calc(22 * var(--pt));
  font-variant-numeric: tabular-nums;
  font-weight: 600;
}

.bt-chart {
  width: 100%;
  height: auto;
  margin-top: calc(16 * var(--pt));
  overflow: visible;
}

.bt-dots circle {
  fill: #00a99d;
  fill-opacity: 0.4;
}

.bt-trend {
  fill: none;
  stroke: #00a99d;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.bt-legend {
  display: flex;
  gap: calc(12 * var(--pt));
  margin-top: calc(16 * var(--pt)) !important;
  padding-left: calc(34 * var(--pt));
  color: var(--tertiary);
  font-size: calc(11 * var(--pt));
}

.bt-legend span {
  display: flex;
  gap: calc(5 * var(--pt));
  align-items: center;
}

.bt-dot {
  width: calc(5 * var(--pt));
  height: calc(5 * var(--pt));
  border-radius: 50%;
  background: rgba(0, 169, 157, 0.4);
}

.bt-bar {
  width: calc(11 * var(--pt));
  height: calc(2 * var(--pt));
  border-radius: 99px;
  background: #00a99d;
}

/* The measurements come in from the oldest, then the average draws over
   them. */
.js [data-reveal] .bt-dots circle {
  opacity: 0;
}

.js .is-visible .bt-dots circle {
  animation: bt-dot 0.35s ease-out var(--d) forwards;
}

@keyframes bt-dot {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

.js [data-reveal] .bt-reveal {
  transform: scaleX(0);
  transform-origin: 30px 0;
}

.js .is-visible .bt-reveal {
  animation: bt-reveal 1.4s cubic-bezier(0.65, 0, 0.35, 1) 0.9s forwards;
}

@keyframes bt-reveal {
  to {
    transform: scaleX(1);
  }
}

/* Bluetooth key: the status card, the app's toast, the Home buttons. */
.k-scene {
  display: flex;
  flex-direction: column;
  gap: calc(12 * var(--pt));
}

.k-status {
  display: flex;
  gap: calc(14 * var(--pt));
  align-items: flex-start;
  padding: calc(16 * var(--pt));
  border-radius: calc(16 * var(--pt));
  background: #fff;
  box-shadow:
    0 16px 28px rgba(14, 26, 36, 0.1),
    0 2px 5px rgba(14, 26, 36, 0.05);
}

.k-badge {
  display: grid;
  flex: none;
  place-items: center;
  width: calc(44 * var(--pt));
  height: calc(44 * var(--pt));
  border-radius: 50%;
  background: rgba(0, 98, 230, 0.14);
  color: #0062e6;
}

.k-badge svg {
  width: calc(26 * var(--pt));
  height: calc(26 * var(--pt));
}

.k-status p {
  display: flex;
  flex-direction: column;
  gap: calc(4 * var(--pt));
}

.k-status b {
  font-size: calc(17 * var(--pt));
  font-weight: 600;
}

.k-status p > span {
  color: var(--secondary);
  font-size: calc(15 * var(--pt));
}

/* The toast drops in from the top, as the app's does. */
.k-toast-slot {
  height: calc(52 * var(--pt));
}

.k-toast {
  display: flex;
  gap: calc(10 * var(--pt));
  align-items: center;
  width: fit-content;
  max-width: 100%;
  margin-inline: auto !important;
  padding: calc(12 * var(--pt)) calc(16 * var(--pt)) calc(12 * var(--pt)) calc(12 * var(--pt));
  border-radius: calc(20 * var(--pt));
  background: rgba(255, 255, 255, 0.86);
  box-shadow:
    0 calc(8 * var(--pt)) calc(16 * var(--pt)) rgba(0, 0, 0, 0.08),
    0 0 0 0.5px rgba(0, 0, 0, 0.04);
  font-size: calc(15 * var(--pt));
  font-weight: 500;
  opacity: 0;
  translate: 0 calc(-24 * var(--pt));
  scale: 0.96;
  transition:
    opacity 0.3s ease,
    translate 0.3s ease,
    scale 0.3s ease;
}

.k-toast.is-shown {
  opacity: 1;
  translate: none;
  scale: 1;
  transition:
    opacity 0.25s ease,
    translate 0.45s cubic-bezier(0.34, 1.4, 0.64, 1),
    scale 0.45s cubic-bezier(0.34, 1.4, 0.64, 1);
}

.k-toast i {
  display: grid;
  flex: none;
  place-items: center;
  width: calc(28 * var(--pt));
  height: calc(28 * var(--pt));
  border-radius: 50%;
  background: linear-gradient(#2fc285, #0fa968);
}

.k-toast i svg {
  width: calc(15 * var(--pt));
  height: calc(15 * var(--pt));
}

.k-buttons {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: calc(10 * var(--pt));
}

.k-button {
  position: relative;
  display: grid;
  place-items: center;
  height: calc(60 * var(--pt));
  border-radius: calc(14 * var(--pt));
  background: #fff;
  box-shadow: 0 calc(3 * var(--pt)) calc(12 * var(--pt)) rgba(0, 0, 0, 0.06);
  color: #000;
  transition: color 0.25s ease;
}

.k-icon {
  display: grid;
  width: calc(24 * var(--pt));
  height: calc(24 * var(--pt));
  transition: opacity 0.15s ease;
}

.k-icon svg {
  grid-area: 1 / 1;
  width: 100%;
  height: 100%;
}

/* Locked: a closed padlock; unlocked counts as active and turns blue. */
.k-lock svg:last-child,
.k-button.is-active .k-lock svg:first-child {
  opacity: 0;
}

.k-button.is-active .k-lock svg:last-child {
  opacity: 1;
}

.k-lock svg {
  transition: opacity 0.2s ease;
}

.k-button.is-active,
.k-button.is-blink {
  color: #0062e6;
}

.k-button.is-tapped .k-icon {
  animation: k-bounce 0.35s ease;
}

@keyframes k-bounce {
  40% {
    scale: 0.82;
  }
  75% {
    scale: 1.08;
  }
}

.k-spinner {
  position: absolute;
  width: calc(20 * var(--pt));
  height: calc(20 * var(--pt));
  color: #8e8e93;
  opacity: 0;
  animation: spin 0.8s steps(8) infinite;
}

.k-button.is-sending .k-icon {
  opacity: 0;
}

.k-button.is-sending .k-spinner {
  opacity: 1;
}

/* Sentry: Copeel's notification, then the detection it tells of. */
.s-scene {
  display: flex;
  flex-direction: column;
  gap: calc(14 * var(--pt));
}

.s-notif {
  display: flex;
  gap: calc(10 * var(--pt));
  align-items: flex-start;
  padding: calc(12 * var(--pt)) calc(14 * var(--pt));
  border-radius: calc(22 * var(--pt));
  background: rgba(255, 255, 255, 0.9);
  box-shadow:
    0 16px 28px rgba(14, 26, 36, 0.12),
    0 2px 5px rgba(14, 26, 36, 0.05);
  font-size: calc(15 * var(--pt));
  line-height: 1.3;
}

.s-notif img {
  flex: none;
  width: calc(38 * var(--pt));
  height: calc(38 * var(--pt));
  border-radius: calc(9 * var(--pt));
}

.s-notif > div {
  flex: 1;
  min-width: 0;
}

.s-notif-top {
  display: flex;
  justify-content: space-between;
  gap: calc(8 * var(--pt));
}

.s-notif-top strong {
  font-weight: 600;
}

.s-notif-top time {
  color: var(--secondary);
  font-size: calc(13 * var(--pt));
}

.s-notif-sub {
  font-weight: 600;
}

.s-card {
  display: flex;
  gap: calc(12 * var(--pt));
  padding: calc(12 * var(--pt));
  border-radius: calc(14 * var(--pt));
  background: #fff;
  box-shadow:
    0 16px 28px rgba(14, 26, 36, 0.1),
    0 2px 5px rgba(14, 26, 36, 0.05);
}

.s-map {
  position: relative;
  display: grid;
  flex: none;
  place-items: center;
  overflow: hidden;
  width: calc(90 * var(--pt));
  height: calc(90 * var(--pt));
  border-radius: calc(10 * var(--pt));
  background: #efeff4;
}

.s-map img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 22% 70%;
  scale: 1.6;
}

/* The app's pin: a red rounded square with a bell, on a little point. */
.s-pin {
  position: relative;
  display: grid;
  place-items: center;
  width: calc(21 * var(--pt));
  height: calc(21 * var(--pt));
  margin-top: calc(-8 * var(--pt));
  border-radius: calc(5 * var(--pt));
  background: #ff3b30;
  box-shadow: 0 calc(1.5 * var(--pt)) calc(3 * var(--pt)) rgba(0, 0, 0, 0.25);
}

.s-pin::after {
  content: "";
  position: absolute;
  bottom: calc(-3.5 * var(--pt));
  left: 50%;
  border: calc(3.5 * var(--pt)) solid transparent;
  border-bottom: 0;
  border-top-color: #ff3b30;
  translate: -50% 0;
}

.s-pin svg {
  width: calc(11 * var(--pt));
  height: calc(11 * var(--pt));
}

.s-text {
  display: flex;
  flex: 1;
  flex-direction: column;
  gap: calc(5 * var(--pt));
  min-width: 0;
}

.s-city {
  display: flex;
  gap: calc(6 * var(--pt));
  align-items: center;
  font-size: calc(16 * var(--pt));
}

.s-city b {
  font-weight: 600;
}

.s-count,
.s-level {
  padding: calc(3 * var(--pt)) calc(6 * var(--pt));
  border-radius: 99px;
  background: rgba(255, 59, 48, 0.15);
  color: #ff3b30;
  font-size: calc(11 * var(--pt));
  font-weight: 700;
}

.s-level {
  padding-inline: calc(7 * var(--pt));
  font-weight: 600;
}

.s-address {
  color: var(--secondary);
  font-size: calc(13 * var(--pt));
  font-weight: 500;
}

.s-bottom {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-top: auto !important;
  color: var(--secondary);
  font-size: calc(13 * var(--pt));
}

/* The notification lands, then the detection rises under it, its pin
   dropping on the map. */
.js [data-reveal] .s-notif {
  opacity: 0;
  translate: 0 calc(-30 * var(--pt));
  scale: 0.94;
}

.js [data-reveal] .s-card {
  opacity: 0;
  translate: 0 calc(16 * var(--pt));
}

.js [data-reveal] .s-pin {
  opacity: 0;
  translate: 0 calc(-14 * var(--pt));
}

.js .is-visible .s-notif {
  animation: s-land 0.6s cubic-bezier(0.34, 1.3, 0.64, 1) 0.4s forwards;
}

.js .is-visible .s-card {
  animation: s-rise 0.6s cubic-bezier(0.22, 1, 0.36, 1) 1.5s forwards;
}

.js .is-visible .s-pin {
  animation: s-pin 0.5s cubic-bezier(0.34, 1.56, 0.64, 1) 1.9s forwards;
}

@keyframes s-land {
  to {
    opacity: 1;
    translate: none;
    scale: 1;
  }
}

@keyframes s-rise {
  to {
    opacity: 1;
    translate: none;
  }
}

@keyframes s-pin {
  to {
    opacity: 1;
    translate: none;
  }
}

/* Supercharger passport: no screen in the app yet, so a card in its
   language: the count, the progress, every station of the catalogue on
   the map of France, the ones charged at in red, the latest stamps as the
   app draws them. */
.bento-passport-card {
  container-type: inline-size;
  width: min(460px, 100%);
  margin-inline: auto;
}

.bento-passport .eyebrow {
  --accent: var(--red);
}

.pp-card {
  --pt: calc(100cqw / 370);
  --red: #ff3b30;
  padding: calc(16 * var(--pt));
  border-radius: calc(18 * var(--pt));
  background: #fff;
  color: #000;
  font-family: -apple-system, BlinkMacSystemFont, "SF Pro Text", system-ui, sans-serif;
  line-height: 1.25;
  text-align: start;
  box-shadow:
    0 16px 28px rgba(14, 26, 36, 0.1),
    0 2px 5px rgba(14, 26, 36, 0.05);
}

.pp-card p {
  margin: 0;
}

.pp-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: calc(8 * var(--pt));
  font-size: calc(17 * var(--pt));
}

.pp-head b {
  font-weight: 600;
}

.pp-head span {
  color: rgba(60, 60, 67, 0.6);
  font-size: calc(13 * var(--pt));
  white-space: nowrap;
}

.pp-count {
  display: flex;
  gap: calc(6 * var(--pt));
  align-items: baseline;
  margin-top: calc(6 * var(--pt)) !important;
}

.pp-count b {
  color: var(--red);
  font-family: ui-rounded, "SF Pro Rounded", -apple-system, BlinkMacSystemFont, system-ui, sans-serif;
  font-size: calc(34 * var(--pt));
  font-variant-numeric: tabular-nums;
  font-weight: 700;
  line-height: 1.1;
}

.pp-count span {
  color: rgba(60, 60, 67, 0.6);
  font-size: calc(15 * var(--pt));
}

.pp-bar {
  display: block;
  overflow: hidden;
  height: calc(6 * var(--pt));
  margin-top: calc(10 * var(--pt));
  border-radius: 99px;
  background: #e5e5ea;
}

.pp-bar i {
  display: block;
  height: 100%;
  border-radius: inherit;
  background: linear-gradient(90deg, rgba(255, 59, 48, 0.78), var(--red));
}

.pp-map {
  position: relative;
  margin-top: calc(10 * var(--pt));
  margin-bottom: calc(46 * var(--pt));
}

.pp-map svg {
  display: block;
  width: 100%;
  height: auto;
}

.pp-others {
  fill: #f5f5f7;
}

.pp-france {
  fill: #ebebf0;
  stroke: #dcdce2;
  stroke-width: 0.6;
  stroke-linejoin: round;
}

.pp-grey circle {
  fill: #c3c3ca;
}

.pp-red circle {
  fill: var(--red);
  stroke: #fff;
  stroke-width: 0.8;
}

/* The latest stamps, below the coast: over the sea and Spain, clear of
   the collected stations, and spilling under the map. */
.pp-stamps {
  position: absolute;
  top: 84%;
  right: 0;
  left: 0;
  display: flex;
  justify-content: space-around;
}

.pp-stamp {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: calc(5 * var(--pt));
  rotate: var(--r);
}

.pp-disc {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  width: calc(58 * var(--pt));
  height: calc(58 * var(--pt));
  border-radius: 50%;
  background: linear-gradient(135deg, var(--red), rgba(255, 59, 48, 0.78));
  box-shadow: 0 calc(4 * var(--pt)) calc(10 * var(--pt)) rgba(255, 59, 48, 0.35);
  color: #fff;
}

.pp-disc::before {
  content: "";
  position: absolute;
  inset: calc(4 * var(--pt));
  border: 1.5px solid rgba(255, 255, 255, 0.45);
  border-radius: 50%;
}

.pp-disc svg {
  width: calc(15 * var(--pt));
  height: calc(15 * var(--pt));
}

.pp-disc b {
  font-family: ui-rounded, "SF Pro Rounded", -apple-system, BlinkMacSystemFont, system-ui, sans-serif;
  font-size: calc(9.5 * var(--pt));
  font-weight: 800;
  letter-spacing: 0.04em;
}

/* The green seal of a collected station. */
.pp-seal {
  position: absolute;
  top: calc(-2 * var(--pt));
  right: calc(-2 * var(--pt));
  width: calc(18 * var(--pt));
  height: calc(18 * var(--pt));
  border: calc(2 * var(--pt)) solid #fff;
  border-radius: 50%;
  background: #0fa968 url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='m6.5 12.5 3.6 3.6 7.4-8' fill='none' stroke='%23fff' stroke-width='3.4' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center / 70% no-repeat;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.15);
}

.pp-label {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: calc(2 * var(--pt)) calc(7 * var(--pt));
  border-radius: calc(8 * var(--pt));
  background: rgba(255, 255, 255, 0.85);
  line-height: 1.2;
}

.pp-label b {
  font-size: calc(11 * var(--pt));
  font-weight: 600;
}

.pp-label small {
  color: rgba(60, 60, 67, 0.4);
  font-size: calc(10 * var(--pt));
}

/* The collected stations light up along the route, then the stamps come
   down one after the other, like a stamp on paper. */
.js [data-reveal] .pp-red circle {
  opacity: 0;
  transform-box: fill-box;
  transform-origin: center;
}

.js .is-visible .pp-red circle {
  animation: pp-dot 0.4s cubic-bezier(0.34, 1.56, 0.64, 1) calc(0.3s + var(--n) * 55ms) forwards;
}

@keyframes pp-dot {
  from {
    opacity: 0;
    scale: 0.2;
  }
  to {
    opacity: 1;
    scale: 1;
  }
}

.js [data-reveal] .pp-stamp {
  opacity: 0;
}

.js .is-visible .pp-stamp {
  animation: pp-stamp 0.5s cubic-bezier(0.2, 0.8, 0.3, 1) calc(1.7s + var(--n) * 0.28s) forwards;
}

@keyframes pp-stamp {
  0% {
    opacity: 0;
    scale: 1.5;
    rotate: calc(var(--r) - 12deg);
  }
  55% {
    opacity: 1;
    scale: 0.93;
  }
  100% {
    opacity: 1;
    scale: 1;
    rotate: var(--r);
  }
}

.js [data-reveal] .pp-bar i {
  scale: 0 1;
  transform-origin: left;
}

.js .is-visible .pp-bar i {
  animation: pp-bar 1.4s cubic-bezier(0.65, 0, 0.35, 1) 0.3s forwards;
}

@keyframes pp-bar {
  to {
    scale: 1 1;
  }
}

/* The dial sits in the middle of whatever height the row gives its tile. */
.bento-tariff {
  display: grid;
  flex: 1;
  place-items: center;
}

/* The tariff dial, redrawn from the app: the slots draw themselves, then a
   hand runs round the day while the centre shows the hour and its price.
   The centre's type is in container units, so it scales with the dial. */
.dial {
  container-type: inline-size;
  position: relative;
  width: min(300px, 82%);
  aspect-ratio: 1;
}

.dial svg {
  display: block;
  width: 100%;
  height: 100%;
  overflow: visible;
}

.dial-track {
  fill: none;
  stroke: rgba(60, 60, 67, 0.08);
  stroke-width: 30;
}

.dial-arc {
  fill: none;
  stroke: var(--c);
  stroke-width: 30;
  stroke-dasharray: var(--len) 24;
  stroke-dashoffset: calc(var(--from) * -1);
}

/* The script fills the arcs itself; the slots not in force step back. */
.dial-arc {
  transition: opacity 0.5s var(--ease-apple);
}

.dial-arc.is-dim {
  opacity: 0.32;
}

/* The centre gives a small nod when the slot changes. */
.dial-centre.is-changing {
  animation: slot-change 0.6s var(--ease-apple);
}

@keyframes slot-change {
  0% {
    scale: 1;
  }
  35% {
    scale: 1.08;
  }
  100% {
    scale: 1;
  }
}

.dial-tick {
  stroke: rgba(60, 60, 67, 0.3);
  stroke-width: 1.2;
  stroke-linecap: round;
}

.dial-tick.major {
  stroke: rgba(60, 60, 67, 0.55);
  stroke-width: 1.6;
}

.dial-hour {
  fill: rgba(60, 60, 67, 0.6);
  font-family: var(--font-text);
  font-size: 11px;
  font-weight: 600;
  text-anchor: middle;
}

/* The ends of the slot being adjusted, as the editor draws them. */
.dial-knob {
  fill: #fff;
  stroke: rgba(0, 0, 0, 0.06);
  stroke-width: 1;
  filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.25));
  opacity: 0;
  transition: opacity 0.35s var(--ease-apple);
}

.dial.is-editing .dial-knob {
  opacity: 1;
}

/* The end being dragged is held a little larger. */
.dial-knob.is-grabbed {
  stroke: rgba(0, 0, 0, 0.12);
  stroke-width: 6;
}

.dial-centre {
  position: absolute;
  inset: 28%;
  display: grid;
  place-content: center;
  text-align: center;
}

.dial-centre p {
  margin: 0;
}

.dial-label {
  color: var(--slot, #ff9500);
  font-size: 4.3cqw;
  font-weight: 600;
  transition: color 0.4s;
}

.dial-time {
  margin: 0.5cqw 0 !important;
  font-family: var(--font-display);
  font-size: 8.6cqw;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.02em;
}

.dial-price {
  min-height: 1.3em;
  color: var(--ink-secondary);
  font-size: 4.3cqw;
  font-variant-numeric: tabular-nums;
}

/* Tempo, on the French page: today's and tomorrow's colour, under the dial. */
.el-tempo {
  position: relative;
  width: min(330px, 92%);
  margin-top: 20px;
}

/* Notifications: the lock screen of the app's onboarding. */
.bento-wide {
  display: grid;
  gap: 32px;
  align-items: center;
  padding-bottom: 0;
}

.lockscreen {
  position: relative;
  width: min(340px, 100%);
  margin: 0 auto;
  padding: 28px 12px 14px;
  overflow: hidden;
  border-radius: 40px 40px 0 0;
  background:
    radial-gradient(70% 45% at 12% 4%, rgba(56, 217, 181, 0.38), transparent 70%),
    radial-gradient(75% 50% at 92% 100%, rgba(245, 117, 194, 0.32), transparent 70%),
    linear-gradient(180deg, #0d3338 0%, #121418 50%, #38122e 100%);
  color: rgba(255, 255, 255, 0.92);
  text-align: center;
  box-shadow: 0 30px 60px -30px rgba(14, 26, 36, 0.5);
}

.lock-date {
  margin: 0;
  font-size: 16px;
  font-weight: 600;
}

.lock-time {
  margin: 0 0 56px;
  font-family: ui-rounded, "SF Pro Rounded", var(--font-display);
  font-size: 84px;
  font-weight: 600;
  line-height: 1;
  letter-spacing: -0.02em;
}

.lock-stack {
  display: grid;
  gap: 8px;
}

.notif {
  display: flex;
  gap: 10px;
  align-items: flex-start;
  padding: 11px 12px;
  border-radius: 22px;
  background: rgba(255, 255, 255, 0.16);
  -webkit-backdrop-filter: blur(24px) saturate(160%);
  backdrop-filter: blur(24px) saturate(160%);
  box-shadow: inset 0 0 0 0.5px rgba(255, 255, 255, 0.22);
  text-align: start;
}

.notif img {
  flex: none;
  width: 38px;
  height: 38px;
  border-radius: 9px;
}

.notif div {
  min-width: 0;
  flex: 1;
}

.notif p {
  margin: 0;
  font-size: 13.5px;
  line-height: 1.3;
}

.notif-top {
  display: flex;
  gap: 6px;
  justify-content: space-between;
  align-items: baseline;
}

.notif-top strong {
  min-width: 0;
  font-weight: 600;
  overflow-wrap: anywhere;
}

.notif time {
  flex: none;
  color: rgba(255, 255, 255, 0.55);
  font-size: 12px;
}

/* The notifications land one after the other when the tile comes in. */
.js .notif {
  opacity: 0;
  translate: 0 -24px;
  scale: 0.96;
  transition:
    opacity 0.6s var(--ease-apple),
    translate 0.7s var(--ease-apple),
    scale 0.7s var(--ease-apple);
}

.js .notif.is-in {
  opacity: 1;
  translate: 0 0;
  scale: 1;
}

/* Range: the app's map, cut out, as it is. The rings that say "how far"
   spread from the tile's top corner, behind the words, not over the map. */
.range-visual {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  width: min(440px, 100%);
  margin-inline: auto;
  border-radius: 20px;
  box-shadow:
    0 16px 28px rgba(14, 26, 36, 0.1),
    0 2px 5px rgba(14, 26, 36, 0.05);
}

/* Framed to the height of the battery card beside it: the reachable area
   and the car stay in view, the card sits on the map's lower edge. */
.range-map {
  display: block;
  width: 100%;
  height: auto;
  /* The battery card's own proportions (292.5 pt tall for 370 wide), so the
     two visuals of the row are the same size. */
  aspect-ratio: 370 / 292.5;
  object-fit: cover;
  object-position: 50% 82%;
}

.range-rings {
  position: absolute;
  top: 0;
  left: 0;
  z-index: -1;
  pointer-events: none;
}

.range-ring {
  position: absolute;
  top: 0;
  left: 0;
  width: min(1100px, 190vw);
  aspect-ratio: 1;
  border: 1.25px solid color-mix(in srgb, var(--red) 42%, transparent);
  border-radius: 50%;
  translate: -50% -50%;
  opacity: 0;
  animation: ring 12s cubic-bezier(0.2, 0.6, 0.35, 1) infinite;
}

.range-ring:nth-child(2) {
  animation-delay: 4s;
}

.range-ring:nth-child(3) {
  animation-delay: 8s;
}

@keyframes ring {
  0% {
    opacity: 0;
    scale: 0.05;
  }
  12% {
    opacity: 1;
  }
  100% {
    opacity: 0;
    scale: 1;
  }
}

.range-card {
  position: absolute;
  right: 4%;
  bottom: 4%;
  left: 4%;
  z-index: 2;
  width: 92%;
  height: auto;
  filter: drop-shadow(0 10px 20px rgba(14, 26, 36, 0.18));
}

.bento-range {
  padding-bottom: 28px;
}

.bento-range .eyebrow {
  --accent: var(--red);
}

.bento-battery .eyebrow {
  --accent: #00a99d;
}

.bento-app > .eyebrow {
  margin: 0 0 8px;
}

/* Battery and range share a row: their visuals sit at the foot of the
   tiles, aligned, whatever the length of the words above them. */
:is(.bento-battery, .bento-range) > p:last-of-type {
  margin-bottom: 32px;
}

:is(.bento-battery, .bento-range) > .bento-visual {
  margin-top: auto;
}

.bento-battery {
  padding-bottom: 28px;
}

@media (min-width: 760px) {
  .bento {
    grid-template-columns: 1fr 1fr;
  }

  .bento-tile {
    padding: 40px;
  }

  .bento-wide {
    padding-bottom: 0;
  }

  .bento-wide {
    grid-column: 1 / -1;
    grid-template-columns: 1fr 1fr;
    padding-top: 56px;
  }

  .bento-wide .bento-copy {
    align-self: center;
    padding-bottom: 40px;
  }

  .bento-wide h3 {
    font-size: var(--text-title);
  }

  .bento-range,
  .bento-battery {
    padding-bottom: 40px;
  }
}

/* Intelligence ------------------------------------------------------------ */

/* The one dark moment of the page. Its tile stays pinned for three quarters of a
   screen of scroll (the conversation plays on its own, the pin only lets
   it be seen settled), while on the app's own screen rebuilt in HTML four
   questions are asked and answered one after the other. */
.d-intel {
  --steps: 1;
  position: relative;
  height: calc(100vh + var(--steps) * 75vh);
  height: calc(100svh + var(--steps) * 75svh);
  margin: clamp(96px, 14vw, 160px) auto 0;
}

.intel-pin {
  position: sticky;
  top: 0;
  display: grid;
  height: 100vh;
  height: 100svh;
  max-width: var(--container-wide);
  margin: 0 auto;
  padding: calc(var(--header-h) + 12px) 12px 12px;
}

.intel-tile {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  display: grid;
  grid-template-rows: auto 1fr;
  gap: 20px;
  padding: clamp(24px, 5vw, 56px) 16px 0;
  background: #050608;
  color: #f5f5f7;
  text-align: center;
}

.intel-copy {
  max-width: 520px;
  margin: 0 auto;
}

/* The eyebrow carries the app's sparkles, and the light that runs over
   "Réflexion…" while the app thinks. */
.intel-eyebrow {
  display: inline-flex;
  gap: 8px;
  align-items: center;
  background: linear-gradient(90deg, #6ea9f7 40%, #fff 50%, #6ea9f7 60%) 0 0 / 250% 100%;
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  animation: shimmer 3.6s linear infinite;
}

.intel-sparkle {
  display: inline-grid;
  color: #6ea9f7;
}

.intel-sparkle svg {
  width: 20px;
  height: 20px;
}

.intel-copy h2 {
  font-size: clamp(1.75rem, 1.1rem + 2.6vw, 3.5rem);
}

.intel-copy > p:not(.eyebrow):not(.intel-dots) {
  margin: 14px 0 0;
  color: rgba(245, 245, 247, 0.62);
  font-size: var(--text-lead);
  line-height: 1.4;
}

/* Where the reader is in the sequence. */
.intel-dots {
  display: flex;
  gap: 8px;
  justify-content: center;
  margin: 24px 0 0;
}

.intel-dots i {
  width: 8px;
  height: 8px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.25);
  transition:
    width 0.4s var(--ease-apple),
    background-color 0.4s var(--ease-apple);
}

.intel-dots i.is-active {
  width: 28px;
  background: #fff;
}

/* The screen sits at the bottom of the stage on phones, in the middle of
   its column on wide screens, sized so it always fits. */
.intel-stage {
  container-type: size;
  position: relative;
  display: grid;
  place-items: end center;
  min-height: 0;
}

/* A low blue light behind the screen, brighter while the app thinks. */
.intel-glow {
  position: absolute;
  left: 50%;
  bottom: 10%;
  width: min(760px, 160cqw);
  aspect-ratio: 1;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(0, 98, 230, 0.42), rgba(0, 98, 230, 0.12) 38%, transparent 66%);
  opacity: 0.55;
  translate: -50% 40%;
  transition:
    opacity 1.2s var(--ease-apple),
    scale 1.2s var(--ease-apple);
  pointer-events: none;
}

.intel-stage.is-thinking .intel-glow {
  opacity: 1;
  scale: 1.08;
}

@media (max-width: 639px) {
  .intel-tile {
    gap: 16px;
    padding: 24px 8px 0;
  }

  .intel-copy > p:not(.eyebrow):not(.intel-dots) {
    display: none;
  }

  .intel-dots {
    margin-top: 14px;
  }
}

/* Short phones: the title alone, so the screen keeps its room. */
@media (max-width: 639px) and (max-height: 700px) {
  .intel-eyebrow {
    display: none;
  }

  .intel-copy h2 {
    font-size: 1.5rem;
  }

  .intel-dots {
    margin-top: 10px;
  }
}

@media (min-width: 900px) {
  .intel-tile {
    grid-template-columns: 1fr 1fr;
    grid-template-rows: 1fr;
    padding: 0 clamp(48px, 6vw, 96px);
    text-align: start;
  }

  .intel-copy {
    align-self: center;
    margin: 0;
  }

  .intel-dots {
    justify-content: flex-start;
  }

  .intel-stage {
    place-items: center;
  }

  .intel-glow {
    bottom: 50%;
    translate: -50% 50%;
  }
}

/* Apple's iPhone 18 Pro Max bezel (Apple Design Resources), as Apple
   asks: upright, whole, unaltered, no added shadow. Its screen is
   transparent: the app's screen, in HTML, sits beneath it at the
   bezel's own measures (1320 × 2868 px at 75, 66 in a 1470 × 3000 image),
   the Dynamic Island coming from the image. The phone is sized by the room
   it has and never cut. */
.ai-phone {
  --fw: min(400px, 92cqw, calc((100cqh - 20px) * 1470 / 3000));
  position: relative;
  flex: none;
  width: var(--fw);
  aspect-ratio: 1470 / 3000;
  align-self: start;
}

@media (min-width: 900px) {
  .ai-phone {
    --fw: min(400px, 92cqw, calc((100cqh - 72px) * 1470 / 3000));
    align-self: center;
  }
}

.ai-bezel {
  position: absolute;
  inset: 0;
  z-index: 4;
  width: 100%;
  height: 100%;
  pointer-events: none;
  user-select: none;
  -webkit-user-drag: none;
}

/* The screen, 440 pt wide; 1 pt is var(--pt). */
.ai-screen {
  --sw: calc(var(--fw) * 1320 / 1470);
  --pt: calc(var(--sw) / 440);
  --secondary: rgba(60, 60, 67, 0.6);
  --tertiary: rgba(60, 60, 67, 0.3);
  --blue: #0062e6;
  --smooth: cubic-bezier(0.32, 0.72, 0, 1);
  position: absolute;
  top: calc(66 / 3000 * 100%);
  left: calc(75 / 1470 * 100%);
  overflow: hidden;
  width: calc(1320 / 1470 * 100%);
  height: calc(2868 / 3000 * 100%);
  border-radius: calc(var(--sw) * 0.13);
  background: #f2f2f7;
  color: #000;
  font-family: -apple-system, BlinkMacSystemFont, "SF Pro Text", system-ui, sans-serif;
  font-size: calc(17 * var(--pt));
  line-height: 1.3;
  letter-spacing: -0.01em;
  text-align: start;
  user-select: none;
}

/* Status bar and home indicator (the Dynamic Island is the bezel's). */
.ai-status-bar {
  position: absolute;
  inset: 0 0 auto;
  z-index: 3;
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: calc(54 * var(--pt));
  padding: calc(8 * var(--pt)) calc(42 * var(--pt)) 0 calc(64 * var(--pt));
  font-size: calc(17 * var(--pt));
}

.ai-status-bar b {
  font-weight: 600;
}

.ai-status-bar span {
  display: flex;
  gap: calc(6 * var(--pt));
  align-items: center;
}

.ai-status-bar svg {
  width: auto;
  height: calc(12 * var(--pt));
}

.ai-home {
  position: absolute;
  bottom: calc(8 * var(--pt));
  left: 50%;
  z-index: 3;
  width: calc(140 * var(--pt));
  height: calc(5 * var(--pt));
  border-radius: 999px;
  background: #000;
  translate: -50% 0;
}

.ai-screen p {
  margin: 0;
}

.ai-screen svg {
  display: block;
}

/* Navigation bar: the menu, the title over the car's name, and the glass
   capsule with "new conversation" (once there is one) and "close". */
.ai-nav {
  position: absolute;
  inset: 0 0 auto;
  z-index: 2;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: calc(60 * var(--pt)) calc(16 * var(--pt)) 0;
}

.ai-glass {
  display: flex;
  height: calc(44 * var(--pt));
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.74);
  box-shadow:
    inset 0 0 0 0.5px rgba(255, 255, 255, 0.8),
    0 calc(4 * var(--pt)) calc(16 * var(--pt)) rgba(0, 0, 0, 0.08);
  -webkit-backdrop-filter: blur(12px) saturate(1.6);
  backdrop-filter: blur(12px) saturate(1.6);
}

.ai-glass svg,
.ai-new {
  flex: none;
  width: calc(44 * var(--pt));
  padding: calc(12 * var(--pt));
}

.ai-new {
  display: block;
  overflow: hidden;
  width: 0;
  padding: 0;
  opacity: 0;
  transition:
    width 0.35s var(--smooth),
    opacity 0.35s var(--smooth);
}

.ai-new svg {
  width: calc(44 * var(--pt));
}

.is-clearing .ai-track {
  opacity: 0;
  transition: opacity 0.3s ease !important;
}

.has-chat .ai-new {
  width: calc(44 * var(--pt));
  opacity: 1;
}

.has-chat .ai-new.is-pressed {
  opacity: 0.4;
}

.ai-title {
  position: absolute;
  left: 50%;
  top: calc(62 * var(--pt));
  display: flex;
  flex-direction: column;
  align-items: center;
  translate: -50% 0;
  white-space: nowrap;
}

.ai-title b {
  font-weight: 600;
}

.ai-title span {
  color: var(--secondary);
  font-size: calc(13 * var(--pt));
}

/* The conversation scrolls under the bars, fading into them. */
.ai-viewport {
  position: absolute;
  inset: 0;
  -webkit-mask-image: linear-gradient(transparent calc(106 * var(--pt)), #000 calc(156 * var(--pt)), #000 calc(100% - 98 * var(--pt)), transparent calc(100% - 62 * var(--pt)));
  mask-image: linear-gradient(transparent calc(106 * var(--pt)), #000 calc(156 * var(--pt)), #000 calc(100% - 98 * var(--pt)), transparent calc(100% - 62 * var(--pt)));
}

.ai-empty {
  position: absolute;
  inset: calc(114 * var(--pt)) 0 calc(176 * var(--pt));
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 0 calc(32 * var(--pt));
  text-align: center;
  transition:
    opacity 0.3s var(--smooth),
    translate 0.3s var(--smooth);
}

.ai-empty-icon {
  color: var(--blue);
}

.ai-empty-icon svg {
  width: calc(46 * var(--pt));
  height: calc(46 * var(--pt));
}

.ai-empty-title {
  margin-top: calc(16 * var(--pt)) !important;
  font-size: calc(22 * var(--pt));
  font-weight: 700;
}

.ai-empty-text {
  max-width: calc(300 * var(--pt));
  margin-top: calc(6 * var(--pt)) !important;
  color: var(--secondary);
  font-size: calc(15 * var(--pt));
  line-height: 1.33;
}

.has-chat .ai-empty {
  opacity: 0;
  translate: 0 calc(-12 * var(--pt));
}

/* The turns. The track moves as the app's list scrolls: each new question
   is brought to the top, then the answer is read down to its end. */
.ai-track {
  position: absolute;
  inset: 0 calc(16 * var(--pt)) auto;
  translate: 0 var(--scroll, 0);
  transition: translate 0.6s var(--smooth);
}

.ai-turn {
  display: none;
  padding-bottom: calc(20 * var(--pt));
}

.ai-turn.is-asked {
  display: block;
}

.ai-question {
  width: fit-content;
  max-width: calc(100% - 56 * var(--pt));
  margin-left: auto !important;
  padding: calc(10 * var(--pt)) calc(14 * var(--pt));
  border-radius: calc(20 * var(--pt));
  background: #fff;
  line-height: calc(22 * var(--pt));
}

/* Entrances, only when a turn is played: shown at once, it just is. */
.enter-q .ai-question {
  --rise: 12;
  animation: ai-in 0.35s var(--smooth) both;
}

.enter-a .ai-response {
  animation: ai-in 0.45s var(--smooth) both;
}

.ai-action.enter .ai-status {
  --rise: 0;
  animation: ai-in 0.25s var(--smooth) both;
}

.ai-thinking {
  display: none !important;
  gap: calc(8 * var(--pt));
  align-items: center;
  margin-top: calc(24 * var(--pt)) !important;
  font-size: calc(15 * var(--pt));
  font-weight: 500;
}

.ai-turn.is-thinking .ai-thinking {
  display: flex !important;
}

.ai-sparkles {
  color: var(--blue);
}

.ai-sparkles svg {
  width: calc(17 * var(--pt));
  height: calc(17 * var(--pt));
}

/* The symbol's "breathe" effect, layer by layer. */
.ai-sparkles .ai-star,
.intel-sparkle .ai-star {
  transform-box: fill-box;
  transform-origin: center;
  animation: breathe 1.8s ease-in-out infinite;
}

.ai-star:nth-child(2) {
  animation-delay: 0.15s !important;
}

.ai-star:nth-child(3) {
  animation-delay: 0.3s !important;
}

@keyframes breathe {
  50% {
    opacity: 0.45;
    scale: 0.92;
  }
}

/* "Réflexion…": a band of ink runs over grey text every 1.8 s. */
.ai-shimmer {
  background: linear-gradient(90deg, var(--secondary) 40%, #000 50%, var(--secondary) 60%) 0 0 / 250% 100%;
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  animation: shimmer 1.8s linear infinite;
}

@keyframes shimmer {
  from {
    background-position: 100% 0;
  }
  to {
    background-position: -40% 0;
  }
}

.ai-response {
  display: none;
  flex-direction: column;
  gap: calc(12 * var(--pt));
  margin-top: calc(24 * var(--pt));
}

.is-answered .ai-response {
  display: flex;
}

@keyframes ai-in {
  from {
    opacity: 0;
    translate: 0 calc(var(--rise, 8) * var(--pt));
  }
}

.ai-text {
  line-height: calc(25 * var(--pt));
}

.ai-card {
  padding: calc(16 * var(--pt));
  border-radius: calc(16 * var(--pt));
  background: #fff;
}

.ai-chart-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.ai-chart-header p {
  display: flex;
  flex-direction: column;
  gap: calc(2 * var(--pt));
}

.ai-chart-header b {
  font-size: calc(15 * var(--pt));
  font-weight: 600;
}

.ai-chart-header span {
  color: var(--secondary);
  font-size: calc(13 * var(--pt));
}

.ai-chev {
  color: var(--tertiary);
}

.ai-chev svg {
  width: calc(13 * var(--pt));
  height: calc(13 * var(--pt));
}

.ai-figures {
  display: flex;
  gap: calc(24 * var(--pt));
  margin-top: calc(12 * var(--pt));
}

.ai-figures p {
  display: flex;
  flex-direction: column;
  gap: calc(2 * var(--pt));
}

.ai-figures span {
  color: var(--secondary);
  font-size: calc(13 * var(--pt));
  font-weight: 500;
}

.ai-figures b {
  font-size: calc(22 * var(--pt));
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  line-height: 1.25;
}

.ai-plot {
  width: 100%;
  height: auto;
  margin-top: calc(16 * var(--pt));
  overflow: visible;
}

.ai-ring {
  position: relative;
}

.ai-ring-centre {
  position: absolute;
  left: 50%;
  top: calc(16 * var(--pt) + 50% - 8 * var(--pt));
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: calc(1 * var(--pt));
  translate: -50% -50%;
}

.ai-ring-centre b {
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

.ai-ring-centre span {
  color: var(--secondary);
  font-size: calc(12 * var(--pt));
}

.ai-legend {
  display: flex;
  flex-direction: column;
  gap: calc(8 * var(--pt));
  margin-top: calc(12 * var(--pt));
  font-size: calc(15 * var(--pt));
}

.ai-legend p {
  display: grid;
  grid-template-columns: calc(8 * var(--pt)) 1fr auto calc(40 * var(--pt));
  gap: calc(8 * var(--pt));
  align-items: center;
}

.ai-legend i {
  width: calc(8 * var(--pt));
  height: calc(8 * var(--pt));
  border-radius: 50%;
}

.ai-legend span {
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

.ai-legend span:nth-of-type(2) {
  color: var(--secondary);
  font-variant-numeric: tabular-nums;
}

.ai-legend span:nth-of-type(3) {
  color: var(--tertiary);
  font-variant-numeric: tabular-nums;
  text-align: end;
}

/* Bars rise one after the other; the dashed average follows. */
.ai-bar {
  fill: var(--blue);
  transform-box: fill-box;
  transform-origin: bottom;
}

.ai-average {
  stroke: #d1d1d6;
  stroke-width: 1;
  stroke-dasharray: 4 3;
}

.js .ai-chart[data-ai-chart="bars"] .ai-bar {
  scale: 1 0;
  transition: scale 0.7s var(--smooth) calc(var(--i) * 70ms);
}

.js .ai-chart[data-ai-chart="bars"] .ai-average {
  opacity: 0;
  transition: opacity 0.4s ease 0.6s;
}

.js .is-drawn .ai-chart[data-ai-chart="bars"] .ai-bar {
  scale: 1;
}

.js .is-drawn .ai-chart[data-ai-chart="bars"] .ai-average {
  opacity: 1;
}

.ai-ref {
  display: block;
  width: 100%;
  height: auto;
}

/* Copy, and the two thumbs. */
.ai-footer {
  display: flex;
  align-items: center;
  height: calc(44 * var(--pt));
  margin-top: calc(-10 * var(--pt));
  color: var(--secondary);
}

.ai-footer svg {
  width: calc(36 * var(--pt));
  height: calc(17 * var(--pt));
  padding-right: calc(19 * var(--pt));
}

/* The commands the app proposes, each with its "Run" button. */
.ai-actions {
  padding: 0;
}

.ai-action {
  position: relative;
  display: flex;
  gap: calc(12 * var(--pt));
  align-items: center;
  min-height: calc(56 * var(--pt));
  padding: calc(10 * var(--pt)) calc(12 * var(--pt));
}

.ai-action + .ai-action::before {
  content: "";
  position: absolute;
  top: 0;
  right: 0;
  left: calc(60 * var(--pt));
  height: 1px;
  background: rgba(60, 60, 67, 0.18);
}

.ai-tile {
  display: grid;
  flex: none;
  place-items: center;
  width: calc(36 * var(--pt));
  height: calc(36 * var(--pt));
  border-radius: calc(10 * var(--pt));
  background: rgba(0, 98, 230, 0.16);
  color: var(--blue);
}

.ai-tile svg {
  width: calc(17 * var(--pt));
  height: calc(17 * var(--pt));
}

.ai-action p {
  display: flex;
  flex: 1;
  flex-direction: column;
  gap: calc(2 * var(--pt));
  font-size: calc(15 * var(--pt));
}

.ai-action b {
  font-weight: 600;
}

.ai-status {
  display: none;
  gap: calc(4 * var(--pt));
  align-items: center;
  color: var(--secondary);
  font-size: calc(13 * var(--pt));
}

.ai-status svg {
  width: calc(13 * var(--pt));
  height: calc(13 * var(--pt));
  color: #0fa968;
}

.ai-run {
  flex: none;
  padding: calc(4 * var(--pt)) calc(12 * var(--pt));
  border-radius: 999px;
  background: var(--blue);
  color: #fff;
  font-size: calc(15 * var(--pt));
  font-weight: 600;
  line-height: calc(20 * var(--pt));
  transition:
    scale 0.15s ease,
    opacity 0.15s ease;
}

.ai-spinner {
  display: none !important;
  flex: none;
  width: calc(20 * var(--pt));
  height: calc(20 * var(--pt));
  margin: 0 calc(12 * var(--pt));
  color: #8e8e93;
  animation: spin 0.8s steps(8) infinite;
}

@keyframes spin {
  to {
    rotate: 360deg;
  }
}

.ai-action.is-pressed .ai-run {
  opacity: 0.7;
  scale: 0.92;
}

.ai-action.is-sending .ai-run,
.ai-action.is-sent .ai-run {
  display: none;
}

.ai-action.is-sending .ai-spinner {
  display: block !important;
}

.ai-action.is-sent .ai-status {
  display: flex;
}

/* Suggestions under an empty conversation, then the text field. */
.ai-bottom {
  position: absolute;
  inset: auto 0 0;
  z-index: 2;
  display: flex;
  flex-direction: column;
  gap: calc(16 * var(--pt));
  padding-bottom: calc(34 * var(--pt));
}

.ai-suggestions {
  display: flex;
  gap: calc(10 * var(--pt));
  padding: 0 calc(16 * var(--pt));
  overflow: hidden;
  transition: opacity 0.25s var(--smooth);
}

.ai-suggestion {
  display: flex;
  flex: none;
  flex-direction: column;
  gap: calc(10 * var(--pt));
  width: calc(220 * var(--pt));
  padding: calc(14 * var(--pt));
  border-radius: calc(16 * var(--pt));
  background: #fff;
  font-size: calc(15 * var(--pt));
}

.ai-suggestion b {
  display: flex;
  gap: calc(6 * var(--pt));
  align-items: center;
  font-weight: 600;
}

.ai-suggestion b svg {
  width: calc(17 * var(--pt));
  height: calc(17 * var(--pt));
}

.ai-suggestion > span {
  display: -webkit-box;
  overflow: hidden;
  min-height: calc(40 * var(--pt));
  color: var(--secondary);
  line-height: calc(20 * var(--pt));
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
}

.is-typing .ai-suggestions,
.has-chat .ai-suggestions {
  opacity: 0;
  pointer-events: none;
}

.ai-composer {
  display: flex;
  gap: calc(6 * var(--pt));
  align-items: flex-end;
  margin: 0 calc(16 * var(--pt));
  border-radius: calc(22 * var(--pt));
  background: rgba(255, 255, 255, 0.78);
  box-shadow:
    inset 0 0 0 0.5px rgba(0, 0, 0, 0.06),
    0 calc(6 * var(--pt)) calc(20 * var(--pt)) rgba(0, 0, 0, 0.08);
  -webkit-backdrop-filter: blur(14px) saturate(1.6);
  backdrop-filter: blur(14px) saturate(1.6);
}

.ai-field {
  position: relative;
  flex: 1;
  min-width: 0;
  min-height: calc(44 * var(--pt));
  padding: calc(11 * var(--pt)) 0 calc(11 * var(--pt)) calc(16 * var(--pt));
  line-height: calc(22 * var(--pt));
}

.ai-placeholder {
  position: absolute;
  top: calc(11 * var(--pt));
  color: var(--tertiary);
}

.ai-draft:not(:empty) + .ai-placeholder,
.ai-field:has(.ai-draft:not(:empty)) .ai-placeholder {
  display: none;
}

/* The insertion point, while a question is typed. */
.is-typing .ai-draft::after {
  content: "";
  display: inline-block;
  width: calc(2 * var(--pt));
  height: calc(20 * var(--pt));
  margin-left: calc(1 * var(--pt));
  border-radius: 1px;
  background: var(--blue);
  vertical-align: calc(-4 * var(--pt));
}

.ai-send {
  display: grid;
  flex: none;
  place-items: center;
  width: calc(34 * var(--pt));
  height: calc(34 * var(--pt));
  margin: calc(5 * var(--pt));
  border-radius: 50%;
  background: rgba(120, 120, 128, 0.16);
  color: rgba(60, 60, 67, 0.3);
  transition:
    background-color 0.25s var(--smooth),
    color 0.25s var(--smooth),
    scale 0.15s ease;
}

.ai-send svg {
  width: calc(18 * var(--pt));
  height: calc(18 * var(--pt));
}

.is-ready .ai-send {
  background: var(--blue);
  color: #fff;
}

.is-sending-question .ai-send {
  scale: 0.86;
}

/* Privacy ----------------------------------------------------------------- */

.d-privacy {
  max-width: var(--container);
  margin: 0 auto;
  padding: clamp(96px, 14vw, 160px) 20px 0;
}

/* Three promises, side by side, separated by hairlines. */
.privacy-list {
  display: grid;
  margin: clamp(40px, 6vw, 64px) 0 0;
  padding: 0;
  list-style: none;
}

.privacy-list li {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 18px;
  padding: 32px 24px;
  font-family: var(--font-display);
  font-size: clamp(1.375rem, 1.1rem + 0.7vw, 1.75rem);
  font-weight: 700;
  letter-spacing: -0.022em;
  text-align: center;
}

.privacy-list li + li {
  border-top: 1px solid var(--line);
}

.privacy-icon {
  color: var(--brand);
}

.privacy-icon svg {
  display: block;
  width: 44px;
  height: 44px;
  stroke-width: 1.3;
}

@media (min-width: 760px) {
  .privacy-list {
    grid-template-columns: repeat(3, 1fr);
  }

  .privacy-list li + li {
    border-top: 0;
    border-left: 1px solid var(--line);
  }
}

/* Each line icon traces itself once, when it comes into view. The shapes
   carry a class: a class change on an ancestor does not reliably restyle SVG
   shapes matched by their pathLength attribute alone. */
.js .privacy-icon svg .trace,
.js .security-icon svg .trace {
  stroke-dasharray: 1;
  stroke-dashoffset: 1;
}

.js .is-visible .privacy-icon svg .trace,
.js .is-visible .security-icon svg .trace {
  animation: trace 1.4s var(--ease-apple) forwards;
  animation-delay: calc(var(--i, 0) * 0.12s + 0.2s);
}

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

/* Security: six facts, each one checked in the code. */
.security-title {
  max-width: 24ch;
  margin: clamp(72px, 10vw, 112px) auto 0;
  font-family: var(--font-display);
  font-size: var(--text-title);
  font-weight: 700;
  line-height: 1.12;
  letter-spacing: -0.025em;
  text-align: center;
  text-wrap: balance;
}

.security-grid {
  display: grid;
  gap: 0 40px;
  margin: clamp(32px, 5vw, 48px) 0 0;
  padding: 0;
  list-style: none;
}

.security-grid li {
  padding: 28px 0;
  border-top: 1px solid var(--line);
}

.security-grid h4 {
  margin: 16px 0 6px;
  font-size: 19px;
  font-weight: 600;
  letter-spacing: -0.015em;
}

.security-grid p {
  margin: 0;
  color: var(--ink-secondary);
  font-size: 16px;
  line-height: 1.45;
  text-wrap: pretty;
}

.security-icon {
  display: block;
  color: var(--brand);
}

.security-icon svg {
  display: block;
  width: 30px;
  height: 30px;
  stroke-width: 1.4;
}

/* On phones the icon sits beside the text, so six facts stay short. */
@media (max-width: 639px) {
  .security-grid li {
    display: grid;
    grid-template-columns: 30px 1fr;
    column-gap: 16px;
    padding: 22px 0;
  }

  .security-icon {
    grid-row: span 2;
  }

  .security-grid h4 {
    margin-top: 2px;
  }
}

@media (min-width: 640px) {
  .security-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (min-width: 960px) {
  .security-grid {
    grid-template-columns: repeat(3, 1fr);
  }
}

/* Integrations ------------------------------------------------------------ */

.d-integrations {
  max-width: var(--container);
  margin: 0 auto;
  padding: clamp(96px, 14vw, 160px) 20px 0;
}

.d-heading {
  text-align: center;
}

.integrations {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 40px 24px;
  margin: clamp(40px, 6vw, 64px) 0 0;
  padding: 0;
  list-style: none;
}

.integration-icon {
  display: grid;
  place-items: center;
  width: 54px;
  height: 54px;
  border-radius: 14px;
}

/* The drawn ones: the app's tinted square and coloured glyph. */
span.integration-icon {
  background: color-mix(in srgb, var(--c) 14%, #fff);
  color: var(--c);
}

span.integration-icon svg {
  width: 30px;
  height: 30px;
}

.integrations h3 {
  margin: 16px 0 4px;
  font-size: 17px;
  font-weight: 600;
  letter-spacing: -0.012em;
}

.integrations p {
  margin: 0;
  color: var(--ink-secondary);
  font-size: 15px;
  line-height: 1.45;
  text-wrap: pretty;
}

@media (min-width: 900px) {
  .integrations {
    grid-template-columns: repeat(4, 1fr);
    gap: 56px 40px;
  }
}

/* Closing ----------------------------------------------------------------- */

.d-closing {
  position: relative;
  isolation: isolate;
  margin-top: clamp(96px, 14vw, 160px);
  padding: clamp(96px, 12vw, 144px) 20px;
  text-align: center;
}

.d-closing::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: var(--wash);
  mask-image: linear-gradient(180deg, transparent, #000 40%);
}

.closing-mark {
  display: block;
  width: 72px;
  height: auto;
  margin: 0 auto 28px;
}

.d-closing h2 {
  max-width: 18ch;
  margin-inline: auto;
}

.d-closing p {
  max-width: 40ch;
  margin: 16px auto 0;
  color: var(--ink-secondary);
  font-size: var(--text-lead);
  line-height: 1.4;
  text-wrap: pretty;
}

.d-closing p:last-child {
  margin-top: 32px;
}

/* Motion ------------------------------------------------------------------ */

@media (prefers-reduced-motion: reduce) {
  .js [data-reveal] {
    opacity: 1;
    translate: none;
    transition: none;
  }

  .d-hero-phones .phone,
  .w-flow i,
  .is-rolling,
  .range-ring,
  .ai-star,
  .ai-shimmer,
  .intel-eyebrow {
    animation: none;
  }

  .dial-centre.is-changing {
    animation: none;
  }

  .js .privacy-icon svg .trace,
  .js .security-icon svg .trace {
    stroke-dashoffset: 0;
    animation: none !important;
  }

  .js .story-stage .scene {
    transition: none;
  }

  .js [data-reveal] :is(.bt-dots circle, .s-notif, .s-card, .s-pin, .pp-red circle, .pp-stamp, .pp-bar i) {
    opacity: 1;
    translate: none;
    scale: 1;
    animation: none !important;
  }

  .js [data-reveal] .bt-reveal {
    transform: none;
    animation: none !important;
  }

  .js [data-reveal] .rt-leg {
    stroke-dashoffset: 0;
  }

  .js [data-reveal] .rt-marker,
  .js [data-reveal] .rt-casing {
    opacity: 1;
    scale: 1;
  }

  .js .is-visible .rt-leg,
  .js .is-visible .rt-marker {
    animation: none;
  }

  .range-ring {
    opacity: 0.6;
    scale: 0.35;
  }

  .range-ring:nth-child(2) {
    scale: 0.65;
  }

  .range-ring:nth-child(3) {
    scale: 1;
  }

  .d-statement .word {
    --w: 1 !important;
  }

  .js .notif {
    opacity: 1;
    translate: none;
    scale: 1;
  }
}
